int MAIN (int argc, char **argv) { ENGINE *e = NULL; int i, ret = 1, badarg = 0; char *CApath = NULL, *CAfile = NULL; char *untfile = NULL, *trustfile = NULL, *crlfile = NULL; STACK_OF (X509) * untrusted = NULL, *trusted = NULL; STACK_OF (X509_CRL) * crls = NULL; X509_STORE *cert_ctx = NULL; X509_LOOKUP *lookup = NULL; X509_VERIFY_PARAM *vpm = NULL; #ifndef OPENSSL_NO_ENGINE char *engine = NULL; #endif cert_ctx = X509_STORE_new (); if (cert_ctx == NULL) goto end; X509_STORE_set_verify_cb (cert_ctx, cb); ERR_load_crypto_strings (); apps_startup (); if (bio_err == NULL) if ((bio_err = BIO_new (BIO_s_file ())) != NULL) BIO_set_fp (bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); if (!load_config (bio_err, NULL)) goto end; argc--; argv++; for (;;) { if (argc >= 1) { if (strcmp (*argv, "-CApath") == 0) { if (argc-- < 1) goto end; CApath = *(++argv); } else if (strcmp (*argv, "-CAfile") == 0) { if (argc-- < 1) goto end; CAfile = *(++argv); } else if (args_verify (&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto end; continue; } else if (strcmp (*argv, "-untrusted") == 0) { if (argc-- < 1) goto end; untfile = *(++argv); } else if (strcmp (*argv, "-trusted") == 0) { if (argc-- < 1) goto end; trustfile = *(++argv); } else if (strcmp (*argv, "-CRLfile") == 0) { if (argc-- < 1) goto end; crlfile = *(++argv); } #ifndef OPENSSL_NO_ENGINE else if (strcmp (*argv, "-engine") == 0) { if (--argc < 1) goto end; engine = *(++argv); } #endif else if (strcmp (*argv, "-help") == 0) goto end; else if (strcmp (*argv, "-verbose") == 0) v_verbose = 1; else if (argv[0][0] == '-') goto end; else break; argc--; argv++; } else break; } #ifndef OPENSSL_NO_ENGINE e = setup_engine (bio_err, engine, 0); #endif if (vpm) X509_STORE_set1_param (cert_ctx, vpm); lookup = X509_STORE_add_lookup (cert_ctx, X509_LOOKUP_file ()); if (lookup == NULL) abort (); if (CAfile) { i = X509_LOOKUP_load_file (lookup, CAfile, X509_FILETYPE_PEM); if (!i) { BIO_printf (bio_err, "Error loading file %s\n", CAfile); ERR_print_errors (bio_err); goto end; } } else X509_LOOKUP_load_file (lookup, NULL, X509_FILETYPE_DEFAULT); lookup = X509_STORE_add_lookup (cert_ctx, X509_LOOKUP_hash_dir ()); if (lookup == NULL) abort (); if (CApath) { i = X509_LOOKUP_add_dir (lookup, CApath, X509_FILETYPE_PEM); if (!i) { BIO_printf (bio_err, "Error loading directory %s\n", CApath); ERR_print_errors (bio_err); goto end; } } else X509_LOOKUP_add_dir (lookup, NULL, X509_FILETYPE_DEFAULT); ERR_clear_error (); if (untfile) { untrusted = load_certs (bio_err, untfile, FORMAT_PEM, NULL, e, "untrusted certificates"); if (!untrusted) goto end; } if (trustfile) { trusted = load_certs (bio_err, trustfile, FORMAT_PEM, NULL, e, "trusted certificates"); if (!trusted) goto end; } if (crlfile) { crls = load_crls (bio_err, crlfile, FORMAT_PEM, NULL, e, "other CRLs"); if (!crls) goto end; } ret = 0; if (argc < 1) { if (1 != check (cert_ctx, NULL, untrusted, trusted, crls, e)) ret = -1; } else { for (i = 0; i < argc; i++) if (1 != check (cert_ctx, argv[i], untrusted, trusted, crls, e)) ret = -1; } end: if (ret == 1) { BIO_printf (bio_err, "usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]"); BIO_printf (bio_err, " [-attime timestamp]"); #ifndef OPENSSL_NO_ENGINE BIO_printf (bio_err, " [-engine e]"); #endif BIO_printf (bio_err, " cert1 cert2 ...\n"); BIO_printf (bio_err, "recognized usages:\n"); for (i = 0; i < X509_PURPOSE_get_count (); i++) { X509_PURPOSE *ptmp; ptmp = X509_PURPOSE_get0 (i); BIO_printf (bio_err, "\t%-10s\t%s\n", X509_PURPOSE_get0_sname (ptmp), X509_PURPOSE_get0_name (ptmp)); } } if (vpm) X509_VERIFY_PARAM_free (vpm); if (cert_ctx != NULL) X509_STORE_free (cert_ctx); sk_X509_pop_free (untrusted, X509_free); sk_X509_pop_free (trusted, X509_free); sk_X509_CRL_pop_free (crls, X509_CRL_free); apps_shutdown (); OPENSSL_EXIT (ret < 0 ? 2 : ret); }
int MAIN(int argc, char **argv) { ENGINE *e = NULL; int operation = 0; int ret = 0; char **args; const char *inmode = "r", *outmode = "w"; char *infile = NULL, *outfile = NULL, *rctfile = NULL; char *signerfile = NULL, *recipfile = NULL; STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL; char *certfile = NULL, *keyfile = NULL, *contfile = NULL; char *certsoutfile = NULL; const EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL; CMS_ContentInfo *cms = NULL, *rcms = NULL; X509_STORE *store = NULL; X509 *cert = NULL, *recip = NULL, *signer = NULL; EVP_PKEY *key = NULL; STACK_OF(X509) *encerts = NULL, *other = NULL; BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL; int badarg = 0; int flags = CMS_DETACHED, noout = 0, print = 0; int verify_retcode = 0; int rr_print = 0, rr_allorfirst = -1; STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL; CMS_ReceiptRequest *rr = NULL; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; char *inrand = NULL; int need_rand = 0; const EVP_MD *sign_md = NULL; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; # ifndef OPENSSL_NO_ENGINE char *engine = NULL; # endif unsigned char *secret_key = NULL, *secret_keyid = NULL; unsigned char *pwri_pass = NULL, *pwri_tmp = NULL; size_t secret_keylen = 0, secret_keyidlen = 0; cms_key_param *key_first = NULL, *key_param = NULL; ASN1_OBJECT *econtent_type = NULL; X509_VERIFY_PARAM *vpm = NULL; args = argv + 1; ret = 1; apps_startup(); if (bio_err == NULL) { if ((bio_err = BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); } if (!load_config(bio_err, NULL)) goto end; while (!badarg && *args && *args[0] == '-') { if (!strcmp(*args, "-encrypt")) operation = SMIME_ENCRYPT; else if (!strcmp(*args, "-decrypt")) operation = SMIME_DECRYPT; else if (!strcmp(*args, "-sign")) operation = SMIME_SIGN; else if (!strcmp(*args, "-sign_receipt")) operation = SMIME_SIGN_RECEIPT; else if (!strcmp(*args, "-resign")) operation = SMIME_RESIGN; else if (!strcmp(*args, "-verify")) operation = SMIME_VERIFY; else if (!strcmp(*args, "-verify_retcode")) verify_retcode = 1; else if (!strcmp(*args, "-verify_receipt")) { operation = SMIME_VERIFY_RECEIPT; if (!args[1]) goto argerr; args++; rctfile = *args; } else if (!strcmp(*args, "-cmsout")) operation = SMIME_CMSOUT; else if (!strcmp(*args, "-data_out")) operation = SMIME_DATAOUT; else if (!strcmp(*args, "-data_create")) operation = SMIME_DATA_CREATE; else if (!strcmp(*args, "-digest_verify")) operation = SMIME_DIGEST_VERIFY; else if (!strcmp(*args, "-digest_create")) operation = SMIME_DIGEST_CREATE; else if (!strcmp(*args, "-compress")) operation = SMIME_COMPRESS; else if (!strcmp(*args, "-uncompress")) operation = SMIME_UNCOMPRESS; else if (!strcmp(*args, "-EncryptedData_decrypt")) operation = SMIME_ENCRYPTED_DECRYPT; else if (!strcmp(*args, "-EncryptedData_encrypt")) operation = SMIME_ENCRYPTED_ENCRYPT; # ifndef OPENSSL_NO_DES else if (!strcmp(*args, "-des3")) cipher = EVP_des_ede3_cbc(); else if (!strcmp(*args, "-des")) cipher = EVP_des_cbc(); else if (!strcmp(*args, "-des3-wrap")) wrap_cipher = EVP_des_ede3_wrap(); # endif # ifndef OPENSSL_NO_SEED else if (!strcmp(*args, "-seed")) cipher = EVP_seed_cbc(); # endif # ifndef OPENSSL_NO_RC2 else if (!strcmp(*args, "-rc2-40")) cipher = EVP_rc2_40_cbc(); else if (!strcmp(*args, "-rc2-128")) cipher = EVP_rc2_cbc(); else if (!strcmp(*args, "-rc2-64")) cipher = EVP_rc2_64_cbc(); # endif # ifndef OPENSSL_NO_AES else if (!strcmp(*args, "-aes128")) cipher = EVP_aes_128_cbc(); else if (!strcmp(*args, "-aes192")) cipher = EVP_aes_192_cbc(); else if (!strcmp(*args, "-aes256")) cipher = EVP_aes_256_cbc(); else if (!strcmp(*args, "-aes128-wrap")) wrap_cipher = EVP_aes_128_wrap(); else if (!strcmp(*args, "-aes192-wrap")) wrap_cipher = EVP_aes_192_wrap(); else if (!strcmp(*args, "-aes256-wrap")) wrap_cipher = EVP_aes_256_wrap(); # endif # ifndef OPENSSL_NO_CAMELLIA else if (!strcmp(*args, "-camellia128")) cipher = EVP_camellia_128_cbc(); else if (!strcmp(*args, "-camellia192")) cipher = EVP_camellia_192_cbc(); else if (!strcmp(*args, "-camellia256")) cipher = EVP_camellia_256_cbc(); # endif else if (!strcmp(*args, "-debug_decrypt")) flags |= CMS_DEBUG_DECRYPT; else if (!strcmp(*args, "-text")) flags |= CMS_TEXT; else if (!strcmp(*args, "-nointern")) flags |= CMS_NOINTERN; else if (!strcmp(*args, "-noverify") || !strcmp(*args, "-no_signer_cert_verify")) flags |= CMS_NO_SIGNER_CERT_VERIFY; else if (!strcmp(*args, "-nocerts")) flags |= CMS_NOCERTS; else if (!strcmp(*args, "-noattr")) flags |= CMS_NOATTR; else if (!strcmp(*args, "-nodetach")) flags &= ~CMS_DETACHED; else if (!strcmp(*args, "-nosmimecap")) flags |= CMS_NOSMIMECAP; else if (!strcmp(*args, "-binary")) flags |= CMS_BINARY; else if (!strcmp(*args, "-keyid")) flags |= CMS_USE_KEYID; else if (!strcmp(*args, "-nosigs")) flags |= CMS_NOSIGS; else if (!strcmp(*args, "-no_content_verify")) flags |= CMS_NO_CONTENT_VERIFY; else if (!strcmp(*args, "-no_attr_verify")) flags |= CMS_NO_ATTR_VERIFY; else if (!strcmp(*args, "-stream")) flags |= CMS_STREAM; else if (!strcmp(*args, "-indef")) flags |= CMS_STREAM; else if (!strcmp(*args, "-noindef")) flags &= ~CMS_STREAM; else if (!strcmp(*args, "-nooldmime")) flags |= CMS_NOOLDMIMETYPE; else if (!strcmp(*args, "-crlfeol")) flags |= CMS_CRLFEOL; else if (!strcmp(*args, "-noout")) noout = 1; else if (!strcmp(*args, "-receipt_request_print")) rr_print = 1; else if (!strcmp(*args, "-receipt_request_all")) rr_allorfirst = 0; else if (!strcmp(*args, "-receipt_request_first")) rr_allorfirst = 1; else if (!strcmp(*args, "-receipt_request_from")) { if (!args[1]) goto argerr; args++; if (!rr_from) rr_from = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(rr_from, *args); } else if (!strcmp(*args, "-receipt_request_to")) { if (!args[1]) goto argerr; args++; if (!rr_to) rr_to = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(rr_to, *args); } else if (!strcmp(*args, "-print")) { noout = 1; print = 1; } else if (!strcmp(*args, "-secretkey")) { long ltmp; if (!args[1]) goto argerr; args++; secret_key = string_to_hex(*args, <mp); if (!secret_key) { BIO_printf(bio_err, "Invalid key %s\n", *args); goto argerr; } secret_keylen = (size_t)ltmp; } else if (!strcmp(*args, "-secretkeyid")) { long ltmp; if (!args[1]) goto argerr; args++; secret_keyid = string_to_hex(*args, <mp); if (!secret_keyid) { BIO_printf(bio_err, "Invalid id %s\n", *args); goto argerr; } secret_keyidlen = (size_t)ltmp; } else if (!strcmp(*args, "-pwri_password")) { if (!args[1]) goto argerr; args++; pwri_pass = (unsigned char *)*args; } else if (!strcmp(*args, "-econtent_type")) { if (!args[1]) goto argerr; args++; econtent_type = OBJ_txt2obj(*args, 0); if (!econtent_type) { BIO_printf(bio_err, "Invalid OID %s\n", *args); goto argerr; } } else if (!strcmp(*args, "-rand")) { if (!args[1]) goto argerr; args++; inrand = *args; need_rand = 1; } # ifndef OPENSSL_NO_ENGINE else if (!strcmp(*args, "-engine")) { if (!args[1]) goto argerr; engine = *++args; } # endif else if (!strcmp(*args, "-passin")) { if (!args[1]) goto argerr; passargin = *++args; } else if (!strcmp(*args, "-to")) { if (!args[1]) goto argerr; to = *++args; } else if (!strcmp(*args, "-from")) { if (!args[1]) goto argerr; from = *++args; } else if (!strcmp(*args, "-subject")) { if (!args[1]) goto argerr; subject = *++args; } else if (!strcmp(*args, "-signer")) { if (!args[1]) goto argerr; /* If previous -signer argument add signer to list */ if (signerfile) { if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); if (!keyfile) keyfile = signerfile; if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(skkeys, keyfile); keyfile = NULL; } signerfile = *++args; } else if (!strcmp(*args, "-recip")) { if (!args[1]) goto argerr; if (operation == SMIME_ENCRYPT) { if (!encerts) encerts = sk_X509_new_null(); cert = load_cert(bio_err, *++args, FORMAT_PEM, NULL, e, "recipient certificate file"); if (!cert) goto end; sk_X509_push(encerts, cert); cert = NULL; } else recipfile = *++args; } else if (!strcmp(*args, "-certsout")) { if (!args[1]) goto argerr; certsoutfile = *++args; } else if (!strcmp(*args, "-md")) { if (!args[1]) goto argerr; sign_md = EVP_get_digestbyname(*++args); if (sign_md == NULL) { BIO_printf(bio_err, "Unknown digest %s\n", *args); goto argerr; } } else if (!strcmp(*args, "-inkey")) { if (!args[1]) goto argerr; /* If previous -inkey arument add signer to list */ if (keyfile) { if (!signerfile) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); goto argerr; } if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); signerfile = NULL; if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(skkeys, keyfile); } keyfile = *++args; } else if (!strcmp(*args, "-keyform")) { if (!args[1]) goto argerr; keyform = str2fmt(*++args); } else if (!strcmp(*args, "-keyopt")) { int keyidx = -1; if (!args[1]) goto argerr; if (operation == SMIME_ENCRYPT) { if (encerts) keyidx += sk_X509_num(encerts); } else { if (keyfile || signerfile) keyidx++; if (skkeys) keyidx += sk_OPENSSL_STRING_num(skkeys); } if (keyidx < 0) { BIO_printf(bio_err, "No key specified\n"); goto argerr; } if (key_param == NULL || key_param->idx != keyidx) { cms_key_param *nparam; nparam = OPENSSL_malloc(sizeof(cms_key_param)); if (!nparam) { BIO_printf(bio_err, "Out of memory\n"); goto argerr; } nparam->idx = keyidx; nparam->param = sk_OPENSSL_STRING_new_null(); nparam->next = NULL; if (key_first == NULL) key_first = nparam; else key_param->next = nparam; key_param = nparam; } sk_OPENSSL_STRING_push(key_param->param, *++args); } else if (!strcmp(*args, "-rctform")) { if (!args[1]) goto argerr; rctformat = str2fmt(*++args); } else if (!strcmp(*args, "-certfile")) { if (!args[1]) goto argerr; certfile = *++args; } else if (!strcmp(*args, "-CAfile")) { if (!args[1]) goto argerr; CAfile = *++args; } else if (!strcmp(*args, "-CApath")) { if (!args[1]) goto argerr; CApath = *++args; } else if (!strcmp(*args, "-in")) { if (!args[1]) goto argerr; infile = *++args; } else if (!strcmp(*args, "-inform")) { if (!args[1]) goto argerr; informat = str2fmt(*++args); } else if (!strcmp(*args, "-outform")) { if (!args[1]) goto argerr; outformat = str2fmt(*++args); } else if (!strcmp(*args, "-out")) { if (!args[1]) goto argerr; outfile = *++args; } else if (!strcmp(*args, "-content")) { if (!args[1]) goto argerr; contfile = *++args; } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) continue; else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL) badarg = 1; args++; } if (((rr_allorfirst != -1) || rr_from) && !rr_to) { BIO_puts(bio_err, "No Signed Receipts Recipients\n"); goto argerr; } if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) { BIO_puts(bio_err, "Signed receipts only allowed with -sign\n"); goto argerr; } if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) { BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); goto argerr; } if (operation & SMIME_SIGNERS) { if (keyfile && !signerfile) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); goto argerr; } /* Check to see if any final signer needs to be appended */ if (signerfile) { if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); if (!keyfile) keyfile = signerfile; sk_OPENSSL_STRING_push(skkeys, keyfile); } if (!sksigners) { BIO_printf(bio_err, "No signer certificate specified\n"); badarg = 1; } signerfile = NULL; keyfile = NULL; need_rand = 1; } else if (operation == SMIME_DECRYPT) { if (!recipfile && !keyfile && !secret_key && !pwri_pass) { BIO_printf(bio_err, "No recipient certificate or key specified\n"); badarg = 1; } } else if (operation == SMIME_ENCRYPT) { if (!*args && !secret_key && !pwri_pass && !encerts) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); badarg = 1; } need_rand = 1; } else if (!operation) badarg = 1; if (badarg) { argerr: BIO_printf(bio_err, "Usage cms [options] cert.pem ...\n"); BIO_printf(bio_err, "where options are\n"); BIO_printf(bio_err, "-encrypt encrypt message\n"); BIO_printf(bio_err, "-decrypt decrypt encrypted message\n"); BIO_printf(bio_err, "-sign sign message\n"); BIO_printf(bio_err, "-verify verify signed message\n"); BIO_printf(bio_err, "-cmsout output CMS structure\n"); # ifndef OPENSSL_NO_DES BIO_printf(bio_err, "-des3 encrypt with triple DES\n"); BIO_printf(bio_err, "-des encrypt with DES\n"); # endif # ifndef OPENSSL_NO_SEED BIO_printf(bio_err, "-seed encrypt with SEED\n"); # endif # ifndef OPENSSL_NO_RC2 BIO_printf(bio_err, "-rc2-40 encrypt with RC2-40 (default)\n"); BIO_printf(bio_err, "-rc2-64 encrypt with RC2-64\n"); BIO_printf(bio_err, "-rc2-128 encrypt with RC2-128\n"); # endif # ifndef OPENSSL_NO_AES BIO_printf(bio_err, "-aes128, -aes192, -aes256\n"); BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); # endif # ifndef OPENSSL_NO_CAMELLIA BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n"); BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); # endif BIO_printf(bio_err, "-nointern don't search certificates in message for signer\n"); BIO_printf(bio_err, "-nosigs don't verify message signature\n"); BIO_printf(bio_err, "-noverify don't verify signers certificate\n"); BIO_printf(bio_err, "-nocerts don't include signers certificate when signing\n"); BIO_printf(bio_err, "-nodetach use opaque signing\n"); BIO_printf(bio_err, "-noattr don't include any signed attributes\n"); BIO_printf(bio_err, "-binary don't translate message to text\n"); BIO_printf(bio_err, "-certfile file other certificates file\n"); BIO_printf(bio_err, "-certsout file certificate output file\n"); BIO_printf(bio_err, "-signer file signer certificate file\n"); BIO_printf(bio_err, "-recip file recipient certificate file for decryption\n"); BIO_printf(bio_err, "-keyid use subject key identifier\n"); BIO_printf(bio_err, "-in file input file\n"); BIO_printf(bio_err, "-inform arg input format SMIME (default), PEM or DER\n"); BIO_printf(bio_err, "-inkey file input private key (if not signer or recipient)\n"); BIO_printf(bio_err, "-keyform arg input private key format (PEM or ENGINE)\n"); BIO_printf(bio_err, "-keyopt nm:v set public key parameters\n"); BIO_printf(bio_err, "-out file output file\n"); BIO_printf(bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); BIO_printf(bio_err, "-content file supply or override content for detached signature\n"); BIO_printf(bio_err, "-to addr to address\n"); BIO_printf(bio_err, "-from ad from address\n"); BIO_printf(bio_err, "-subject s subject\n"); BIO_printf(bio_err, "-text include or delete text MIME headers\n"); BIO_printf(bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf(bio_err, "-CAfile file trusted certificates file\n"); BIO_printf(bio_err, "-trusted_first use trusted certificates first when building the trust chain\n"); BIO_printf(bio_err, "-no_alt_chains only ever use the first certificate chain found\n"); BIO_printf(bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); # ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); # endif BIO_printf(bio_err, "-passin arg input file pass phrase source\n"); BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); BIO_printf(bio_err, " load the file (or the files in the directory) into\n"); BIO_printf(bio_err, " the random number generator\n"); BIO_printf(bio_err, "cert.pem recipient certificate(s) for encryption\n"); goto end; } # ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine, 0); # endif if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (need_rand) { app_RAND_load_file(NULL, bio_err, (inrand != NULL)); if (inrand != NULL) BIO_printf(bio_err, "%ld semi-random bytes loaded\n", app_RAND_load_files(inrand)); } ret = 2; if (!(operation & SMIME_SIGNERS)) flags &= ~CMS_DETACHED; if (operation & SMIME_OP) { if (outformat == FORMAT_ASN1) outmode = "wb"; } else { if (flags & CMS_BINARY) outmode = "wb"; } if (operation & SMIME_IP) { if (informat == FORMAT_ASN1) inmode = "rb"; } else { if (flags & CMS_BINARY) inmode = "rb"; } if (operation == SMIME_ENCRYPT) { if (!cipher) { # ifndef OPENSSL_NO_DES cipher = EVP_des_ede3_cbc(); # else BIO_printf(bio_err, "No cipher selected\n"); goto end; # endif } if (secret_key && !secret_keyid) { BIO_printf(bio_err, "No secret key id\n"); goto end; } if (*args && !encerts) encerts = sk_X509_new_null(); while (*args) { if (!(cert = load_cert(bio_err, *args, FORMAT_PEM, NULL, e, "recipient certificate file"))) goto end; sk_X509_push(encerts, cert); cert = NULL; args++; } } if (certfile) { if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL, e, "certificate file"))) { ERR_print_errors(bio_err); goto end; } } if (recipfile && (operation == SMIME_DECRYPT)) { if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL, e, "recipient certificate file"))) { ERR_print_errors(bio_err); goto end; } } if (operation == SMIME_SIGN_RECEIPT) { if (!(signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL, e, "receipt signer certificate file"))) { ERR_print_errors(bio_err); goto end; } } if (operation == SMIME_DECRYPT) { if (!keyfile) keyfile = recipfile; } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) { if (!keyfile) keyfile = signerfile; } else keyfile = NULL; if (keyfile) { key = load_key(bio_err, keyfile, keyform, 0, passin, e, "signing key file"); if (!key) goto end; } if (infile) { if (!(in = BIO_new_file(infile, inmode))) { BIO_printf(bio_err, "Can't open input file %s\n", infile); goto end; } } else in = BIO_new_fp(stdin, BIO_NOCLOSE); if (operation & SMIME_IP) { if (informat == FORMAT_SMIME) cms = SMIME_read_CMS(in, &indata); else if (informat == FORMAT_PEM) cms = PEM_read_bio_CMS(in, NULL, NULL, NULL); else if (informat == FORMAT_ASN1) cms = d2i_CMS_bio(in, NULL); else { BIO_printf(bio_err, "Bad input format for CMS file\n"); goto end; } if (!cms) { BIO_printf(bio_err, "Error reading S/MIME message\n"); goto end; } if (contfile) { BIO_free(indata); if (!(indata = BIO_new_file(contfile, "rb"))) { BIO_printf(bio_err, "Can't read content file %s\n", contfile); goto end; } } if (certsoutfile) { STACK_OF(X509) *allcerts; allcerts = CMS_get1_certs(cms); if (!save_certs(certsoutfile, allcerts)) { BIO_printf(bio_err, "Error writing certs to %s\n", certsoutfile); ret = 5; goto end; } sk_X509_pop_free(allcerts, X509_free); } } if (rctfile) { char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; if (!(rctin = BIO_new_file(rctfile, rctmode))) { BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile); goto end; } if (rctformat == FORMAT_SMIME) rcms = SMIME_read_CMS(rctin, NULL); else if (rctformat == FORMAT_PEM) rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); else if (rctformat == FORMAT_ASN1) rcms = d2i_CMS_bio(rctin, NULL); else { BIO_printf(bio_err, "Bad input format for receipt\n"); goto end; } if (!rcms) { BIO_printf(bio_err, "Error reading receipt\n"); goto end; } } if (outfile) { if (!(out = BIO_new_file(outfile, outmode))) { BIO_printf(bio_err, "Can't open output file %s\n", outfile); goto end; } } else { out = BIO_new_fp(stdout, BIO_NOCLOSE); # ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); out = BIO_push(tmpbio, out); } # endif } if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) { if (!(store = setup_verify(bio_err, CAfile, CApath))) goto end; X509_STORE_set_verify_cb(store, cms_cb); if (vpm) X509_STORE_set1_param(store, vpm); } ret = 3; if (operation == SMIME_DATA_CREATE) { cms = CMS_data_create(in, flags); } else if (operation == SMIME_DIGEST_CREATE) { cms = CMS_digest_create(in, sign_md, flags); } else if (operation == SMIME_COMPRESS) { cms = CMS_compress(in, -1, flags); } else if (operation == SMIME_ENCRYPT) { int i; flags |= CMS_PARTIAL; cms = CMS_encrypt(NULL, in, cipher, flags); if (!cms) goto end; for (i = 0; i < sk_X509_num(encerts); i++) { CMS_RecipientInfo *ri; cms_key_param *kparam; int tflags = flags; X509 *x = sk_X509_value(encerts, i); for (kparam = key_first; kparam; kparam = kparam->next) { if (kparam->idx == i) { tflags |= CMS_KEY_PARAM; break; } } ri = CMS_add1_recipient_cert(cms, x, tflags); if (!ri) goto end; if (kparam) { EVP_PKEY_CTX *pctx; pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!cms_set_pkey_param(pctx, kparam->param)) goto end; } if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE && wrap_cipher) { EVP_CIPHER_CTX *wctx; wctx = CMS_RecipientInfo_kari_get0_ctx(ri); EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL); } } if (secret_key) { if (!CMS_add0_recipient_key(cms, NID_undef, secret_key, secret_keylen, secret_keyid, secret_keyidlen, NULL, NULL, NULL)) goto end; /* NULL these because call absorbs them */ secret_key = NULL; secret_keyid = NULL; } if (pwri_pass) { pwri_tmp = (unsigned char *)BUF_strdup((char *)pwri_pass); if (!pwri_tmp) goto end; if (!CMS_add0_recipient_password(cms, -1, NID_undef, NID_undef, pwri_tmp, -1, NULL)) goto end; pwri_tmp = NULL; } if (!(flags & CMS_STREAM)) { if (!CMS_final(cms, in, NULL, flags)) goto end; } } else if (operation == SMIME_ENCRYPTED_ENCRYPT) { cms = CMS_EncryptedData_encrypt(in, cipher, secret_key, secret_keylen, flags); } else if (operation == SMIME_SIGN_RECEIPT) { CMS_ContentInfo *srcms = NULL; STACK_OF(CMS_SignerInfo) *sis; CMS_SignerInfo *si; sis = CMS_get0_SignerInfos(cms); if (!sis) goto end; si = sk_CMS_SignerInfo_value(sis, 0); srcms = CMS_sign_receipt(si, signer, key, other, flags); if (!srcms) goto end; CMS_ContentInfo_free(cms); cms = srcms; } else if (operation & SMIME_SIGNERS) { int i; /* * If detached data content we enable streaming if S/MIME output * format. */ if (operation == SMIME_SIGN) { if (flags & CMS_DETACHED) { if (outformat == FORMAT_SMIME) flags |= CMS_STREAM; } flags |= CMS_PARTIAL; cms = CMS_sign(NULL, NULL, other, in, flags); if (!cms) goto end; if (econtent_type) CMS_set1_eContentType(cms, econtent_type); if (rr_to) { rr = make_receipt_request(rr_to, rr_allorfirst, rr_from); if (!rr) { BIO_puts(bio_err, "Signed Receipt Request Creation Error\n"); goto end; } } } else flags |= CMS_REUSE_DIGEST; for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { CMS_SignerInfo *si; cms_key_param *kparam; int tflags = flags; signerfile = sk_OPENSSL_STRING_value(sksigners, i); keyfile = sk_OPENSSL_STRING_value(skkeys, i); signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL, e, "signer certificate"); if (!signer) goto end; key = load_key(bio_err, keyfile, keyform, 0, passin, e, "signing key file"); if (!key) goto end; for (kparam = key_first; kparam; kparam = kparam->next) { if (kparam->idx == i) { tflags |= CMS_KEY_PARAM; break; } } si = CMS_add1_signer(cms, signer, key, sign_md, tflags); if (!si) goto end; if (kparam) { EVP_PKEY_CTX *pctx; pctx = CMS_SignerInfo_get0_pkey_ctx(si); if (!cms_set_pkey_param(pctx, kparam->param)) goto end; } if (rr && !CMS_add1_ReceiptRequest(si, rr)) goto end; X509_free(signer); signer = NULL; EVP_PKEY_free(key); key = NULL; } /* If not streaming or resigning finalize structure */ if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) { if (!CMS_final(cms, in, NULL, flags)) goto end; } } if (!cms) { BIO_printf(bio_err, "Error creating CMS structure\n"); goto end; } ret = 4; if (operation == SMIME_DECRYPT) { if (flags & CMS_DEBUG_DECRYPT) CMS_decrypt(cms, NULL, NULL, NULL, NULL, flags); if (secret_key) { if (!CMS_decrypt_set1_key(cms, secret_key, secret_keylen, secret_keyid, secret_keyidlen)) { BIO_puts(bio_err, "Error decrypting CMS using secret key\n"); goto end; } } if (key) { if (!CMS_decrypt_set1_pkey(cms, key, recip)) { BIO_puts(bio_err, "Error decrypting CMS using private key\n"); goto end; } } if (pwri_pass) { if (!CMS_decrypt_set1_password(cms, pwri_pass, -1)) { BIO_puts(bio_err, "Error decrypting CMS using password\n"); goto end; } } if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) { BIO_printf(bio_err, "Error decrypting CMS structure\n"); goto end; } } else if (operation == SMIME_DATAOUT) { if (!CMS_data(cms, out, flags)) goto end; } else if (operation == SMIME_UNCOMPRESS) { if (!CMS_uncompress(cms, indata, out, flags)) goto end; } else if (operation == SMIME_DIGEST_VERIFY) { if (CMS_digest_verify(cms, indata, out, flags) > 0) BIO_printf(bio_err, "Verification successful\n"); else { BIO_printf(bio_err, "Verification failure\n"); goto end; } } else if (operation == SMIME_ENCRYPTED_DECRYPT) { if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen, indata, out, flags)) goto end; } else if (operation == SMIME_VERIFY) { if (CMS_verify(cms, other, store, indata, out, flags) > 0) BIO_printf(bio_err, "Verification successful\n"); else { BIO_printf(bio_err, "Verification failure\n"); if (verify_retcode) ret = verify_err + 32; goto end; } if (signerfile) { STACK_OF(X509) *signers; signers = CMS_get0_signers(cms); if (!save_certs(signerfile, signers)) { BIO_printf(bio_err, "Error writing signers to %s\n", signerfile); ret = 5; goto end; } sk_X509_free(signers); } if (rr_print) receipt_request_print(bio_err, cms); } else if (operation == SMIME_VERIFY_RECEIPT) { if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0) BIO_printf(bio_err, "Verification successful\n"); else { BIO_printf(bio_err, "Verification failure\n"); goto end; } } else { if (noout) { if (print) CMS_ContentInfo_print_ctx(out, cms, 0, NULL); } else if (outformat == FORMAT_SMIME) { if (to) BIO_printf(out, "To: %s\n", to); if (from) BIO_printf(out, "From: %s\n", from); if (subject) BIO_printf(out, "Subject: %s\n", subject); if (operation == SMIME_RESIGN) ret = SMIME_write_CMS(out, cms, indata, flags); else ret = SMIME_write_CMS(out, cms, in, flags); } else if (outformat == FORMAT_PEM) ret = PEM_write_bio_CMS_stream(out, cms, in, flags); else if (outformat == FORMAT_ASN1) ret = i2d_CMS_bio_stream(out, cms, in, flags); else { BIO_printf(bio_err, "Bad output format for CMS file\n"); goto end; } if (ret <= 0) { ret = 6; goto end; } } ret = 0; end: if (ret) ERR_print_errors(bio_err); if (need_rand) app_RAND_write_file(NULL, bio_err); sk_X509_pop_free(encerts, X509_free); sk_X509_pop_free(other, X509_free); if (vpm) X509_VERIFY_PARAM_free(vpm); if (sksigners) sk_OPENSSL_STRING_free(sksigners); if (skkeys) sk_OPENSSL_STRING_free(skkeys); if (secret_key) OPENSSL_free(secret_key); if (secret_keyid) OPENSSL_free(secret_keyid); if (pwri_tmp) OPENSSL_free(pwri_tmp); if (econtent_type) ASN1_OBJECT_free(econtent_type); if (rr) CMS_ReceiptRequest_free(rr); if (rr_to) sk_OPENSSL_STRING_free(rr_to); if (rr_from) sk_OPENSSL_STRING_free(rr_from); for (key_param = key_first; key_param;) { cms_key_param *tparam; sk_OPENSSL_STRING_free(key_param->param); tparam = key_param->next; OPENSSL_free(key_param); key_param = tparam; } X509_STORE_free(store); X509_free(cert); X509_free(recip); X509_free(signer); EVP_PKEY_free(key); CMS_ContentInfo_free(cms); CMS_ContentInfo_free(rcms); BIO_free(rctin); BIO_free(in); BIO_free(indata); BIO_free_all(out); if (passin) OPENSSL_free(passin); return (ret); }
int MAIN(int argc, char **argv) { ENGINE *e = NULL; char **args; char *host = NULL, *port = NULL, *path = "/"; char *thost = NULL, *tport = NULL, *tpath = NULL; char *reqin = NULL, *respin = NULL; char *reqout = NULL, *respout = NULL; char *signfile = NULL, *keyfile = NULL; char *rsignfile = NULL, *rkeyfile = NULL; char *outfile = NULL; int add_nonce = 1, noverify = 0, use_ssl = -1; STACK_OF(CONF_VALUE) *headers = NULL; OCSP_REQUEST *req = NULL; OCSP_RESPONSE *resp = NULL; OCSP_BASICRESP *bs = NULL; X509 *issuer = NULL, *cert = NULL; X509 *signer = NULL, *rsigner = NULL; EVP_PKEY *key = NULL, *rkey = NULL; BIO *acbio = NULL, *cbio = NULL; BIO *derbio = NULL; BIO *out = NULL; int req_timeout = -1; int req_text = 0, resp_text = 0; long nsec = MAX_VALIDITY_PERIOD, maxage = -1; char *CAfile = NULL, *CApath = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL; char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; int ret = 1; int accept_count = -1; int badarg = 0; int badsig = 0; int i; int ignore_err = 0; STACK_OF(OPENSSL_STRING) *reqnames = NULL; STACK_OF(OCSP_CERTID) *ids = NULL; X509 *rca_cert = NULL; char *ridx_filename = NULL; char *rca_filename = NULL; CA_DB *rdb = NULL; int nmin = 0, ndays = -1; const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); if (!load_config(bio_err, NULL)) goto end; SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); args = argv + 1; reqnames = sk_OPENSSL_STRING_new_null(); ids = sk_OCSP_CERTID_new_null(); while (!badarg && *args && *args[0] == '-') { if (!strcmp(*args, "-out")) { if (args[1]) { args++; outfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-timeout")) { if (args[1]) { args++; req_timeout = atol(*args); if (req_timeout < 0) { BIO_printf(bio_err, "Illegal timeout value %s\n", *args); badarg = 1; } } else badarg = 1; } else if (!strcmp(*args, "-url")) { if (thost) OPENSSL_free(thost); if (tport) OPENSSL_free(tport); if (tpath) OPENSSL_free(tpath); if (args[1]) { args++; if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl)) { BIO_printf(bio_err, "Error parsing URL\n"); badarg = 1; } thost = host; tport = port; tpath = path; } else badarg = 1; } else if (!strcmp(*args, "-host")) { if (args[1]) { args++; host = *args; } else badarg = 1; } else if (!strcmp(*args, "-port")) { if (args[1]) { args++; port = *args; } else badarg = 1; } else if (!strcmp(*args, "-header")) { if (args[1] && args[2]) { if (!X509V3_add_value(args[1], args[2], &headers)) goto end; args += 2; } else badarg = 1; } else if (!strcmp(*args, "-ignore_err")) ignore_err = 1; else if (!strcmp(*args, "-noverify")) noverify = 1; else if (!strcmp(*args, "-nonce")) add_nonce = 2; else if (!strcmp(*args, "-no_nonce")) add_nonce = 0; else if (!strcmp(*args, "-resp_no_certs")) rflags |= OCSP_NOCERTS; else if (!strcmp(*args, "-resp_key_id")) rflags |= OCSP_RESPID_KEY; else if (!strcmp(*args, "-no_certs")) sign_flags |= OCSP_NOCERTS; else if (!strcmp(*args, "-no_signature_verify")) verify_flags |= OCSP_NOSIGS; else if (!strcmp(*args, "-no_cert_verify")) verify_flags |= OCSP_NOVERIFY; else if (!strcmp(*args, "-no_chain")) verify_flags |= OCSP_NOCHAIN; else if (!strcmp(*args, "-no_cert_checks")) verify_flags |= OCSP_NOCHECKS; else if (!strcmp(*args, "-no_explicit")) verify_flags |= OCSP_NOEXPLICIT; else if (!strcmp(*args, "-trust_other")) verify_flags |= OCSP_TRUSTOTHER; else if (!strcmp(*args, "-no_intern")) verify_flags |= OCSP_NOINTERN; else if (!strcmp(*args, "-badsig")) badsig = 1; else if (!strcmp(*args, "-text")) { req_text = 1; resp_text = 1; } else if (!strcmp(*args, "-req_text")) req_text = 1; else if (!strcmp(*args, "-resp_text")) resp_text = 1; else if (!strcmp(*args, "-reqin")) { if (args[1]) { args++; reqin = *args; } else badarg = 1; } else if (!strcmp(*args, "-respin")) { if (args[1]) { args++; respin = *args; } else badarg = 1; } else if (!strcmp(*args, "-signer")) { if (args[1]) { args++; signfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-VAfile")) { if (args[1]) { args++; verify_certfile = *args; verify_flags |= OCSP_TRUSTOTHER; } else badarg = 1; } else if (!strcmp(*args, "-sign_other")) { if (args[1]) { args++; sign_certfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-verify_other")) { if (args[1]) { args++; verify_certfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-CAfile")) { if (args[1]) { args++; CAfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-CApath")) { if (args[1]) { args++; CApath = *args; } else badarg = 1; } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) { if (badarg) goto end; continue; } else if (!strcmp(*args, "-validity_period")) { if (args[1]) { args++; nsec = atol(*args); if (nsec < 0) { BIO_printf(bio_err, "Illegal validity period %s\n", *args); badarg = 1; } } else badarg = 1; } else if (!strcmp(*args, "-status_age")) { if (args[1]) { args++; maxage = atol(*args); if (maxage < 0) { BIO_printf(bio_err, "Illegal validity age %s\n", *args); badarg = 1; } } else badarg = 1; } else if (!strcmp(*args, "-signkey")) { if (args[1]) { args++; keyfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-reqout")) { if (args[1]) { args++; reqout = *args; } else badarg = 1; } else if (!strcmp(*args, "-respout")) { if (args[1]) { args++; respout = *args; } else badarg = 1; } else if (!strcmp(*args, "-path")) { if (args[1]) { args++; path = *args; } else badarg = 1; } else if (!strcmp(*args, "-issuer")) { if (args[1]) { args++; X509_free(issuer); issuer = load_cert(bio_err, *args, FORMAT_PEM, NULL, e, "issuer certificate"); if (!issuer) goto end; } else badarg = 1; } else if (!strcmp(*args, "-cert")) { if (args[1]) { args++; X509_free(cert); cert = load_cert(bio_err, *args, FORMAT_PEM, NULL, e, "certificate"); if (!cert) goto end; if (!cert_id_md) cert_id_md = EVP_sha1(); if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids)) goto end; if (!sk_OPENSSL_STRING_push(reqnames, *args)) goto end; } else badarg = 1; } else if (!strcmp(*args, "-serial")) { if (args[1]) { args++; if (!cert_id_md) cert_id_md = EVP_sha1(); if (!add_ocsp_serial(&req, *args, cert_id_md, issuer, ids)) goto end; if (!sk_OPENSSL_STRING_push(reqnames, *args)) goto end; } else badarg = 1; } else if (!strcmp(*args, "-index")) { if (args[1]) { args++; ridx_filename = *args; } else badarg = 1; } else if (!strcmp(*args, "-CA")) { if (args[1]) { args++; rca_filename = *args; } else badarg = 1; } else if (!strcmp(*args, "-nmin")) { if (args[1]) { args++; nmin = atol(*args); if (nmin < 0) { BIO_printf(bio_err, "Illegal update period %s\n", *args); badarg = 1; } } if (ndays == -1) ndays = 0; else badarg = 1; } else if (!strcmp(*args, "-nrequest")) { if (args[1]) { args++; accept_count = atol(*args); if (accept_count < 0) { BIO_printf(bio_err, "Illegal accept count %s\n", *args); badarg = 1; } } else badarg = 1; } else if (!strcmp(*args, "-ndays")) { if (args[1]) { args++; ndays = atol(*args); if (ndays < 0) { BIO_printf(bio_err, "Illegal update period %s\n", *args); badarg = 1; } } else badarg = 1; } else if (!strcmp(*args, "-rsigner")) { if (args[1]) { args++; rsignfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-rkey")) { if (args[1]) { args++; rkeyfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-rother")) { if (args[1]) { args++; rcertfile = *args; } else badarg = 1; } else if (!strcmp(*args, "-rmd")) { if (args[1]) { args++; rsign_md = EVP_get_digestbyname(*args); if (!rsign_md) badarg = 1; } else badarg = 1; } else if ((cert_id_md = EVP_get_digestbyname((*args) + 1)) == NULL) { badarg = 1; } args++; } /* Have we anything to do? */ if (!req && !reqin && !respin && !(port && ridx_filename)) badarg = 1; if (badarg) { BIO_printf(bio_err, "OCSP utility\n"); BIO_printf(bio_err, "Usage ocsp [options]\n"); BIO_printf(bio_err, "where options are\n"); BIO_printf(bio_err, "-out file output filename\n"); BIO_printf(bio_err, "-issuer file issuer certificate\n"); BIO_printf(bio_err, "-cert file certificate to check\n"); BIO_printf(bio_err, "-serial n serial number to check\n"); BIO_printf(bio_err, "-signer file certificate to sign OCSP request with\n"); BIO_printf(bio_err, "-signkey file private key to sign OCSP request with\n"); BIO_printf(bio_err, "-sign_other file additional certificates to include in signed request\n"); BIO_printf(bio_err, "-no_certs don't include any certificates in signed request\n"); BIO_printf(bio_err, "-req_text print text form of request\n"); BIO_printf(bio_err, "-resp_text print text form of response\n"); BIO_printf(bio_err, "-text print text form of request and response\n"); BIO_printf(bio_err, "-reqout file write DER encoded OCSP request to \"file\"\n"); BIO_printf(bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n"); BIO_printf(bio_err, "-reqin file read DER encoded OCSP request from \"file\"\n"); BIO_printf(bio_err, "-respin file read DER encoded OCSP reponse from \"file\"\n"); BIO_printf(bio_err, "-nonce add OCSP nonce to request\n"); BIO_printf(bio_err, "-no_nonce don't add OCSP nonce to request\n"); BIO_printf(bio_err, "-url URL OCSP responder URL\n"); BIO_printf(bio_err, "-host host:n send OCSP request to host on port n\n"); BIO_printf(bio_err, "-path path to use in OCSP request\n"); BIO_printf(bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf(bio_err, "-CAfile file trusted certificates file\n"); BIO_printf(bio_err, "-VAfile file validator certificates file\n"); BIO_printf(bio_err, "-validity_period n maximum validity discrepancy in seconds\n"); BIO_printf(bio_err, "-status_age n maximum status age in seconds\n"); BIO_printf(bio_err, "-noverify don't verify response at all\n"); BIO_printf(bio_err, "-verify_other file additional certificates to search for signer\n"); BIO_printf(bio_err, "-trust_other don't verify additional certificates\n"); BIO_printf(bio_err, "-no_intern don't search certificates contained in response for signer\n"); BIO_printf(bio_err, "-no_signature_verify don't check signature on response\n"); BIO_printf(bio_err, "-no_cert_verify don't check signing certificate\n"); BIO_printf(bio_err, "-no_chain don't chain verify response\n"); BIO_printf(bio_err, "-no_cert_checks don't do additional checks on signing certificate\n"); BIO_printf(bio_err, "-port num port to run responder on\n"); BIO_printf(bio_err, "-index file certificate status index file\n"); BIO_printf(bio_err, "-CA file CA certificate\n"); BIO_printf(bio_err, "-rsigner file responder certificate to sign responses with\n"); BIO_printf(bio_err, "-rkey file responder key to sign responses with\n"); BIO_printf(bio_err, "-rother file other certificates to include in response\n"); BIO_printf(bio_err, "-resp_no_certs don't include any certificates in response\n"); BIO_printf(bio_err, "-nmin n number of minutes before next update\n"); BIO_printf(bio_err, "-ndays n number of days before next update\n"); BIO_printf(bio_err, "-resp_key_id identify reponse by signing certificate key ID\n"); BIO_printf(bio_err, "-nrequest n number of requests to accept (default unlimited)\n"); BIO_printf(bio_err, "-<dgst alg> use specified digest in the request\n"); BIO_printf(bio_err, "-timeout n timeout connection to OCSP responder after n seconds\n"); goto end; } if (outfile) out = BIO_new_file(outfile, "w"); else out = BIO_new_fp(stdout, BIO_NOCLOSE); if (!out) { BIO_printf(bio_err, "Error opening output file\n"); goto end; } if (!req && (add_nonce != 2)) add_nonce = 0; if (!req && reqin) { if (!strcmp(reqin, "-")) derbio = BIO_new_fp(stdin, BIO_NOCLOSE); else derbio = BIO_new_file(reqin, "rb"); if (!derbio) { BIO_printf(bio_err, "Error Opening OCSP request file\n"); goto end; } req = d2i_OCSP_REQUEST_bio(derbio, NULL); BIO_free(derbio); if (!req) { BIO_printf(bio_err, "Error reading OCSP request\n"); goto end; } } if (!req && port) { acbio = init_responder(port); if (!acbio) goto end; } if (rsignfile && !rdb) { if (!rkeyfile) rkeyfile = rsignfile; rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM, NULL, e, "responder certificate"); if (!rsigner) { BIO_printf(bio_err, "Error loading responder certificate\n"); goto end; } rca_cert = load_cert(bio_err, rca_filename, FORMAT_PEM, NULL, e, "CA certificate"); if (rcertfile) { rother = load_certs(bio_err, rcertfile, FORMAT_PEM, NULL, e, "responder other certificates"); if (!rother) goto end; } rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, 0, NULL, NULL, "responder private key"); if (!rkey) goto end; } if (acbio) BIO_printf(bio_err, "Waiting for OCSP client connections...\n"); redo_accept: if (acbio) { if (!do_responder(&req, &cbio, acbio, port)) goto end; if (!req) { resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); send_ocsp_response(cbio, resp); goto done_resp; } } if (!req && (signfile || reqout || host || add_nonce || ridx_filename)) { BIO_printf(bio_err, "Need an OCSP request for this operation!\n"); goto end; } if (req && add_nonce) OCSP_request_add1_nonce(req, NULL, -1); if (signfile) { if (!keyfile) keyfile = signfile; signer = load_cert(bio_err, signfile, FORMAT_PEM, NULL, e, "signer certificate"); if (!signer) { BIO_printf(bio_err, "Error loading signer certificate\n"); goto end; } if (sign_certfile) { sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM, NULL, e, "signer certificates"); if (!sign_other) goto end; } key = load_key(bio_err, keyfile, FORMAT_PEM, 0, NULL, NULL, "signer private key"); if (!key) goto end; if (!OCSP_request_sign (req, signer, key, NULL, sign_other, sign_flags)) { BIO_printf(bio_err, "Error signing OCSP request\n"); goto end; } } if (req_text && req) OCSP_REQUEST_print(out, req, 0); if (reqout) { if (!strcmp(reqout, "-")) derbio = BIO_new_fp(stdout, BIO_NOCLOSE); else derbio = BIO_new_file(reqout, "wb"); if (!derbio) { BIO_printf(bio_err, "Error opening file %s\n", reqout); goto end; } i2d_OCSP_REQUEST_bio(derbio, req); BIO_free(derbio); } if (ridx_filename && (!rkey || !rsigner || !rca_cert)) { BIO_printf(bio_err, "Need a responder certificate, key and CA for this operation!\n"); goto end; } if (ridx_filename && !rdb) { rdb = load_index(ridx_filename, NULL); if (!rdb) goto end; if (!index_index(rdb)) goto end; } if (rdb) { i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, rsign_md, rother, rflags, nmin, ndays, badsig); if (cbio) send_ocsp_response(cbio, resp); } else if (host) { # ifndef OPENSSL_NO_SOCK resp = process_responder(bio_err, req, host, path, port, use_ssl, headers, req_timeout); if (!resp) goto end; # else BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n"); goto end; # endif } else if (respin) { if (!strcmp(respin, "-")) derbio = BIO_new_fp(stdin, BIO_NOCLOSE); else derbio = BIO_new_file(respin, "rb"); if (!derbio) { BIO_printf(bio_err, "Error Opening OCSP response file\n"); goto end; } resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); BIO_free(derbio); if (!resp) { BIO_printf(bio_err, "Error reading OCSP response\n"); goto end; } } else { ret = 0; goto end; } done_resp: if (respout) { if (!strcmp(respout, "-")) derbio = BIO_new_fp(stdout, BIO_NOCLOSE); else derbio = BIO_new_file(respout, "wb"); if (!derbio) { BIO_printf(bio_err, "Error opening file %s\n", respout); goto end; } i2d_OCSP_RESPONSE_bio(derbio, resp); BIO_free(derbio); } i = OCSP_response_status(resp); if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { BIO_printf(out, "Responder Error: %s (%d)\n", OCSP_response_status_str(i), i); if (ignore_err) goto redo_accept; ret = 0; goto end; } if (resp_text) OCSP_RESPONSE_print(out, resp, 0); /* If running as responder don't verify our own response */ if (cbio) { if (accept_count > 0) accept_count--; /* Redo if more connections needed */ if (accept_count) { BIO_free_all(cbio); cbio = NULL; OCSP_REQUEST_free(req); req = NULL; OCSP_RESPONSE_free(resp); resp = NULL; goto redo_accept; } ret = 0; goto end; } else if (ridx_filename) { ret = 0; goto end; } if (!store) store = setup_verify(bio_err, CAfile, CApath); if (!store) goto end; if (vpm) X509_STORE_set1_param(store, vpm); if (verify_certfile) { verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM, NULL, e, "validator certificate"); if (!verify_other) goto end; } bs = OCSP_response_get1_basic(resp); if (!bs) { BIO_printf(bio_err, "Error parsing response\n"); goto end; } ret = 0; if (!noverify) { if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) { if (i == -1) BIO_printf(bio_err, "WARNING: no nonce in response\n"); else { BIO_printf(bio_err, "Nonce Verify error\n"); ret = 1; goto end; } } i = OCSP_basic_verify(bs, verify_other, store, verify_flags); if (i <= 0) { BIO_printf(bio_err, "Response Verify Failure\n"); ERR_print_errors(bio_err); ret = 1; } else BIO_printf(bio_err, "Response verify OK\n"); } if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage)) ret = 1; end: ERR_print_errors(bio_err); X509_free(signer); X509_STORE_free(store); if (vpm) X509_VERIFY_PARAM_free(vpm); EVP_PKEY_free(key); EVP_PKEY_free(rkey); X509_free(issuer); X509_free(cert); X509_free(rsigner); X509_free(rca_cert); free_index(rdb); BIO_free_all(cbio); BIO_free_all(acbio); BIO_free(out); OCSP_REQUEST_free(req); OCSP_RESPONSE_free(resp); OCSP_BASICRESP_free(bs); sk_OPENSSL_STRING_free(reqnames); sk_OCSP_CERTID_free(ids); sk_X509_pop_free(sign_other, X509_free); sk_X509_pop_free(verify_other, X509_free); sk_CONF_VALUE_pop_free(headers, X509V3_conf_free); if (thost) OPENSSL_free(thost); if (tport) OPENSSL_free(tport); if (tpath) OPENSSL_free(tpath); OPENSSL_EXIT(ret); }
int MAIN(int argc, char **argv) { ENGINE *e = NULL; int operation = 0; int ret = 0; char **args; const char *inmode = "r", *outmode = "w"; char *infile = NULL, *outfile = NULL; char *signerfile = NULL, *recipfile = NULL; char *certfile = NULL, *keyfile = NULL, *contfile=NULL; const EVP_CIPHER *cipher = NULL; PKCS7 *p7 = NULL; X509_STORE *store = NULL; X509 *cert = NULL, *recip = NULL, *signer = NULL; EVP_PKEY *key = NULL; STACK_OF(X509) *encerts = NULL, *other = NULL; BIO *in = NULL, *out = NULL, *indata = NULL; int badarg = 0; int flags = PKCS7_DETACHED; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; char *inrand = NULL; int need_rand = 0; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; int keyform = FORMAT_PEM; #ifndef OPENSSL_NO_ENGINE char *engine=NULL; #endif X509_VERIFY_PARAM *vpm = NULL; args = argv + 1; ret = 1; apps_startup(); if (bio_err == NULL) { if ((bio_err = BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT); } if (!load_config(bio_err, NULL)) goto end; while (!badarg && *args && *args[0] == '-') { if (!strcmp (*args, "-encrypt")) operation = SMIME_ENCRYPT; else if (!strcmp (*args, "-decrypt")) operation = SMIME_DECRYPT; else if (!strcmp (*args, "-sign")) operation = SMIME_SIGN; else if (!strcmp (*args, "-verify")) operation = SMIME_VERIFY; else if (!strcmp (*args, "-pk7out")) operation = SMIME_PK7OUT; #ifndef OPENSSL_NO_DES else if (!strcmp (*args, "-des3")) cipher = EVP_des_ede3_cbc(); else if (!strcmp (*args, "-des")) cipher = EVP_des_cbc(); #endif #ifndef OPENSSL_NO_SEED else if (!strcmp (*args, "-seed")) cipher = EVP_seed_cbc(); #endif #ifndef OPENSSL_NO_RC2 else if (!strcmp (*args, "-rc2-40")) cipher = EVP_rc2_40_cbc(); else if (!strcmp (*args, "-rc2-128")) cipher = EVP_rc2_cbc(); else if (!strcmp (*args, "-rc2-64")) cipher = EVP_rc2_64_cbc(); #endif #ifndef OPENSSL_NO_AES else if (!strcmp(*args,"-aes128")) cipher = EVP_aes_128_cbc(); else if (!strcmp(*args,"-aes192")) cipher = EVP_aes_192_cbc(); else if (!strcmp(*args,"-aes256")) cipher = EVP_aes_256_cbc(); #endif #ifndef OPENSSL_NO_CAMELLIA else if (!strcmp(*args,"-camellia128")) cipher = EVP_camellia_128_cbc(); else if (!strcmp(*args,"-camellia192")) cipher = EVP_camellia_192_cbc(); else if (!strcmp(*args,"-camellia256")) cipher = EVP_camellia_256_cbc(); #endif else if (!strcmp (*args, "-text")) flags |= PKCS7_TEXT; else if (!strcmp (*args, "-nointern")) flags |= PKCS7_NOINTERN; else if (!strcmp (*args, "-noverify")) flags |= PKCS7_NOVERIFY; else if (!strcmp (*args, "-nochain")) flags |= PKCS7_NOCHAIN; else if (!strcmp (*args, "-nocerts")) flags |= PKCS7_NOCERTS; else if (!strcmp (*args, "-noattr")) flags |= PKCS7_NOATTR; else if (!strcmp (*args, "-nodetach")) flags &= ~PKCS7_DETACHED; else if (!strcmp (*args, "-nosmimecap")) flags |= PKCS7_NOSMIMECAP; else if (!strcmp (*args, "-binary")) flags |= PKCS7_BINARY; else if (!strcmp (*args, "-nosigs")) flags |= PKCS7_NOSIGS; else if (!strcmp (*args, "-nooldmime")) flags |= PKCS7_NOOLDMIMETYPE; else if (!strcmp (*args, "-crlfeol")) flags |= PKCS7_CRLFEOL; else if (!strcmp(*args,"-rand")) { if (args[1]) { args++; inrand = *args; } else badarg = 1; need_rand = 1; } #ifndef OPENSSL_NO_ENGINE else if (!strcmp(*args,"-engine")) { if (args[1]) { args++; engine = *args; } else badarg = 1; } #endif else if (!strcmp(*args,"-passin")) { if (args[1]) { args++; passargin = *args; } else badarg = 1; } else if (!strcmp (*args, "-to")) { if (args[1]) { args++; to = *args; } else badarg = 1; } else if (!strcmp (*args, "-from")) { if (args[1]) { args++; from = *args; } else badarg = 1; } else if (!strcmp (*args, "-subject")) { if (args[1]) { args++; subject = *args; } else badarg = 1; } else if (!strcmp (*args, "-signer")) { if (args[1]) { args++; signerfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-recip")) { if (args[1]) { args++; recipfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-inkey")) { if (args[1]) { args++; keyfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-keyform")) { if (args[1]) { args++; keyform = str2fmt(*args); } else badarg = 1; } else if (!strcmp (*args, "-certfile")) { if (args[1]) { args++; certfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-CAfile")) { if (args[1]) { args++; CAfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-CApath")) { if (args[1]) { args++; CApath = *args; } else badarg = 1; } else if (!strcmp (*args, "-in")) { if (args[1]) { args++; infile = *args; } else badarg = 1; } else if (!strcmp (*args, "-inform")) { if (args[1]) { args++; informat = str2fmt(*args); } else badarg = 1; } else if (!strcmp (*args, "-outform")) { if (args[1]) { args++; outformat = str2fmt(*args); } else badarg = 1; } else if (!strcmp (*args, "-out")) { if (args[1]) { args++; outfile = *args; } else badarg = 1; } else if (!strcmp (*args, "-content")) { if (args[1]) { args++; contfile = *args; } else badarg = 1; } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) continue; else badarg = 1; args++; } if (operation == SMIME_SIGN) { if (!signerfile) { BIO_printf(bio_err, "No signer certificate specified\n"); badarg = 1; } need_rand = 1; } else if (operation == SMIME_DECRYPT) { if (!recipfile && !keyfile) { BIO_printf(bio_err, "No recipient certificate or key specified\n"); badarg = 1; } } else if (operation == SMIME_ENCRYPT) { if (!*args) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); badarg = 1; } need_rand = 1; } else if (!operation) badarg = 1; if (badarg) { BIO_printf (bio_err, "Usage smime [options] cert.pem ...\n"); BIO_printf (bio_err, "where options are\n"); BIO_printf (bio_err, "-encrypt encrypt message\n"); BIO_printf (bio_err, "-decrypt decrypt encrypted message\n"); BIO_printf (bio_err, "-sign sign message\n"); BIO_printf (bio_err, "-verify verify signed message\n"); BIO_printf (bio_err, "-pk7out output PKCS#7 structure\n"); #ifndef OPENSSL_NO_DES BIO_printf (bio_err, "-des3 encrypt with triple DES\n"); BIO_printf (bio_err, "-des encrypt with DES\n"); #endif #ifndef OPENSSL_NO_SEED BIO_printf (bio_err, "-seed encrypt with SEED\n"); #endif #ifndef OPENSSL_NO_RC2 BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40 (default)\n"); BIO_printf (bio_err, "-rc2-64 encrypt with RC2-64\n"); BIO_printf (bio_err, "-rc2-128 encrypt with RC2-128\n"); #endif #ifndef OPENSSL_NO_AES BIO_printf (bio_err, "-aes128, -aes192, -aes256\n"); BIO_printf (bio_err, " encrypt PEM output with cbc aes\n"); #endif #ifndef OPENSSL_NO_CAMELLIA BIO_printf (bio_err, "-camellia128, -camellia192, -camellia256\n"); BIO_printf (bio_err, " encrypt PEM output with cbc camellia\n"); #endif BIO_printf (bio_err, "-nointern don't search certificates in message for signer\n"); BIO_printf (bio_err, "-nosigs don't verify message signature\n"); BIO_printf (bio_err, "-noverify don't verify signers certificate\n"); BIO_printf (bio_err, "-nocerts don't include signers certificate when signing\n"); BIO_printf (bio_err, "-nodetach use opaque signing\n"); BIO_printf (bio_err, "-noattr don't include any signed attributes\n"); BIO_printf (bio_err, "-binary don't translate message to text\n"); BIO_printf (bio_err, "-certfile file other certificates file\n"); BIO_printf (bio_err, "-signer file signer certificate file\n"); BIO_printf (bio_err, "-recip file recipient certificate file for decryption\n"); BIO_printf (bio_err, "-in file input file\n"); BIO_printf (bio_err, "-inform arg input format SMIME (default), PEM or DER\n"); BIO_printf (bio_err, "-inkey file input private key (if not signer or recipient)\n"); BIO_printf (bio_err, "-keyform arg input private key format (PEM or ENGINE)\n"); BIO_printf (bio_err, "-out file output file\n"); BIO_printf (bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); BIO_printf (bio_err, "-content file supply or override content for detached signature\n"); BIO_printf (bio_err, "-to addr to address\n"); BIO_printf (bio_err, "-from ad from address\n"); BIO_printf (bio_err, "-subject s subject\n"); BIO_printf (bio_err, "-text include or delete text MIME headers\n"); BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); BIO_printf (bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); BIO_printf (bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); #ifndef OPENSSL_NO_ENGINE BIO_printf (bio_err, "-engine e use engine e, possibly a hardware device.\n"); #endif BIO_printf (bio_err, "-passin arg input file pass phrase source\n"); BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); BIO_printf(bio_err, " load the file (or the files in the directory) into\n"); BIO_printf(bio_err, " the random number generator\n"); BIO_printf (bio_err, "cert.pem recipient certificate(s) for encryption\n"); goto end; } #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine, 0); #endif if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (need_rand) { app_RAND_load_file(NULL, bio_err, (inrand != NULL)); if (inrand != NULL) BIO_printf(bio_err,"%ld semi-random bytes loaded\n", app_RAND_load_files(inrand)); } ret = 2; if (operation != SMIME_SIGN) flags &= ~PKCS7_DETACHED; if (operation & SMIME_OP) { if (flags & PKCS7_BINARY) inmode = "rb"; if (outformat == FORMAT_ASN1) outmode = "wb"; } else { if (flags & PKCS7_BINARY) outmode = "wb"; if (informat == FORMAT_ASN1) inmode = "rb"; } if (operation == SMIME_ENCRYPT) { if (!cipher) { #ifndef OPENSSL_NO_RC2 cipher = EVP_rc2_40_cbc(); #else BIO_printf(bio_err, "No cipher selected\n"); goto end; #endif } encerts = sk_X509_new_null(); while (*args) { if (!(cert = load_cert(bio_err,*args,FORMAT_PEM, NULL, e, "recipient certificate file"))) { #if 0 /* An appropriate message is already printed */ BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args); #endif goto end; } sk_X509_push(encerts, cert); cert = NULL; args++; } } if (signerfile && (operation == SMIME_SIGN)) { if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM, NULL, e, "signer certificate"))) { #if 0 /* An appropri message has already been printed */ BIO_printf(bio_err, "Can't read signer certificate file %s\n", signerfile); #endif goto end; } } if (certfile) { if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL, e, "certificate file"))) { #if 0 /* An appropriate message has already been printed */ BIO_printf(bio_err, "Can't read certificate file %s\n", certfile); #endif ERR_print_errors(bio_err); goto end; } } if (recipfile && (operation == SMIME_DECRYPT)) { if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL, e, "recipient certificate file"))) { #if 0 /* An appropriate message has alrady been printed */ BIO_printf(bio_err, "Can't read recipient certificate file %s\n", recipfile); #endif ERR_print_errors(bio_err); goto end; } } if (operation == SMIME_DECRYPT) { if (!keyfile) keyfile = recipfile; } else if (operation == SMIME_SIGN) { if (!keyfile) keyfile = signerfile; } else keyfile = NULL; if (keyfile) { key = load_key(bio_err, keyfile, keyform, 0, passin, e, "signing key file"); if (!key) goto end; } if (infile) { if (!(in = BIO_new_file(infile, inmode))) { BIO_printf (bio_err, "Can't open input file %s\n", infile); goto end; } } else in = BIO_new_fp(stdin, BIO_NOCLOSE); if (outfile) { if (!(out = BIO_new_file(outfile, outmode))) { BIO_printf (bio_err, "Can't open output file %s\n", outfile); goto end; } } else { out = BIO_new_fp(stdout, BIO_NOCLOSE); #ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); out = BIO_push(tmpbio, out); } #endif } if (operation == SMIME_VERIFY) { if (!(store = setup_verify(bio_err, CAfile, CApath))) goto end; X509_STORE_set_verify_cb_func(store, smime_cb); if (vpm) X509_STORE_set1_param(store, vpm); } ret = 3; if (operation == SMIME_ENCRYPT) p7 = PKCS7_encrypt(encerts, in, cipher, flags); else if (operation == SMIME_SIGN) { /* If detached data and SMIME output enable partial * signing. */ if ((flags & PKCS7_DETACHED) && (outformat == FORMAT_SMIME)) flags |= PKCS7_STREAM; p7 = PKCS7_sign(signer, key, other, in, flags); } else { if (informat == FORMAT_SMIME) p7 = SMIME_read_PKCS7(in, &indata); else if (informat == FORMAT_PEM) p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); else if (informat == FORMAT_ASN1) p7 = d2i_PKCS7_bio(in, NULL); else { BIO_printf(bio_err, "Bad input format for PKCS#7 file\n"); goto end; } if (!p7) { BIO_printf(bio_err, "Error reading S/MIME message\n"); goto end; } if (contfile) { BIO_free(indata); if (!(indata = BIO_new_file(contfile, "rb"))) { BIO_printf(bio_err, "Can't read content file %s\n", contfile); goto end; } } } if (!p7) { BIO_printf(bio_err, "Error creating PKCS#7 structure\n"); goto end; } ret = 4; if (operation == SMIME_DECRYPT) { if (!PKCS7_decrypt(p7, key, recip, out, flags)) { BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n"); goto end; } } else if (operation == SMIME_VERIFY) { STACK_OF(X509) *signers; if (PKCS7_verify(p7, other, store, indata, out, flags)) BIO_printf(bio_err, "Verification successful\n"); else { BIO_printf(bio_err, "Verification failure\n"); goto end; } signers = PKCS7_get0_signers(p7, other, flags); if (!save_certs(signerfile, signers)) { BIO_printf(bio_err, "Error writing signers to %s\n", signerfile); ret = 5; goto end; } sk_X509_free(signers); } else if (operation == SMIME_PK7OUT) PEM_write_bio_PKCS7(out, p7); else { if (to) BIO_printf(out, "To: %s\n", to); if (from) BIO_printf(out, "From: %s\n", from); if (subject) BIO_printf(out, "Subject: %s\n", subject); if (outformat == FORMAT_SMIME) SMIME_write_PKCS7(out, p7, in, flags); else if (outformat == FORMAT_PEM) PEM_write_bio_PKCS7(out,p7); else if (outformat == FORMAT_ASN1) i2d_PKCS7_bio(out,p7); else { BIO_printf(bio_err, "Bad output format for PKCS#7 file\n"); goto end; } } ret = 0; end: if (need_rand) app_RAND_write_file(NULL, bio_err); if (ret) ERR_print_errors(bio_err); sk_X509_pop_free(encerts, X509_free); sk_X509_pop_free(other, X509_free); if (vpm) X509_VERIFY_PARAM_free(vpm); X509_STORE_free(store); X509_free(cert); X509_free(recip); X509_free(signer); EVP_PKEY_free(key); PKCS7_free(p7); BIO_free(in); BIO_free(indata); BIO_free_all(out); if (passin) OPENSSL_free(passin); return (ret); }
int s_client_main(int argc, char **argv) { unsigned int off = 0, clr = 0; SSL *con = NULL; int s, k, width, state = 0, af = AF_UNSPEC; char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; int cbuf_len, cbuf_off; int sbuf_len, sbuf_off; fd_set readfds, writefds; char *port = PORT_STR; int full_log = 1; char *host = SSL_HOST_NAME; char *cert_file = NULL, *key_file = NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; char *passarg = NULL, *pass = NULL; X509 *cert = NULL; EVP_PKEY *key = NULL; char *CApath = NULL, *CAfile = NULL, *cipher = NULL; int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE, bugs = 0; int crlf = 0; int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; SSL_CTX *ctx = NULL; int ret = 1, in_init = 1, i, nbio_test = 0; int starttls_proto = PROTO_OFF; int prexit = 0; X509_VERIFY_PARAM *vpm = NULL; int badarg = 0; const SSL_METHOD *meth = NULL; int socket_type = SOCK_STREAM; BIO *sbio; int mbuf_len = 0; struct timeval timeout, *timeoutp; const char *errstr = NULL; #ifndef OPENSSL_NO_ENGINE char *engine_id = NULL; char *ssl_client_engine_id = NULL; ENGINE *ssl_client_engine = NULL; #endif ENGINE *e = NULL; #ifndef OPENSSL_NO_TLSEXT char *servername = NULL; tlsextctx tlsextcbp = {NULL, 0}; #ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; #endif #endif char *sess_in = NULL; char *sess_out = NULL; struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0; long socket_mtu = 0; meth = SSLv23_client_method(); c_Pause = 0; c_quiet = 0; c_ign_eof = 0; c_debug = 0; c_msg = 0; c_showcerts = 0; if (((cbuf = malloc(BUFSIZZ)) == NULL) || ((sbuf = malloc(BUFSIZZ)) == NULL) || ((mbuf = malloc(BUFSIZZ + 1)) == NULL)) { /* NUL byte */ BIO_printf(bio_err, "out of memory\n"); goto end; } verify_depth = 0; verify_error = X509_V_OK; c_nbio = 0; argc--; argv++; while (argc >= 1) { if (strcmp(*argv, "-host") == 0) { if (--argc < 1) goto bad; host = *(++argv); } else if (strcmp(*argv, "-port") == 0) { if (--argc < 1) goto bad; port = *(++argv); if (port == NULL || *port == '\0') goto bad; } else if (strcmp(*argv, "-connect") == 0) { if (--argc < 1) goto bad; if (!extract_host_port(*(++argv), &host, NULL, &port)) goto bad; } else if (strcmp(*argv, "-verify") == 0) { verify = SSL_VERIFY_PEER; if (--argc < 1) goto bad; verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); if (errstr) goto bad; BIO_printf(bio_err, "verify depth is %d\n", verify_depth); } else if (strcmp(*argv, "-cert") == 0) { if (--argc < 1) goto bad; cert_file = *(++argv); } else if (strcmp(*argv, "-sess_out") == 0) { if (--argc < 1) goto bad; sess_out = *(++argv); } else if (strcmp(*argv, "-sess_in") == 0) { if (--argc < 1) goto bad; sess_in = *(++argv); } else if (strcmp(*argv, "-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto bad; continue; } else if (strcmp(*argv, "-verify_return_error") == 0) verify_return_error = 1; else if (strcmp(*argv, "-prexit") == 0) prexit = 1; else if (strcmp(*argv, "-crlf") == 0) crlf = 1; else if (strcmp(*argv, "-quiet") == 0) { c_quiet = 1; c_ign_eof = 1; } else if (strcmp(*argv, "-ign_eof") == 0) c_ign_eof = 1; else if (strcmp(*argv, "-no_ign_eof") == 0) c_ign_eof = 0; else if (strcmp(*argv, "-pause") == 0) c_Pause = 1; else if (strcmp(*argv, "-debug") == 0) c_debug = 1; #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-tlsextdebug") == 0) c_tlsextdebug = 1; else if (strcmp(*argv, "-status") == 0) c_status_req = 1; #endif else if (strcmp(*argv, "-msg") == 0) c_msg = 1; else if (strcmp(*argv, "-showcerts") == 0) c_showcerts = 1; else if (strcmp(*argv, "-nbio_test") == 0) nbio_test = 1; else if (strcmp(*argv, "-state") == 0) state = 1; else if (strcmp(*argv, "-ssl3") == 0) meth = SSLv3_client_method(); else if (strcmp(*argv, "-tls1_2") == 0) meth = TLSv1_2_client_method(); else if (strcmp(*argv, "-tls1_1") == 0) meth = TLSv1_1_client_method(); else if (strcmp(*argv, "-tls1") == 0) meth = TLSv1_client_method(); #ifndef OPENSSL_NO_DTLS1 else if (strcmp(*argv, "-dtls1") == 0) { meth = DTLSv1_client_method(); socket_type = SOCK_DGRAM; } else if (strcmp(*argv, "-timeout") == 0) enable_timeouts = 1; else if (strcmp(*argv, "-mtu") == 0) { if (--argc < 1) goto bad; socket_mtu = strtonum(*(++argv), 0, LONG_MAX, &errstr); if (errstr) goto bad; } #endif else if (strcmp(*argv, "-bugs") == 0) bugs = 1; else if (strcmp(*argv, "-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); } else if (strcmp(*argv, "-pass") == 0) { if (--argc < 1) goto bad; passarg = *(++argv); } else if (strcmp(*argv, "-key") == 0) { if (--argc < 1) goto bad; key_file = *(++argv); } else if (strcmp(*argv, "-reconnect") == 0) { reconnect = 5; } else if (strcmp(*argv, "-CApath") == 0) { if (--argc < 1) goto bad; CApath = *(++argv); } else if (strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); } else if (strcmp(*argv, "-no_tls1_2") == 0) off |= SSL_OP_NO_TLSv1_2; else if (strcmp(*argv, "-no_tls1_1") == 0) off |= SSL_OP_NO_TLSv1_1; else if (strcmp(*argv, "-no_tls1") == 0) off |= SSL_OP_NO_TLSv1; else if (strcmp(*argv, "-no_ssl3") == 0) off |= SSL_OP_NO_SSLv3; else if (strcmp(*argv, "-no_ssl2") == 0) off |= SSL_OP_NO_SSLv2; else if (strcmp(*argv, "-no_comp") == 0) { off |= SSL_OP_NO_COMPRESSION; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-no_ticket") == 0) { off |= SSL_OP_NO_TICKET; } #ifndef OPENSSL_NO_NEXTPROTONEG else if (strcmp(*argv, "-nextprotoneg") == 0) { if (--argc < 1) goto bad; next_proto_neg_in = *(++argv); } #endif #endif else if (strcmp(*argv, "-serverpref") == 0) off |= SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv, "-legacy_renegotiation") == 0) ; /* no-op */ else if (strcmp(*argv, "-legacy_server_connect") == 0) { off |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-no_legacy_server_connect") == 0) { clr |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-cipher") == 0) { if (--argc < 1) goto bad; cipher = *(++argv); } else if (strcmp(*argv, "-nbio") == 0) { c_nbio = 1; } else if (strcmp(*argv, "-starttls") == 0) { if (--argc < 1) goto bad; ++argv; if (strcmp(*argv, "smtp") == 0) starttls_proto = PROTO_SMTP; else if (strcmp(*argv, "lmtp") == 0) starttls_proto = PROTO_LMTP; else if (strcmp(*argv, "pop3") == 0) starttls_proto = PROTO_POP3; else if (strcmp(*argv, "imap") == 0) starttls_proto = PROTO_IMAP; else if (strcmp(*argv, "ftp") == 0) starttls_proto = PROTO_FTP; else if (strcmp(*argv, "xmpp") == 0) starttls_proto = PROTO_XMPP; else goto bad; } #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv, "-engine") == 0) { if (--argc < 1) goto bad; engine_id = *(++argv); } else if (strcmp(*argv, "-ssl_client_engine") == 0) { if (--argc < 1) goto bad; ssl_client_engine_id = *(++argv); } #endif else if (strcmp(*argv, "-4") == 0) { af = AF_INET; } else if (strcmp(*argv, "-6") == 0) { af = AF_INET6; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-servername") == 0) { if (--argc < 1) goto bad; servername = *(++argv); /* meth=TLSv1_client_method(); */ } #endif #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) goto bad; srtp_profiles = *(++argv); } #endif else if (strcmp(*argv, "-keymatexport") == 0) { if (--argc < 1) goto bad; keymatexportlabel = *(++argv); } else if (strcmp(*argv, "-keymatexportlen") == 0) { const char *errstr; if (--argc < 1) goto bad; keymatexportlen = strtonum(*(++argv), 1, INT_MAX, &errstr); if (errstr) goto bad; } else { BIO_printf(bio_err, "unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: if (errstr) BIO_printf(bio_err, "invalid argument %s: %s\n", *argv, errstr); else sc_usage(); goto end; } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; if (next_proto_neg_in) { next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); if (next_proto.data == NULL) { BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); goto end; } } else next_proto.data = NULL; #endif #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); if (ssl_client_engine_id) { ssl_client_engine = ENGINE_by_id(ssl_client_engine_id); if (!ssl_client_engine) { BIO_printf(bio_err, "Error getting client auth engine\n"); goto end; } } #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (key_file == NULL) key_file = cert_file; if (key_file) { key = load_key(bio_err, key_file, key_format, 0, pass, e, "client certificate private key file"); if (!key) { ERR_print_errors(bio_err); goto end; } } if (cert_file) { cert = load_cert(bio_err, cert_file, cert_format, NULL, e, "client certificate file"); if (!cert) { ERR_print_errors(bio_err); goto end; } } if (bio_c_out == NULL) { if (c_quiet && !c_debug && !c_msg) { bio_c_out = BIO_new(BIO_s_null()); } else { if (bio_c_out == NULL) bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE); } } ctx = SSL_CTX_new(meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; } if (vpm) SSL_CTX_set1_param(ctx, vpm); #ifndef OPENSSL_NO_ENGINE if (ssl_client_engine) { if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { BIO_puts(bio_err, "Error setting client auth engine\n"); ERR_print_errors(bio_err); ENGINE_free(ssl_client_engine); goto end; } ENGINE_free(ssl_client_engine); } #endif #ifndef OPENSSL_NO_SRTP if (srtp_profiles != NULL) SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); #endif if (bugs) SSL_CTX_set_options(ctx, SSL_OP_ALL | off); else SSL_CTX_set_options(ctx, off); if (clr) SSL_CTX_clear_options(ctx, clr); /* * DTLS: partial reads end up discarding unread UDP bytes :-( Setting * read ahead solves this problem. */ if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.data) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); #endif if (state) SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); if (cipher != NULL) if (!SSL_CTX_set_cipher_list(ctx, cipher)) { BIO_printf(bio_err, "error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } SSL_CTX_set_verify(ctx, verify, verify_callback); if (!set_cert_key_stuff(ctx, cert, key)) goto end; if ((!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { /* * BIO_printf(bio_err,"error setting default verify * locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { tlsextcbp.biodebug = bio_err; SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); } #endif con = SSL_new(ctx); if (sess_in) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); if (!stmp) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); BIO_free(stmp); if (!sess) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } SSL_set_session(con, sess); SSL_SESSION_free(sess); } #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { if (!SSL_set_tlsext_host_name(con, servername)) { BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); ERR_print_errors(bio_err); goto end; } } #endif /* SSL_set_cipher_list(con,"RC4-MD5"); */ re_start: if (init_client(&s, host, port, socket_type, af) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); if (c_nbio) { unsigned long l = 1; BIO_printf(bio_c_out, "turning on non blocking io\n"); if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) { ERR_print_errors(bio_err); goto end; } } if (c_Pause & 0x01) SSL_set_debug(con, 1); if (SSL_version(con) == DTLS1_VERSION) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (getsockname(s, &peer, (void *) &peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } (void) BIO_ctrl_set_connected(sbio, 1, &peer); if (enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 0; timeout.tv_usec = DGRAM_SND_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); } else sbio = BIO_new_socket(s, BIO_NOCLOSE); if (nbio_test) { BIO *test; test = BIO_new(BIO_f_nbio_test()); sbio = BIO_push(test, sbio); } if (c_debug) { SSL_set_debug(con, 1); BIO_set_callback(sbio, bio_dump_callback); BIO_set_callback_arg(sbio, (char *) bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } #ifndef OPENSSL_NO_TLSEXT if (c_tlsextdebug) { SSL_set_tlsext_debug_callback(con, tlsext_cb); SSL_set_tlsext_debug_arg(con, bio_c_out); } if (c_status_req) { SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); } #endif SSL_set_bio(con, sbio, sbio); SSL_set_connect_state(con); /* ok, lets connect */ width = SSL_get_fd(con) + 1; read_tty = 1; write_tty = 0; tty_on = 0; read_ssl = 1; write_ssl = 1; cbuf_len = 0; cbuf_off = 0; sbuf_len = 0; sbuf_off = 0; /* This is an ugly hack that does a lot of assumptions */ /* * We do have to handle multi-line responses which may come in a * single packet or not. We therefore have to use BIO_gets() which * does need a buffering BIO. So during the initial chitchat we do * push a buffering BIO into the chain that is removed again later on * to not disturb the rest of the s_client operation. */ if (starttls_proto == PROTO_SMTP || starttls_proto == PROTO_LMTP) { int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from SMTP */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); } while (mbuf_len > 3 && mbuf[3] == '-'); /* STARTTLS command requires EHLO... */ BIO_printf(fbio, "%cHLO openssl.client.net\r\n", starttls_proto == PROTO_SMTP ? 'E' : 'L'); (void) BIO_flush(fbio); /* wait for multi-line response to end EHLO SMTP response */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); if (strstr(mbuf, "STARTTLS")) foundit = 1; } while (mbuf_len > 3 && mbuf[3] == '-'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found starttls in server response," " try anyway...\n"); BIO_printf(sbio, "STARTTLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_POP3) { mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ); if (mbuf_len == -1) { BIO_printf(bio_err, "BIO_read failed\n"); goto end; } BIO_printf(sbio, "STLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_IMAP) { int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); BIO_gets(fbio, mbuf, BUFSIZZ); /* STARTTLS command requires CAPABILITY... */ BIO_printf(fbio, ". CAPABILITY\r\n"); (void) BIO_flush(fbio); /* wait for multi-line CAPABILITY response */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); if (strstr(mbuf, "STARTTLS")) foundit = 1; } while (mbuf_len > 3 && mbuf[0] != '.'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found STARTTLS in server response," " try anyway...\n"); BIO_printf(sbio, ". STARTTLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_FTP) { BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from FTP */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); } while (mbuf_len > 3 && mbuf[3] == '-'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); BIO_printf(sbio, "AUTH TLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } if (starttls_proto == PROTO_XMPP) { int seen = 0; BIO_printf(sbio, "<stream:stream " "xmlns:stream='http://etherx.jabber.org/streams' " "xmlns='jabber:client' to='%s' version='1.0'>", host); seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'")) { if (strstr(mbuf, "/stream:features>")) goto shut; seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; } BIO_printf(sbio, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); seen = BIO_read(sbio, sbuf, BUFSIZZ); sbuf[seen] = 0; if (!strstr(sbuf, "<proceed")) goto shut; mbuf[0] = 0; } for (;;) { FD_ZERO(&readfds); FD_ZERO(&writefds); if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_get_timeout(con, &timeout)) timeoutp = &timeout; else timeoutp = NULL; if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { in_init = 1; tty_on = 0; } else { tty_on = 1; if (in_init) { in_init = 0; if (sess_out) { BIO *stmp = BIO_new_file(sess_out, "w"); if (stmp) { PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con)); BIO_free(stmp); } else BIO_printf(bio_err, "Error writing session file %s\n", sess_out); } print_stuff(bio_c_out, con, full_log); if (full_log > 0) full_log--; if (starttls_proto) { BIO_write(bio_err, mbuf, mbuf_len); /* We don't need to know any more */ starttls_proto = PROTO_OFF; } if (reconnect) { reconnect--; BIO_printf(bio_c_out, "drop connection and then reconnect\n"); SSL_shutdown(con); SSL_set_connect_state(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); goto re_start; } } } ssl_pending = read_ssl && SSL_pending(con); /* XXX should add tests for fd_set overflow */ if (!ssl_pending) { if (tty_on) { if (read_tty) FD_SET(fileno(stdin), &readfds); if (write_tty) FD_SET(fileno(stdout), &writefds); } if (read_ssl) FD_SET(SSL_get_fd(con), &readfds); if (write_ssl) FD_SET(SSL_get_fd(con), &writefds); /* printf("mode tty(%d %d%d) ssl(%d%d)\n", tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ i = select(width, &readfds, &writefds, NULL, timeoutp); if (i < 0) { BIO_printf(bio_err, "bad select %d\n", errno); goto shut; /* goto end; */ } } if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { BIO_printf(bio_err, "TIMEOUT occured\n"); } if (!ssl_pending && FD_ISSET(SSL_get_fd(con), &writefds)) { k = SSL_write(con, &(cbuf[cbuf_off]), (unsigned int) cbuf_len); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: cbuf_off += k; cbuf_len -= k; if (k <= 0) goto end; /* we have done a write(con,NULL,0); */ if (cbuf_len <= 0) { read_tty = 1; write_ssl = 0; } else { /* if (cbuf_len > 0) */ read_tty = 0; write_ssl = 1; } break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "write W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "write R BLOCK\n"); write_tty = 0; read_ssl = 1; write_ssl = 0; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "write X BLOCK\n"); break; case SSL_ERROR_ZERO_RETURN: if (cbuf_len != 0) { BIO_printf(bio_c_out, "shutdown\n"); ret = 0; goto shut; } else { read_tty = 1; write_ssl = 0; break; } case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { BIO_printf(bio_err, "write:errno=%d\n", errno); goto shut; } else { read_tty = 1; write_ssl = 0; } break; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; } } else if (!ssl_pending && FD_ISSET(fileno(stdout), &writefds)) { i = write(fileno(stdout), &(sbuf[sbuf_off]), sbuf_len); if (i <= 0) { BIO_printf(bio_c_out, "DONE\n"); ret = 0; goto shut; /* goto end; */ } sbuf_len -= i; sbuf_off += i; if (sbuf_len <= 0) { read_ssl = 1; write_tty = 0; } } else if (ssl_pending || FD_ISSET(SSL_get_fd(con), &readfds)) { #ifdef RENEG { static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii = 0; } } #endif k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: if (k <= 0) goto end; sbuf_off = 0; sbuf_len = k; read_ssl = 0; write_tty = 1; break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "read W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "read R BLOCK\n"); write_tty = 0; read_ssl = 1; if ((read_tty == 0) && (write_ssl == 0)) write_ssl = 1; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: ret = errno; BIO_printf(bio_err, "read:errno=%d\n", ret); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out, "closed\n"); ret = 0; goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; /* break; */ } } else if (FD_ISSET(fileno(stdin), &readfds)) { if (crlf) { int j, lf_num; i = read(fileno(stdin), cbuf, BUFSIZZ / 2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) if (cbuf[j] == '\n') lf_num++; for (j = i - 1; j >= 0; j--) { cbuf[j + lf_num] = cbuf[j]; if (cbuf[j] == '\n') { lf_num--; i++; cbuf[j + lf_num] = '\r'; } } assert(lf_num == 0); } else i = read(fileno(stdin), cbuf, BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err, "DONE\n"); ret = 0; goto shut; } if ((!c_ign_eof) && (cbuf[0] == 'R')) { BIO_printf(bio_err, "RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len = 0; } else { cbuf_len = i; cbuf_off = 0; } write_ssl = 1; read_tty = 0; } } ret = 0; shut: if (in_init) print_stuff(bio_c_out, con, full_log); SSL_shutdown(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); end: if (con != NULL) { if (prexit != 0) print_stuff(bio_c_out, con, 1); SSL_free(con); } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) free(next_proto.data); #endif if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); if (key) EVP_PKEY_free(key); free(pass); if (vpm) X509_VERIFY_PARAM_free(vpm); if (cbuf != NULL) { OPENSSL_cleanse(cbuf, BUFSIZZ); free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf, BUFSIZZ); free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf, BUFSIZZ); free(mbuf); } if (bio_c_out != NULL) { BIO_free(bio_c_out); bio_c_out = NULL; } return (ret); }
int smime_main(int argc, char **argv) { ENGINE *e = NULL; int operation = 0; int ret = 0; char **args; const char *inmode = "r", *outmode = "w"; char *infile = NULL, *outfile = NULL; char *signerfile = NULL, *recipfile = NULL; STACK_OF(OPENSSL_STRING) * sksigners = NULL, *skkeys = NULL; char *certfile = NULL, *keyfile = NULL, *contfile = NULL; const EVP_CIPHER *cipher = NULL; PKCS7 *p7 = NULL; X509_STORE *store = NULL; X509 *cert = NULL, *recip = NULL, *signer = NULL; EVP_PKEY *key = NULL; STACK_OF(X509) * encerts = NULL, *other = NULL; BIO *in = NULL, *out = NULL, *indata = NULL; int badarg = 0; int flags = PKCS7_DETACHED; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; int indef = 0; const EVP_MD *sign_md = NULL; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; int keyform = FORMAT_PEM; #ifndef OPENSSL_NO_ENGINE char *engine = NULL; #endif X509_VERIFY_PARAM *vpm = NULL; args = argv + 1; ret = 1; while (!badarg && *args && *args[0] == '-') { if (!strcmp(*args, "-encrypt")) operation = SMIME_ENCRYPT; else if (!strcmp(*args, "-decrypt")) operation = SMIME_DECRYPT; else if (!strcmp(*args, "-sign")) operation = SMIME_SIGN; else if (!strcmp(*args, "-resign")) operation = SMIME_RESIGN; else if (!strcmp(*args, "-verify")) operation = SMIME_VERIFY; else if (!strcmp(*args, "-pk7out")) operation = SMIME_PK7OUT; #ifndef OPENSSL_NO_DES else if (!strcmp(*args, "-des3")) cipher = EVP_des_ede3_cbc(); else if (!strcmp(*args, "-des")) cipher = EVP_des_cbc(); #endif #ifndef OPENSSL_NO_RC2 else if (!strcmp(*args, "-rc2-40")) cipher = EVP_rc2_40_cbc(); else if (!strcmp(*args, "-rc2-128")) cipher = EVP_rc2_cbc(); else if (!strcmp(*args, "-rc2-64")) cipher = EVP_rc2_64_cbc(); #endif #ifndef OPENSSL_NO_AES else if (!strcmp(*args, "-aes128")) cipher = EVP_aes_128_cbc(); else if (!strcmp(*args, "-aes192")) cipher = EVP_aes_192_cbc(); else if (!strcmp(*args, "-aes256")) cipher = EVP_aes_256_cbc(); #endif #ifndef OPENSSL_NO_CAMELLIA else if (!strcmp(*args, "-camellia128")) cipher = EVP_camellia_128_cbc(); else if (!strcmp(*args, "-camellia192")) cipher = EVP_camellia_192_cbc(); else if (!strcmp(*args, "-camellia256")) cipher = EVP_camellia_256_cbc(); #endif else if (!strcmp(*args, "-text")) flags |= PKCS7_TEXT; else if (!strcmp(*args, "-nointern")) flags |= PKCS7_NOINTERN; else if (!strcmp(*args, "-noverify")) flags |= PKCS7_NOVERIFY; else if (!strcmp(*args, "-nochain")) flags |= PKCS7_NOCHAIN; else if (!strcmp(*args, "-nocerts")) flags |= PKCS7_NOCERTS; else if (!strcmp(*args, "-noattr")) flags |= PKCS7_NOATTR; else if (!strcmp(*args, "-nodetach")) flags &= ~PKCS7_DETACHED; else if (!strcmp(*args, "-nosmimecap")) flags |= PKCS7_NOSMIMECAP; else if (!strcmp(*args, "-binary")) flags |= PKCS7_BINARY; else if (!strcmp(*args, "-nosigs")) flags |= PKCS7_NOSIGS; else if (!strcmp(*args, "-stream")) indef = 1; else if (!strcmp(*args, "-indef")) indef = 1; else if (!strcmp(*args, "-noindef")) indef = 0; else if (!strcmp(*args, "-nooldmime")) flags |= PKCS7_NOOLDMIMETYPE; else if (!strcmp(*args, "-crlfeol")) flags |= PKCS7_CRLFEOL; #ifndef OPENSSL_NO_ENGINE else if (!strcmp(*args, "-engine")) { if (!args[1]) goto argerr; engine = *++args; } #endif else if (!strcmp(*args, "-passin")) { if (!args[1]) goto argerr; passargin = *++args; } else if (!strcmp(*args, "-to")) { if (!args[1]) goto argerr; to = *++args; } else if (!strcmp(*args, "-from")) { if (!args[1]) goto argerr; from = *++args; } else if (!strcmp(*args, "-subject")) { if (!args[1]) goto argerr; subject = *++args; } else if (!strcmp(*args, "-signer")) { if (!args[1]) goto argerr; /* If previous -signer argument add signer to list */ if (signerfile) { if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); if (!keyfile) keyfile = signerfile; if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(skkeys, keyfile); keyfile = NULL; } signerfile = *++args; } else if (!strcmp(*args, "-recip")) { if (!args[1]) goto argerr; recipfile = *++args; } else if (!strcmp(*args, "-md")) { if (!args[1]) goto argerr; sign_md = EVP_get_digestbyname(*++args); if (sign_md == NULL) { BIO_printf(bio_err, "Unknown digest %s\n", *args); goto argerr; } } else if (!strcmp(*args, "-inkey")) { if (!args[1]) goto argerr; /* If previous -inkey arument add signer to list */ if (keyfile) { if (!signerfile) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); goto argerr; } if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); signerfile = NULL; if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(skkeys, keyfile); } keyfile = *++args; } else if (!strcmp(*args, "-keyform")) { if (!args[1]) goto argerr; keyform = str2fmt(*++args); } else if (!strcmp(*args, "-certfile")) { if (!args[1]) goto argerr; certfile = *++args; } else if (!strcmp(*args, "-CAfile")) { if (!args[1]) goto argerr; CAfile = *++args; } else if (!strcmp(*args, "-CApath")) { if (!args[1]) goto argerr; CApath = *++args; } else if (!strcmp(*args, "-in")) { if (!args[1]) goto argerr; infile = *++args; } else if (!strcmp(*args, "-inform")) { if (!args[1]) goto argerr; informat = str2fmt(*++args); } else if (!strcmp(*args, "-outform")) { if (!args[1]) goto argerr; outformat = str2fmt(*++args); } else if (!strcmp(*args, "-out")) { if (!args[1]) goto argerr; outfile = *++args; } else if (!strcmp(*args, "-content")) { if (!args[1]) goto argerr; contfile = *++args; } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) continue; else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL) badarg = 1; args++; } if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) { BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); goto argerr; } if (operation & SMIME_SIGNERS) { /* Check to see if any final signer needs to be appended */ if (keyfile && !signerfile) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); goto argerr; } if (signerfile) { if (!sksigners) sksigners = sk_OPENSSL_STRING_new_null(); sk_OPENSSL_STRING_push(sksigners, signerfile); if (!skkeys) skkeys = sk_OPENSSL_STRING_new_null(); if (!keyfile) keyfile = signerfile; sk_OPENSSL_STRING_push(skkeys, keyfile); } if (!sksigners) { BIO_printf(bio_err, "No signer certificate specified\n"); badarg = 1; } signerfile = NULL; keyfile = NULL; } else if (operation == SMIME_DECRYPT) { if (!recipfile && !keyfile) { BIO_printf(bio_err, "No recipient certificate or key specified\n"); badarg = 1; } } else if (operation == SMIME_ENCRYPT) { if (!*args) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); badarg = 1; } } else if (!operation) badarg = 1; if (badarg) { argerr: BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n"); BIO_printf(bio_err, "where options are\n"); BIO_printf(bio_err, "-encrypt encrypt message\n"); BIO_printf(bio_err, "-decrypt decrypt encrypted message\n"); BIO_printf(bio_err, "-sign sign message\n"); BIO_printf(bio_err, "-verify verify signed message\n"); BIO_printf(bio_err, "-pk7out output PKCS#7 structure\n"); #ifndef OPENSSL_NO_DES BIO_printf(bio_err, "-des3 encrypt with triple DES\n"); BIO_printf(bio_err, "-des encrypt with DES\n"); #endif #ifndef OPENSSL_NO_RC2 BIO_printf(bio_err, "-rc2-40 encrypt with RC2-40 (default)\n"); BIO_printf(bio_err, "-rc2-64 encrypt with RC2-64\n"); BIO_printf(bio_err, "-rc2-128 encrypt with RC2-128\n"); #endif #ifndef OPENSSL_NO_AES BIO_printf(bio_err, "-aes128, -aes192, -aes256\n"); BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); #endif #ifndef OPENSSL_NO_CAMELLIA BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n"); BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); #endif BIO_printf(bio_err, "-nointern don't search certificates in message for signer\n"); BIO_printf(bio_err, "-nosigs don't verify message signature\n"); BIO_printf(bio_err, "-noverify don't verify signers certificate\n"); BIO_printf(bio_err, "-nocerts don't include signers certificate when signing\n"); BIO_printf(bio_err, "-nodetach use opaque signing\n"); BIO_printf(bio_err, "-noattr don't include any signed attributes\n"); BIO_printf(bio_err, "-binary don't translate message to text\n"); BIO_printf(bio_err, "-certfile file other certificates file\n"); BIO_printf(bio_err, "-signer file signer certificate file\n"); BIO_printf(bio_err, "-recip file recipient certificate file for decryption\n"); BIO_printf(bio_err, "-in file input file\n"); BIO_printf(bio_err, "-inform arg input format SMIME (default), PEM or DER\n"); BIO_printf(bio_err, "-inkey file input private key (if not signer or recipient)\n"); BIO_printf(bio_err, "-keyform arg input private key format (PEM or ENGINE)\n"); BIO_printf(bio_err, "-out file output file\n"); BIO_printf(bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); BIO_printf(bio_err, "-content file supply or override content for detached signature\n"); BIO_printf(bio_err, "-to addr to address\n"); BIO_printf(bio_err, "-from ad from address\n"); BIO_printf(bio_err, "-subject s subject\n"); BIO_printf(bio_err, "-text include or delete text MIME headers\n"); BIO_printf(bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf(bio_err, "-CAfile file trusted certificates file\n"); BIO_printf(bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); #ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); #endif BIO_printf(bio_err, "-passin arg input file pass phrase source\n"); BIO_printf(bio_err, "cert.pem recipient certificate(s) for encryption\n"); goto end; } #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine, 0); #endif if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } ret = 2; if (!(operation & SMIME_SIGNERS)) flags &= ~PKCS7_DETACHED; if (operation & SMIME_OP) { if (outformat == FORMAT_ASN1) outmode = "wb"; } else { if (flags & PKCS7_BINARY) outmode = "wb"; } if (operation & SMIME_IP) { if (informat == FORMAT_ASN1) inmode = "rb"; } else { if (flags & PKCS7_BINARY) inmode = "rb"; } if (operation == SMIME_ENCRYPT) { if (!cipher) { #ifndef OPENSSL_NO_RC2 cipher = EVP_rc2_40_cbc(); #else BIO_printf(bio_err, "No cipher selected\n"); goto end; #endif } encerts = sk_X509_new_null(); while (*args) { if (!(cert = load_cert(bio_err, *args, FORMAT_PEM, NULL, e, "recipient certificate file"))) { goto end; } sk_X509_push(encerts, cert); cert = NULL; args++; } } if (certfile) { if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL, e, "certificate file"))) { ERR_print_errors(bio_err); goto end; } } if (recipfile && (operation == SMIME_DECRYPT)) { if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL, e, "recipient certificate file"))) { ERR_print_errors(bio_err); goto end; } } if (operation == SMIME_DECRYPT) { if (!keyfile) keyfile = recipfile; } else if (operation == SMIME_SIGN) { if (!keyfile) keyfile = signerfile; } else keyfile = NULL; if (keyfile) { key = load_key(bio_err, keyfile, keyform, 0, passin, e, "signing key file"); if (!key) goto end; } if (infile) { if (!(in = BIO_new_file(infile, inmode))) { BIO_printf(bio_err, "Can't open input file %s\n", infile); goto end; } } else in = BIO_new_fp(stdin, BIO_NOCLOSE); if (operation & SMIME_IP) { if (informat == FORMAT_SMIME) p7 = SMIME_read_PKCS7(in, &indata); else if (informat == FORMAT_PEM) p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); else if (informat == FORMAT_ASN1) p7 = d2i_PKCS7_bio(in, NULL); else { BIO_printf(bio_err, "Bad input format for PKCS#7 file\n"); goto end; } if (!p7) { BIO_printf(bio_err, "Error reading S/MIME message\n"); goto end; } if (contfile) { BIO_free(indata); if (!(indata = BIO_new_file(contfile, "rb"))) { BIO_printf(bio_err, "Can't read content file %s\n", contfile); goto end; } } } if (outfile) { if (!(out = BIO_new_file(outfile, outmode))) { BIO_printf(bio_err, "Can't open output file %s\n", outfile); goto end; } } else { out = BIO_new_fp(stdout, BIO_NOCLOSE); } if (operation == SMIME_VERIFY) { if (!(store = setup_verify(bio_err, CAfile, CApath))) goto end; X509_STORE_set_verify_cb(store, smime_cb); if (vpm) X509_STORE_set1_param(store, vpm); } ret = 3; if (operation == SMIME_ENCRYPT) { if (indef) flags |= PKCS7_STREAM; p7 = PKCS7_encrypt(encerts, in, cipher, flags); } else if (operation & SMIME_SIGNERS) { int i; /* * If detached data content we only enable streaming if * S/MIME output format. */ if (operation == SMIME_SIGN) { if (flags & PKCS7_DETACHED) { if (outformat == FORMAT_SMIME) flags |= PKCS7_STREAM; } else if (indef) flags |= PKCS7_STREAM; flags |= PKCS7_PARTIAL; p7 = PKCS7_sign(NULL, NULL, other, in, flags); if (!p7) goto end; } else flags |= PKCS7_REUSE_DIGEST; for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { signerfile = sk_OPENSSL_STRING_value(sksigners, i); keyfile = sk_OPENSSL_STRING_value(skkeys, i); signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL, e, "signer certificate"); if (!signer) goto end; key = load_key(bio_err, keyfile, keyform, 0, passin, e, "signing key file"); if (!key) goto end; if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags)) goto end; X509_free(signer); signer = NULL; EVP_PKEY_free(key); key = NULL; } /* If not streaming or resigning finalize structure */ if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) { if (!PKCS7_final(p7, in, flags)) goto end; } } if (!p7) { BIO_printf(bio_err, "Error creating PKCS#7 structure\n"); goto end; } ret = 4; if (operation == SMIME_DECRYPT) { if (!PKCS7_decrypt(p7, key, recip, out, flags)) { BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n"); goto end; } } else if (operation == SMIME_VERIFY) { STACK_OF(X509) * signers; if (PKCS7_verify(p7, other, store, indata, out, flags)) BIO_printf(bio_err, "Verification successful\n"); else { BIO_printf(bio_err, "Verification failure\n"); goto end; } signers = PKCS7_get0_signers(p7, other, flags); if (!save_certs(signerfile, signers)) { BIO_printf(bio_err, "Error writing signers to %s\n", signerfile); ret = 5; goto end; } sk_X509_free(signers); } else if (operation == SMIME_PK7OUT) PEM_write_bio_PKCS7(out, p7); else { if (to) BIO_printf(out, "To: %s\n", to); if (from) BIO_printf(out, "From: %s\n", from); if (subject) BIO_printf(out, "Subject: %s\n", subject); if (outformat == FORMAT_SMIME) { if (operation == SMIME_RESIGN) SMIME_write_PKCS7(out, p7, indata, flags); else SMIME_write_PKCS7(out, p7, in, flags); } else if (outformat == FORMAT_PEM) PEM_write_bio_PKCS7_stream(out, p7, in, flags); else if (outformat == FORMAT_ASN1) i2d_PKCS7_bio_stream(out, p7, in, flags); else { BIO_printf(bio_err, "Bad output format for PKCS#7 file\n"); goto end; } } ret = 0; end: if (ret) ERR_print_errors(bio_err); sk_X509_pop_free(encerts, X509_free); sk_X509_pop_free(other, X509_free); if (vpm) X509_VERIFY_PARAM_free(vpm); if (sksigners) sk_OPENSSL_STRING_free(sksigners); if (skkeys) sk_OPENSSL_STRING_free(skkeys); X509_STORE_free(store); X509_free(cert); X509_free(recip); X509_free(signer); EVP_PKEY_free(key); PKCS7_free(p7); BIO_free(in); BIO_free(indata); BIO_free_all(out); free(passin); return (ret); }
int verify_main(int argc, char **argv) { int i, ret = 1, badarg = 0; char *CApath = NULL, *CAfile = NULL; char *untfile = NULL, *trustfile = NULL, *crlfile = NULL; STACK_OF(X509) * untrusted = NULL, *trusted = NULL; STACK_OF(X509_CRL) * crls = NULL; X509_STORE *cert_ctx = NULL; X509_LOOKUP *lookup = NULL; X509_VERIFY_PARAM *vpm = NULL; if (single_execution) { if (pledge("stdio rpath", NULL) == -1) { perror("pledge"); exit(1); } } cert_ctx = X509_STORE_new(); if (cert_ctx == NULL) goto end; X509_STORE_set_verify_cb(cert_ctx, cb); argc--; argv++; for (;;) { if (argc >= 1) { if (strcmp(*argv, "-CApath") == 0) { if (argc-- < 1) goto end; CApath = *(++argv); } else if (strcmp(*argv, "-CAfile") == 0) { if (argc-- < 1) goto end; CAfile = *(++argv); } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto end; continue; } else if (strcmp(*argv, "-untrusted") == 0) { if (argc-- < 1) goto end; untfile = *(++argv); } else if (strcmp(*argv, "-trusted") == 0) { if (argc-- < 1) goto end; trustfile = *(++argv); } else if (strcmp(*argv, "-CRLfile") == 0) { if (argc-- < 1) goto end; crlfile = *(++argv); } else if (strcmp(*argv, "-help") == 0) goto end; else if (strcmp(*argv, "-verbose") == 0) v_verbose = 1; else if (argv[0][0] == '-') goto end; else break; argc--; argv++; } else break; } if (vpm) X509_STORE_set1_param(cert_ctx, vpm); lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); if (lookup == NULL) abort(); if (CAfile) { i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM); if (!i) { BIO_printf(bio_err, "Error loading file %s\n", CAfile); ERR_print_errors(bio_err); goto end; } } else X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); if (lookup == NULL) abort(); if (CApath) { i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); if (!i) { BIO_printf(bio_err, "Error loading directory %s\n", CApath); ERR_print_errors(bio_err); goto end; } } else X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); ERR_clear_error(); if (untfile) { untrusted = load_certs(bio_err, untfile, FORMAT_PEM, NULL, "untrusted certificates"); if (!untrusted) goto end; } if (trustfile) { trusted = load_certs(bio_err, trustfile, FORMAT_PEM, NULL, "trusted certificates"); if (!trusted) goto end; } if (crlfile) { crls = load_crls(bio_err, crlfile, FORMAT_PEM, NULL, "other CRLs"); if (!crls) goto end; } ret = 0; if (argc < 1) { if (1 != check(cert_ctx, NULL, untrusted, trusted, crls)) ret = -1; } else { for (i = 0; i < argc; i++) if (1 != check(cert_ctx, argv[i], untrusted, trusted, crls)) ret = -1; } end: if (ret == 1) { BIO_printf(bio_err, "usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]"); BIO_printf(bio_err, " [-attime timestamp]"); BIO_printf(bio_err, " cert1 cert2 ...\n"); BIO_printf(bio_err, "recognized usages:\n"); for (i = 0; i < X509_PURPOSE_get_count(); i++) { X509_PURPOSE *ptmp; ptmp = X509_PURPOSE_get0(i); BIO_printf(bio_err, "\t%-10s\t%s\n", X509_PURPOSE_get0_sname(ptmp), X509_PURPOSE_get0_name(ptmp)); } } if (vpm) X509_VERIFY_PARAM_free(vpm); if (cert_ctx != NULL) X509_STORE_free(cert_ctx); sk_X509_pop_free(untrusted, X509_free); sk_X509_pop_free(trusted, X509_free); sk_X509_CRL_pop_free(crls, X509_CRL_free); return (ret < 0 ? 2 : ret); }