示例#1
0
文件: cms.c 项目: witchu/lua-openssl
static int openssl_cms_sign(lua_State *L)
{
  X509* signcert = CHECK_OBJECT(1, X509, "openssl.x509");
  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
  STACK_OF(X509)* certs = CHECK_OBJECT(3, STACK_OF(X509), "openssl.stack_of_x509");
  BIO* data = load_bio_object(L, 4);
  unsigned int flags = luaL_optint(L, 5, 0);
  CMS_ContentInfo *cms;
  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
  cms = CMS_sign(signcert, pkey, certs, data, flags);
  if (cms)
  {
    PUSH_OBJECT(cms, "openssl.cms");
    return 1;
  }
  return openssl_pushresult(L, 0);
}
示例#2
0
文件: cms.c 项目: LuaDist2/bkopenssl
static int openssl_cms_sign(lua_State *L)
{
  X509* signcert = CHECK_OBJECT(1, X509, "openssl.x509");
  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
  STACK_OF(X509)* certs = openssl_sk_x509_fromtable(L, 3);
  BIO* data = load_bio_object(L, 4);
  unsigned int flags = luaL_optint(L, 5, 0);
  CMS_ContentInfo *cms;

  cms = CMS_sign(signcert, pkey, certs, data, flags);
  if (cms)
  {
    PUSH_OBJECT(cms, "openssl.cms");
    return 1;
  }
  return openssl_pushresult(L, 0);
}
示例#3
0
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, &ltmp);
            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, &ltmp);
            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);
}
示例#4
0
int main(int argc, char **argv)
{
    BIO *in = NULL, *out = NULL, *tbio = NULL;
    X509 *scert = NULL;
    EVP_PKEY *skey = NULL;
    CMS_ContentInfo *cms = NULL;
    int ret = 1;

    /*
     * For simple S/MIME signing use CMS_DETACHED. On OpenSSL 1.0.0 only: for
     * streaming detached set CMS_DETACHED|CMS_STREAM for streaming
     * non-detached set CMS_STREAM
     */
    int flags = CMS_DETACHED | CMS_STREAM;

    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    /* Read in signer certificate and private key */
    tbio = BIO_new_file("signer.pem", "r");

    if (!tbio)
        goto err;

    scert = PEM_read_bio_X509(tbio, NULL, 0, NULL);

    BIO_reset(tbio);

    skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL);

    if (!scert || !skey)
        goto err;

    /* Open content being signed */

    in = BIO_new_file("sign.txt", "r");

    if (!in)
        goto err;

    /* Sign content */
    cms = CMS_sign(scert, skey, NULL, in, flags);

    if (!cms)
        goto err;

    out = BIO_new_file("smout.txt", "w");
    if (!out)
        goto err;

    if (!(flags & CMS_STREAM))
        BIO_reset(in);

    /* Write out S/MIME message */
    if (!SMIME_write_CMS(out, cms, in, flags))
        goto err;

    ret = 0;

 err:

    if (ret) {
        fprintf(stderr, "Error Signing Data\n");
        ERR_print_errors_fp(stderr);
    }

    if (cms)
        CMS_ContentInfo_free(cms);
    if (scert)
        X509_free(scert);
    EVP_PKEY_free(skey);

    BIO_free(in);
    BIO_free(out);
    BIO_free(tbio);

    return ret;

}
int main(int argc, char **argv)
	{
	BIO *in = NULL, *out = NULL, *tbio = NULL;
	X509 *scert = NULL, *scert2 = NULL;
	EVP_PKEY *skey = NULL, *skey2 = NULL;
	CMS_ContentInfo *cms = NULL;
	int ret = 1;

	OpenSSL_add_all_algorithms();
	ERR_load_crypto_strings();

	tbio = BIO_new_file("signer.pem", "r");

	if (!tbio)
		goto err;

	scert = PEM_read_bio_X509(tbio, NULL, 0, NULL);

	BIO_reset(tbio);

	skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL);

	BIO_free(tbio);

	tbio = BIO_new_file("signer2.pem", "r");

	if (!tbio)
		goto err;

	scert2 = PEM_read_bio_X509(tbio, NULL, 0, NULL);

	BIO_reset(tbio);

	skey2 = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL);

	if (!scert2 || !skey2)
		goto err;

	in = BIO_new_file("sign.txt", "r");

	if (!in)
		goto err;

	cms = CMS_sign(NULL, NULL, NULL, in, CMS_STREAM|CMS_PARTIAL);

	if (!cms)
		goto err;

	/* Add each signer in turn */

	if (!CMS_add1_signer(cms, scert, skey, NULL, 0))
		goto err;

	if (!CMS_add1_signer(cms, scert2, skey2, NULL, 0))
		goto err;

	out = BIO_new_file("smout.txt", "w");
	if (!out)
		goto err;

	/* NB: content included and finalized by SMIME_write_CMS */

	if (!SMIME_write_CMS(out, cms, in, CMS_STREAM))
		goto err;

	ret = 0;

	err:

	if (ret)
		{
		fprintf(stderr, "Error Signing Data\n");
		ERR_print_errors_fp(stderr);
		}

	if (cms)
		CMS_ContentInfo_free(cms);

	if (scert)
		X509_free(scert);
	if (skey)
		EVP_PKEY_free(skey);

	if (scert2)
		X509_free(scert2);
	if (skey)
		EVP_PKEY_free(skey2);

	if (in)
		BIO_free(in);
	if (out)
		BIO_free(out);
	if (tbio)
		BIO_free(tbio);

	return ret;

	}
示例#6
0
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size, 
    const char *cert_pwd, uint8_t **signature, int32_t *signature_size)
{
    PKCS12 *p12 = NULL;
    EVP_PKEY *evp_pkey = NULL;
    BUF_MEM *buf_mem = NULL;
    BIO *cert_bio = NULL;
    BIO *message_bio = NULL;
    BIO *signature_bio = NULL;
    CMS_ContentInfo *cms = NULL;
    CMS_SignerInfo *signer_info = NULL;
    STACK_OF(X509) *ca_stack = NULL;
    X509 *cert = NULL;
    int32_t result = 0;
    int32_t err = MZ_OK;


    if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
        return MZ_PARAM_ERROR;

    mz_crypt_init();

    *signature = NULL;
    *signature_size = 0;

    cert_bio = BIO_new_mem_buf(cert_data, cert_data_size);

    if (d2i_PKCS12_bio(cert_bio, &p12) == NULL)
        err = MZ_SIGN_ERROR;
    if (err == MZ_OK)
        result = PKCS12_parse(p12, cert_pwd, &evp_pkey, &cert, &ca_stack);
    if (result)
    {
        cms = CMS_sign(NULL, NULL, ca_stack, NULL, CMS_BINARY | CMS_PARTIAL);
        if (cms)
            signer_info = CMS_add1_signer(cms, cert, evp_pkey, EVP_sha256(), 0);
        if (signer_info == NULL)
        {
            err = MZ_SIGN_ERROR;
        }
        else
        {
            message_bio = BIO_new_mem_buf(message, message_size);
            signature_bio = BIO_new(BIO_s_mem());

            result = CMS_final(cms, message_bio, NULL, CMS_BINARY);
            if (result)
                result = i2d_CMS_bio(signature_bio, cms);
            if (result)
            {
                BIO_flush(signature_bio);
                BIO_get_mem_ptr(signature_bio, &buf_mem);

                *signature_size = buf_mem->length;
                *signature = MZ_ALLOC(buf_mem->length);
                
                memcpy(*signature, buf_mem->data, buf_mem->length);
            }
#if 0            
            BIO *yy = BIO_new_file("xyz", "wb");
            BIO_write(yy, *signature, *signature_size);
            BIO_flush(yy);
            BIO_free(yy);
#endif
        }
    }

    if (!result)
        err = MZ_SIGN_ERROR;

    if (cms)
        CMS_ContentInfo_free(cms);
    if (signature_bio)
        BIO_free(signature_bio);
    if (cert_bio)
        BIO_free(cert_bio);
    if (message_bio)
        BIO_free(message_bio);
    if (p12)
        PKCS12_free(p12);

    if (err != MZ_OK && *signature != NULL)
    {
        MZ_FREE(*signature);
        *signature = NULL;
        *signature_size = 0;
    }

    return err;
}
示例#7
0
文件: cms.c 项目: Muffo/openssl
int cms_main(int argc, char **argv)
{
    ASN1_OBJECT *econtent_type = NULL;
    BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
    CMS_ContentInfo *cms = NULL, *rcms = NULL;
    CMS_ReceiptRequest *rr = NULL;
    ENGINE *e = NULL;
    EVP_PKEY *key = NULL;
    const EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL;
    const EVP_MD *sign_md = NULL;
    STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL;
    STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
    STACK_OF(X509) *encerts = NULL, *other = NULL;
    X509 *cert = NULL, *recip = NULL, *signer = NULL;
    X509_STORE *store = NULL;
    X509_VERIFY_PARAM *vpm = NULL;
    char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
    const char *CAfile = NULL, *CApath = NULL;
    char *certsoutfile = NULL;
    int noCAfile = 0, noCApath = 0;
    char *infile = NULL, *outfile = NULL, *rctfile = NULL, *inrand = NULL;
    char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *recipfile =
        NULL;
    char *to = NULL, *from = NULL, *subject = NULL, *prog;
    cms_key_param *key_first = NULL, *key_param = NULL;
    int flags = CMS_DETACHED, noout = 0, print = 0, keyidx = -1, vpmtouched =
        0;
    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
    int need_rand = 0, operation = 0, ret = 1, rr_print = 0, rr_allorfirst =
        -1;
    int verify_retcode = 0, rctformat = FORMAT_SMIME, keyform = FORMAT_PEM;
    size_t secret_keylen = 0, secret_keyidlen = 0;
    unsigned char *pwri_pass = NULL, *pwri_tmp = NULL;
    unsigned char *secret_key = NULL, *secret_keyid = NULL;
    long ltmp;
    const char *mime_eol = "\n";
    OPTION_CHOICE o;

    if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
        return 1;

    prog = opt_init(argc, argv, cms_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_EOF:
        case OPT_ERR:
 opthelp:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        case OPT_HELP:
            opt_help(cms_options);
            ret = 0;
            goto end;
        case OPT_INFORM:
            if (!opt_format(opt_arg(), OPT_FMT_PDS, &informat))
                goto opthelp;
            break;
        case OPT_OUTFORM:
            if (!opt_format(opt_arg(), OPT_FMT_PDS, &outformat))
                goto opthelp;
            break;
        case OPT_OUT:
            outfile = opt_arg();
            break;
        case OPT_ENCRYPT:
            operation = SMIME_ENCRYPT;
            break;
        case OPT_DECRYPT:
            operation = SMIME_DECRYPT;
            break;
        case OPT_SIGN:
            operation = SMIME_SIGN;
            break;
        case OPT_SIGN_RECEIPT:
            operation = SMIME_SIGN_RECEIPT;
            break;
        case OPT_RESIGN:
            operation = SMIME_RESIGN;
            break;
        case OPT_VERIFY:
            operation = SMIME_VERIFY;
            break;
        case OPT_VERIFY_RETCODE:
            verify_retcode = 1;
            break;
        case OPT_VERIFY_RECEIPT:
            operation = SMIME_VERIFY_RECEIPT;
            rctfile = opt_arg();
            break;
        case OPT_CMSOUT:
            operation = SMIME_CMSOUT;
            break;
        case OPT_DATA_OUT:
            operation = SMIME_DATAOUT;
            break;
        case OPT_DATA_CREATE:
            operation = SMIME_DATA_CREATE;
            break;
        case OPT_DIGEST_VERIFY:
            operation = SMIME_DIGEST_VERIFY;
            break;
        case OPT_DIGEST_CREATE:
            operation = SMIME_DIGEST_CREATE;
            break;
        case OPT_COMPRESS:
            operation = SMIME_COMPRESS;
            break;
        case OPT_UNCOMPRESS:
            operation = SMIME_UNCOMPRESS;
            break;
        case OPT_ED_DECRYPT:
            operation = SMIME_ENCRYPTED_DECRYPT;
            break;
        case OPT_ED_ENCRYPT:
            operation = SMIME_ENCRYPTED_ENCRYPT;
            break;
        case OPT_DEBUG_DECRYPT:
            flags |= CMS_DEBUG_DECRYPT;
            break;
        case OPT_TEXT:
            flags |= CMS_TEXT;
            break;
        case OPT_ASCIICRLF:
            flags |= CMS_ASCIICRLF;
            break;
        case OPT_NOINTERN:
            flags |= CMS_NOINTERN;
            break;
        case OPT_NOVERIFY:
            flags |= CMS_NO_SIGNER_CERT_VERIFY;
            break;
        case OPT_NOCERTS:
            flags |= CMS_NOCERTS;
            break;
        case OPT_NOATTR:
            flags |= CMS_NOATTR;
            break;
        case OPT_NODETACH:
            flags &= ~CMS_DETACHED;
            break;
        case OPT_NOSMIMECAP:
            flags |= CMS_NOSMIMECAP;
            break;
        case OPT_BINARY:
            flags |= CMS_BINARY;
            break;
        case OPT_KEYID:
            flags |= CMS_USE_KEYID;
            break;
        case OPT_NOSIGS:
            flags |= CMS_NOSIGS;
            break;
        case OPT_NO_CONTENT_VERIFY:
            flags |= CMS_NO_CONTENT_VERIFY;
            break;
        case OPT_NO_ATTR_VERIFY:
            flags |= CMS_NO_ATTR_VERIFY;
            break;
        case OPT_INDEF:
            flags |= CMS_STREAM;
            break;
        case OPT_NOINDEF:
            flags &= ~CMS_STREAM;
            break;
        case OPT_NOOLDMIME:
            flags |= CMS_NOOLDMIMETYPE;
            break;
        case OPT_CRLFEOL:
            mime_eol = "\r\n";
            flags |= CMS_CRLFEOL;
            break;
        case OPT_NOOUT:
            noout = 1;
            break;
        case OPT_RR_PRINT:
            rr_print = 1;
            break;
        case OPT_RR_ALL:
            rr_allorfirst = 0;
            break;
        case OPT_RR_FIRST:
            rr_allorfirst = 1;
            break;
        case OPT_RCTFORM:
            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)
                if (!opt_format(opt_arg(),
                                OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat))
                    goto opthelp;
            break;
        case OPT_CERTFILE:
            certfile = opt_arg();
            break;
        case OPT_CAFILE:
            CAfile = opt_arg();
            break;
        case OPT_CAPATH:
            CApath = opt_arg();
            break;
        case OPT_NOCAFILE:
            noCAfile = 1;
            break;
        case OPT_NOCAPATH:
            noCApath = 1;
            break;
        case OPT_IN:
            infile = opt_arg();
            break;
        case OPT_CONTENT:
            contfile = opt_arg();
            break;
        case OPT_RR_FROM:
            if (rr_from == NULL
                && (rr_from = sk_OPENSSL_STRING_new_null()) == NULL)
                goto end;
            sk_OPENSSL_STRING_push(rr_from, opt_arg());
            break;
        case OPT_RR_TO:
            if (rr_to == NULL
                && (rr_to = sk_OPENSSL_STRING_new_null()) == NULL)
                goto end;
            sk_OPENSSL_STRING_push(rr_to, opt_arg());
            break;
        case OPT_PRINT:
            noout = print = 1;
            break;
        case OPT_SECRETKEY:
            secret_key = OPENSSL_hexstr2buf(opt_arg(), &ltmp);
            if (secret_key == NULL) {
                BIO_printf(bio_err, "Invalid key %s\n", opt_arg());
                goto end;
            }
            secret_keylen = (size_t)ltmp;
            break;
        case OPT_SECRETKEYID:
            secret_keyid = OPENSSL_hexstr2buf(opt_arg(), &ltmp);
            if (secret_keyid == NULL) {
                BIO_printf(bio_err, "Invalid id %s\n", opt_arg());
                goto opthelp;
            }
            secret_keyidlen = (size_t)ltmp;
            break;
        case OPT_PWRI_PASSWORD:
            pwri_pass = (unsigned char *)opt_arg();
            break;
        case OPT_ECONTENT_TYPE:
            econtent_type = OBJ_txt2obj(opt_arg(), 0);
            if (econtent_type == NULL) {
                BIO_printf(bio_err, "Invalid OID %s\n", opt_arg());
                goto opthelp;
            }
            break;
        case OPT_RAND:
            inrand = opt_arg();
            need_rand = 1;
            break;
        case OPT_ENGINE:
            e = setup_engine(opt_arg(), 0);
            break;
        case OPT_PASSIN:
            passinarg = opt_arg();
            break;
        case OPT_TO:
            to = opt_arg();
            break;
        case OPT_FROM:
            from = opt_arg();
            break;
        case OPT_SUBJECT:
            subject = opt_arg();
            break;
        case OPT_CERTSOUT:
            certsoutfile = opt_arg();
            break;
        case OPT_MD:
            if (!opt_md(opt_arg(), &sign_md))
                goto end;
            break;
        case OPT_SIGNER:
            /* If previous -signer argument add signer to list */
            if (signerfile) {
                if (sksigners == NULL
                    && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
                    goto end;
                sk_OPENSSL_STRING_push(sksigners, signerfile);
                if (keyfile == NULL)
                    keyfile = signerfile;
                if (skkeys == NULL
                    && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
                    goto end;
                sk_OPENSSL_STRING_push(skkeys, keyfile);
                keyfile = NULL;
            }
            signerfile = opt_arg();
            break;
        case OPT_INKEY:
            /* If previous -inkey argument add signer to list */
            if (keyfile) {
                if (signerfile == NULL) {
                    BIO_puts(bio_err, "Illegal -inkey without -signer\n");
                    goto end;
                }
                if (sksigners == NULL
                    && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
                    goto end;
                sk_OPENSSL_STRING_push(sksigners, signerfile);
                signerfile = NULL;
                if (skkeys == NULL
                    && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
                    goto end;
                sk_OPENSSL_STRING_push(skkeys, keyfile);
            }
            keyfile = opt_arg();
            break;
        case OPT_KEYFORM:
            if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
                goto opthelp;
            break;
        case OPT_RECIP:
            if (operation == SMIME_ENCRYPT) {
                if (encerts == NULL && (encerts = sk_X509_new_null()) == NULL)
                    goto end;
                cert = load_cert(opt_arg(), FORMAT_PEM,
                                 "recipient certificate file");
                if (cert == NULL)
                    goto end;
                sk_X509_push(encerts, cert);
                cert = NULL;
            } else
                recipfile = opt_arg();
            break;
        case OPT_CIPHER:
            if (!opt_cipher(opt_unknown(), &cipher))
                goto end;
            break;
        case OPT_KEYOPT:
            keyidx = -1;
            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 opthelp;
            }
            if (key_param == NULL || key_param->idx != keyidx) {
                cms_key_param *nparam;
                nparam = app_malloc(sizeof(*nparam), "key param buffer");
                nparam->idx = keyidx;
                if ((nparam->param = sk_OPENSSL_STRING_new_null()) == NULL)
                    goto end;
                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, opt_arg());
            break;
        case OPT_V_CASES:
            if (!opt_verify(o, vpm))
                goto end;
            vpmtouched++;
            break;
        case OPT_3DES_WRAP:
# ifndef OPENSSL_NO_DES
            wrap_cipher = EVP_des_ede3_wrap();
# endif
            break;
        case OPT_AES128_WRAP:
            wrap_cipher = EVP_aes_128_wrap();
            break;
        case OPT_AES192_WRAP:
            wrap_cipher = EVP_aes_192_wrap();
            break;
        case OPT_AES256_WRAP:
            wrap_cipher = EVP_aes_256_wrap();
            break;
        }
    }
    argc = opt_num_rest();
    argv = opt_rest();

    if (((rr_allorfirst != -1) || rr_from) && !rr_to) {
        BIO_puts(bio_err, "No Signed Receipts Recipients\n");
        goto opthelp;
    }

    if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) {
        BIO_puts(bio_err, "Signed receipts only allowed with -sign\n");
        goto opthelp;
    }
    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
        goto opthelp;
    }

    if (operation & SMIME_SIGNERS) {
        if (keyfile && !signerfile) {
            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
            goto opthelp;
        }
        /* Check to see if any final signer needs to be appended */
        if (signerfile) {
            if (!sksigners
                && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
                goto end;
            sk_OPENSSL_STRING_push(sksigners, signerfile);
            if (!skkeys && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
                goto end;
            if (!keyfile)
                keyfile = signerfile;
            sk_OPENSSL_STRING_push(skkeys, keyfile);
        }
        if (!sksigners) {
            BIO_printf(bio_err, "No signer certificate specified\n");
            goto opthelp;
        }
        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");
            goto opthelp;
        }
    } else if (operation == SMIME_ENCRYPT) {
        if (*argv == NULL && !secret_key && !pwri_pass && !encerts) {
            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
            goto opthelp;
        }
        need_rand = 1;
    } else if (!operation)
        goto opthelp;

    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
        BIO_printf(bio_err, "Error getting password\n");
        goto end;
    }

    if (need_rand) {
        app_RAND_load_file(NULL, (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 (flags & CMS_BINARY)
            outformat = FORMAT_BINARY;
    }

    if (!(operation & SMIME_IP)) {
        if (flags & CMS_BINARY)
            informat = FORMAT_BINARY;
    }

    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 (*argv && !encerts)
            if ((encerts = sk_X509_new_null()) == NULL)
                goto end;
        while (*argv) {
            if ((cert = load_cert(*argv, FORMAT_PEM,
                                  "recipient certificate file")) == NULL)
                goto end;
            sk_X509_push(encerts, cert);
            cert = NULL;
            argv++;
        }
    }

    if (certfile) {
        if (!load_certs(certfile, &other, FORMAT_PEM, NULL,
                        "certificate file")) {
            ERR_print_errors(bio_err);
            goto end;
        }
    }

    if (recipfile && (operation == SMIME_DECRYPT)) {
        if ((recip = load_cert(recipfile, FORMAT_PEM,
                               "recipient certificate file")) == NULL) {
            ERR_print_errors(bio_err);
            goto end;
        }
    }

    if (operation == SMIME_SIGN_RECEIPT) {
        if ((signer = load_cert(signerfile, FORMAT_PEM,
                                "receipt signer certificate file")) == NULL) {
            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(keyfile, keyform, 0, passin, e, "signing key file");
        if (!key)
            goto end;
    }

    in = bio_open_default(infile, 'r', informat);
    if (in == NULL)
        goto end;

    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")) == NULL) {
                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)) == NULL) {
            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;
        }
    }

    out = bio_open_default(outfile, 'w', outformat);
    if (out == NULL)
        goto end;

    if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) {
        if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
            goto end;
        X509_STORE_set_verify_cb(store, cms_cb);
        if (vpmtouched)
            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 *)OPENSSL_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(signerfile, FORMAT_PEM, "signer certificate");
            if (!signer)
                goto end;
            key = load_key(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(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%s", to, mime_eol);
            if (from)
                BIO_printf(out, "From: %s%s", from, mime_eol);
            if (subject)
                BIO_printf(out, "Subject: %s%s", subject, mime_eol);
            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);
    sk_X509_pop_free(encerts, X509_free);
    sk_X509_pop_free(other, X509_free);
    X509_VERIFY_PARAM_free(vpm);
    sk_OPENSSL_STRING_free(sksigners);
    sk_OPENSSL_STRING_free(skkeys);
    OPENSSL_free(secret_key);
    OPENSSL_free(secret_keyid);
    OPENSSL_free(pwri_tmp);
    ASN1_OBJECT_free(econtent_type);
    CMS_ReceiptRequest_free(rr);
    sk_OPENSSL_STRING_free(rr_to);
    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);
    OPENSSL_free(passin);
    return (ret);
}
示例#8
0
int
main( int argc, char * argv [] )
{
    enum
    {
        ARG_IN_DATA_FILE_IX          = 1,
        ARG_OUT_SIG_FILE_IX          = 2,
        ARG_KEY_FILE_IX              = 3,
        ARG_KEY_PASS_IX              = 4,
        ARG_KEY_CERT_FILE_IX         = 5,
        ARG_FIRST_EXTRA_CERT_FILE_IX = 6
    };

    int exit_code = 0;

    /* -------------------------------------------------------------- */
    /* initialization */

    exit_code = 1;

    SSL_load_error_strings();
    SSL_library_init();

    /* -------------------------------------------------------------- */
    /* command-line processing */

    exit_code = 2;

    if ( argc < 6 )
    {
        fprintf( stderr, "usage: %s IN_DATA_FILE OUT_SIG_FILE"
                 " KEY_FILE KEY_PASS KEY_CERT EXTRA_CERTS...\n", argv[0] );
        return 1;
    }

    BIO * in_data_file = BIO_new_file( argv[ ARG_IN_DATA_FILE_IX ], "rb" );
    if ( ! in_data_file )
    {
        perror( argv[ ARG_IN_DATA_FILE_IX ] );
        goto end;
    }

    BIO * out_sig_file = BIO_new_file( argv[ ARG_OUT_SIG_FILE_IX ], "wb" );
    if ( ! out_sig_file )
    {
        perror( argv[ ARG_OUT_SIG_FILE_IX ] );
        goto free_in_data_file;
    }

    BIO * key_file = BIO_new_file( argv[ ARG_KEY_FILE_IX ], "rb" );
    if ( ! key_file )
    {
        perror( argv[ ARG_KEY_FILE_IX ] );
        goto free_out_sig_file;
    }

    char * pw = argv[ ARG_KEY_PASS_IX ];
    /* fprintf( stderr, "pw='%s'\n", pw ); */

    BIO * key_cert_file = BIO_new_file( argv[ ARG_KEY_CERT_FILE_IX ], "rb" );
    if ( ! key_cert_file )
    {
        perror( argv[ ARG_KEY_CERT_FILE_IX ] );
        goto free_key_file;
    }

    BIO * * extra_cert_files = NULL;
    int num_extra_cert_files = argc - ARG_FIRST_EXTRA_CERT_FILE_IX;
    if ( num_extra_cert_files > 0 )
    {
        extra_cert_files = calloc( num_extra_cert_files, sizeof( BIO * ) );
        if ( ! extra_cert_files )
        {
            perror( "extra_cert_files" );
            goto free_key_cert_file;
        }

        for ( int i = 0; i < num_extra_cert_files; ++i )
        {
            extra_cert_files[i] =
              BIO_new_file( argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ], "rb" );
            if ( ! extra_cert_files[i] )
            {
                perror( argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] );
                goto free_key_cert_file;
            }
        }
    }

    /* -------------------------------------------------------------- */
    /* processing */

    exit_code = 3;

#define FAIL( msg, dest )                      \
    do {                                       \
        fprintf( stderr, "error: " msg "\n" ); \
        goto dest;                             \
    } while ( 0 )

    EVP_PKEY * key = PEM_read_bio_PrivateKey( key_file, NULL, NULL, pw );
    if ( ! key )
        FAIL( "reading private key", free_extra_cert_files );

    X509 * key_cert = PEM_read_bio_X509( key_cert_file, NULL, NULL, NULL );
    if ( ! key_cert )
        FAIL( "reading signing cert", free_key );

    STACK_OF(X509) * extra_certs = NULL;
    if ( num_extra_cert_files > 0 )
    {
        int success = 1;

        extra_certs = sk_X509_new_null();
        if ( ! extra_certs )
            FAIL( "allocating stack for extra certs", free_key_cert );

        for ( int i = 0; i < num_extra_cert_files; ++i )
        {
            X509 * tmp = PEM_read_bio_X509( extra_cert_files[i],
                                            NULL, NULL, NULL );
            if ( ! tmp )
            {
                fprintf( stderr, "error reading '%s'\n",
                         argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] );
                success = 0;
                break;
            }

            if ( ! sk_X509_push( extra_certs, tmp ) )
            {
                fprintf( stderr, "error pushing '%s'\n",
                         argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] );
                success = 0;
                X509_free( tmp );
                break;
            }
        }

        if ( ! success )
            FAIL( "could not read extra certs", free_extra_certs );
    }

    CMS_ContentInfo * ci = CMS_sign( key_cert, key, extra_certs, in_data_file,
                                     CMS_DETACHED | CMS_BINARY );

    /* if ( 1 != PEM_write_bio_CMS( out_sig_file, ci ) )
           FAIL( "could not write signature in PEM", free_ci ); */

    if ( 1 != i2d_CMS_bio( out_sig_file, ci ) )
           FAIL( "could not write signature in DER", free_ci );

    /* -------------------------------------------------------------- */
    /* success */

    exit_code = 0;

    /* -------------------------------------------------------------- */
    /* cleanup */

free_ci:
    CMS_ContentInfo_free( ci );

free_extra_certs:
    sk_X509_pop_free( extra_certs, &X509_free );

free_key_cert:
    X509_free( key_cert );

free_key:
    EVP_PKEY_free( key );

free_extra_cert_files:
    for ( int i = 0; i < num_extra_cert_files; ++i )
        BIO_vfree( extra_cert_files[ i ] );
    free( extra_cert_files );

free_key_cert_file:
    BIO_vfree( key_cert_file );

free_key_file:
    BIO_vfree( key_file );

free_out_sig_file:
    BIO_vfree( out_sig_file );

free_in_data_file:
    BIO_vfree( in_data_file );

    ERR_print_errors_fp( stderr );

    ERR_remove_state( /* pid= */ 0 );
    ENGINE_cleanup();
    CONF_modules_unload( /* all= */ 1 );
    EVP_cleanup();
    ERR_free_strings();
    CRYPTO_cleanup_all_ex_data();

end:
    return exit_code;
}
示例#9
0
文件: signature.c 项目: ukleinek/rauc
GBytes *cms_sign(GBytes *content, const gchar *certfile, const gchar *keyfile, gchar **interfiles, GError **error)
{
	GError *ierror = NULL;
	BIO *incontent = BIO_new_mem_buf((void *)g_bytes_get_data(content, NULL),
			g_bytes_get_size(content));
	BIO *outsig = BIO_new(BIO_s_mem());
	X509 *signcert = NULL;
	EVP_PKEY *pkey = NULL;
	STACK_OF(X509) *intercerts = NULL;
	CMS_ContentInfo *cms = NULL;
	GBytes *res = NULL;
	int flags = CMS_DETACHED | CMS_BINARY;

	g_return_val_if_fail(content != NULL, NULL);
	g_return_val_if_fail(certfile != NULL, NULL);
	g_return_val_if_fail(keyfile != NULL, NULL);
	g_return_val_if_fail(error == NULL || *error == NULL, NULL);

	signcert = load_cert(certfile, &ierror);
	if (signcert == NULL) {
		g_propagate_error(error, ierror);
		goto out;
	}

	pkey = load_key(keyfile, &ierror);
	if (pkey == NULL) {
		g_propagate_error(error, ierror);
		goto out;
	}

	intercerts = sk_X509_new_null();

	for (gchar **intercertpath = interfiles; intercertpath && *intercertpath != NULL; intercertpath++) {

		X509 *intercert = load_cert(*intercertpath, &ierror);
		if (intercert == NULL) {
			g_propagate_error(error, ierror);
			goto out;
		}

		sk_X509_push(intercerts, intercert);
	}

	cms = CMS_sign(signcert, pkey, intercerts, incontent, flags);
	if (cms == NULL) {
		unsigned long err;
		const gchar *data;
		int errflags;
		err = ERR_get_error_line_data(NULL, NULL, &data, &errflags);
		g_set_error(
				error,
				R_SIGNATURE_ERROR,
				R_SIGNATURE_ERROR_INVALID,
				"failed to create signature: %s", (errflags & ERR_TXT_STRING) ? data : ERR_error_string(err, NULL));
		goto out;
	}
	if (!i2d_CMS_bio(outsig, cms)) {
		g_set_error_literal(
				error,
				R_SIGNATURE_ERROR,
				R_SIGNATURE_ERROR_SERIALIZE_SIG,
				"failed to serialize signature");
		goto out;
	}

	res = bytes_from_bio(outsig);

	if (!res) {
		g_set_error_literal(
				error,
				R_SIGNATURE_ERROR,
				R_SIGNATURE_ERROR_UNKNOWN,
				"Read zero bytes");
		goto out;
	}

	/* keyring was given, perform verification to obtain trust chain */
	if (r_context()->config->keyring_path) {
		g_autoptr(CMS_ContentInfo) vcms = NULL;
		g_autoptr(X509_STORE) store = NULL;
		STACK_OF(X509) *verified_chain = NULL;

		g_message("Keyring given, doing signature verification");
		if (!cms_verify(content, res, &vcms, &store, &ierror)) {
			g_propagate_error(error, ierror);
			res = NULL;
			goto out;
		}

		if (!cms_get_cert_chain(vcms, store, &verified_chain, &ierror)) {
			g_propagate_error(error, ierror);
			res = NULL;
			goto out;
		}

		for (int i = 0; i < sk_X509_num(verified_chain); i++) {
			const ASN1_TIME *expiry_time;
			struct tm *next_month;
			time_t now;
			time_t comp;
			time(&now);

			next_month = gmtime(&now);
			next_month->tm_mon += 1;
			if (next_month->tm_mon == 12)
				next_month->tm_mon = 0;
			comp = timegm(next_month);

			expiry_time = X509_get0_notAfter(sk_X509_value(verified_chain, i));

			/* Check if expiry time is within last month */
			if (X509_cmp_current_time(expiry_time) == 1 && X509_cmp_time(expiry_time, &comp) == -1) {
				char buf[BUFSIZ];
				X509_NAME_oneline(X509_get_subject_name(sk_X509_value(verified_chain, i)),
						buf, sizeof buf);
				g_warning("Certificate %d (%s) will exipre in less than a month!", i + 1, buf);
			}
		}

		sk_X509_pop_free(verified_chain, X509_free);
	} else {
		g_message("No keyring given, skipping signature verification");
	}
out:
	ERR_print_errors_fp(stdout);
	BIO_free_all(incontent);
	BIO_free_all(outsig);
	return res;
}