BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec) { BIO *b; EVP_CIPHER_CTX *ctx; const EVP_CIPHER *ciph; X509_ALGOR *calg = ec->contentEncryptionAlgorithm; unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; unsigned char *tkey = NULL; size_t tkeylen = 0; int ok = 0; int enc, keep_key = 0; enc = ec->cipher ? 1 : 0; b = BIO_new(BIO_f_cipher()); if (b == NULL) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); return NULL; } BIO_get_cipher_ctx(b, &ctx); if (enc) { ciph = ec->cipher; /* * If not keeping key set cipher to NULL so subsequent calls decrypt. */ if (ec->key) ec->cipher = NULL; } else { ciph = EVP_get_cipherbyobj(calg->algorithm); if (!ciph) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER); goto err; } } if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_INITIALISATION_ERROR); goto err; } if (enc) { int ivlen; calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); /* Generate a random IV if we need one */ ivlen = EVP_CIPHER_CTX_iv_length(ctx); if (ivlen > 0) { if (RAND_bytes(iv, ivlen) <= 0) goto err; piv = iv; } } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } tkeylen = EVP_CIPHER_CTX_key_length(ctx); /* Generate random session key */ if (!enc || !ec->key) { tkey = OPENSSL_malloc(tkeylen); if (tkey == NULL) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0) goto err; } if (!ec->key) { ec->key = tkey; ec->keylen = tkeylen; tkey = NULL; if (enc) keep_key = 1; else ERR_clear_error(); } if (ec->keylen != tkeylen) { /* If necessary set key length */ if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) { /* * Only reveal failure if debugging so we don't leak information * which may be useful in MMA. */ if (enc || ec->debug) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_INVALID_KEY_LENGTH); goto err; } else { /* Use random key */ OPENSSL_clear_free(ec->key, ec->keylen); ec->key = tkey; ec->keylen = tkeylen; tkey = NULL; ERR_clear_error(); } } } if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_INITIALISATION_ERROR); goto err; } if (enc) { calg->parameter = ASN1_TYPE_new(); if (calg->parameter == NULL) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) { CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } /* If parameter type not set omit parameter */ if (calg->parameter->type == V_ASN1_UNDEF) { ASN1_TYPE_free(calg->parameter); calg->parameter = NULL; } } ok = 1; err: if (!keep_key || !ok) { OPENSSL_clear_free(ec->key, ec->keylen); ec->key = NULL; } OPENSSL_clear_free(tkey, tkeylen); if (ok) return b; BIO_free(b); return NULL; }
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) { CMS_SignedData *sd; CMS_SignerInfo *si = NULL; X509_ALGOR *alg; int i, type; if (!X509_check_private_key(signer, pk)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); return NULL; } sd = cms_signed_data_init(cms); if (!sd) goto err; si = M_ASN1_new_of(CMS_SignerInfo); if (!si) goto merr; /* Call for side-effect of computing hash and caching extensions */ X509_check_purpose(signer, -1, -1); X509_up_ref(signer); EVP_PKEY_up_ref(pk); si->pkey = pk; si->signer = signer; si->mctx = EVP_MD_CTX_new(); si->pctx = NULL; if (si->mctx == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); goto err; } if (flags & CMS_USE_KEYID) { si->version = 3; if (sd->version < 3) sd->version = 3; type = CMS_SIGNERINFO_KEYIDENTIFIER; } else { type = CMS_SIGNERINFO_ISSUER_SERIAL; si->version = 1; } if (!cms_set1_SignerIdentifier(si->sid, signer, type)) goto err; if (md == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) goto err; md = EVP_get_digestbynid(def_nid); if (md == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST); goto err; } } if (!md) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET); goto err; } X509_ALGOR_set_md(si->digestAlgorithm, md); /* See if digest is present in digestAlgorithms */ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) { const ASN1_OBJECT *aoid; alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); X509_ALGOR_get0(&aoid, NULL, NULL, alg); if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) break; } if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) { alg = X509_ALGOR_new(); if (alg == NULL) goto merr; X509_ALGOR_set_md(alg, md); if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) { X509_ALGOR_free(alg); goto merr; } } if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) goto err; if (!(flags & CMS_NOATTR)) { /* * Initialize signed attributes structure so other attributes * such as signing time etc are added later even if we add none here. */ if (!si->signedAttrs) { si->signedAttrs = sk_X509_ATTRIBUTE_new_null(); if (!si->signedAttrs) goto merr; } if (!(flags & CMS_NOSMIMECAP)) { STACK_OF(X509_ALGOR) *smcap = NULL; i = CMS_add_standard_smimecap(&smcap); if (i) i = CMS_add_smimecap(si, smcap); sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); if (!i) goto merr; } if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; if (!(flags & (CMS_PARTIAL | CMS_KEY_PARAM)) && !CMS_SignerInfo_sign(si)) goto err; } } if (!(flags & CMS_NOCERTS)) { /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) goto merr; } if (flags & CMS_KEY_PARAM) { if (flags & CMS_NOATTR) { si->pctx = EVP_PKEY_CTX_new(si->pkey, NULL); if (si->pctx == NULL) goto err; if (EVP_PKEY_sign_init(si->pctx) <= 0) goto err; if (EVP_PKEY_CTX_set_signature_md(si->pctx, md) <= 0) goto err; } else if (EVP_DigestSignInit(si->mctx, &si->pctx, md, NULL, pk) <= 0) goto err; } if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) goto merr; return si; merr: CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); err: M_ASN1_free_of(si, CMS_SignerInfo); return NULL; }
static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) { CMS_EncryptedContentInfo *ec; CMS_KEKRecipientInfo *kekri; AES_KEY actx; unsigned char *ukey = NULL; int ukeylen; int r = 0, wrap_nid; ec = cms->d.envelopedData->encryptedContentInfo; kekri = ri->d.kekri; if (!kekri->key) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY); return 0; } wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm); if (aes_wrap_keylen(wrap_nid) != kekri->keylen) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_INVALID_KEY_LENGTH); return 0; } /* If encrypted key length is invalid don't bother */ if (kekri->encryptedKey->length < 16) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH); goto err; } if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_ERROR_SETTING_KEY); goto err; } ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); if (!ukey) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE); goto err; } ukeylen = AES_unwrap_key(&actx, NULL, ukey, kekri->encryptedKey->data, kekri->encryptedKey->length); if (ukeylen <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR); goto err; } ec->key = ukey; ec->keylen = ukeylen; r = 1; err: if (!r && ukey) OPENSSL_free(ukey); OPENSSL_cleanse(&actx, sizeof(actx)); return r; }
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; STACK_OF(CMS_RecipientInfo) *rinfos; CMS_RecipientInfo *ri; int i, r, ok = 0; BIO *ret; /* Get BIO first to set up key */ ec = cms->d.envelopedData->encryptedContentInfo; ret = cms_EncryptedContent_init_bio(ec); /* If error or no cipher end of processing */ if (!ret || !ec->cipher) return ret; /* Now encrypt content key according to each RecipientInfo type */ rinfos = cms->d.envelopedData->recipientInfos; for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { ri = sk_CMS_RecipientInfo_value(rinfos, i); switch (ri->type) { case CMS_RECIPINFO_TRANS: r = cms_RecipientInfo_ktri_encrypt(cms, ri); break; case CMS_RECIPINFO_KEK: r = cms_RecipientInfo_kekri_encrypt(cms, ri); break; case CMS_RECIPINFO_PASS: r = cms_RecipientInfo_pwri_crypt(cms, ri, 1); break; default: CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, CMS_R_UNSUPPORTED_RECIPIENT_TYPE); goto err; } if (r <= 0) { CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, CMS_R_ERROR_SETTING_RECIPIENTINFO); goto err; } } ok = 1; err: ec->cipher = NULL; if (ec->key) { OPENSSL_cleanse(ec->key, ec->keylen); OPENSSL_free(ec->key); ec->key = NULL; ec->keylen = 0; } if (ok) return ret; BIO_free(ret); return NULL; }
static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) { CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; EVP_PKEY_CTX *pctx = NULL; unsigned char *ek = NULL; size_t eklen; int ret = 0; CMS_EncryptedContentInfo *ec; ec = cms->d.envelopedData->encryptedContentInfo; if (ktri->pkey == NULL) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY); return 0; } pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); if (!pctx) return 0; if (EVP_PKEY_decrypt_init(pctx) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR); goto err; } if (EVP_PKEY_decrypt(pctx, NULL, &eklen, ktri->encryptedKey->data, ktri->encryptedKey->length) <= 0) goto err; ek = OPENSSL_malloc(eklen); if (ek == NULL) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_PKEY_decrypt(pctx, ek, &eklen, ktri->encryptedKey->data, ktri->encryptedKey->length) <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); goto err; } ret = 1; if (ec->key) { OPENSSL_cleanse(ec->key, ec->keylen); OPENSSL_free(ec->key); } ec->key = ek; ec->keylen = eklen; err: if (pctx) EVP_PKEY_CTX_free(pctx); if (!ret && ek) OPENSSL_free(ek); return ret; }
CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, unsigned char *key, size_t keylen, unsigned char *id, size_t idlen, ASN1_GENERALIZEDTIME *date, ASN1_OBJECT *otherTypeId, ASN1_TYPE *otherType) { CMS_RecipientInfo *ri = NULL; CMS_EnvelopedData *env; CMS_KEKRecipientInfo *kekri; env = cms_get0_enveloped(cms); if (!env) goto err; if (nid == NID_undef) { switch (keylen) { case 16: nid = NID_id_aes128_wrap; break; case 24: nid = NID_id_aes192_wrap; break; case 32: nid = NID_id_aes256_wrap; break; default: CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); goto err; } } else { size_t exp_keylen = aes_wrap_keylen(nid); if (!exp_keylen) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_UNSUPPORTED_KEK_ALGORITHM); goto err; } if (keylen != exp_keylen) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); goto err; } } /* Initialize recipient info */ ri = M_ASN1_new_of(CMS_RecipientInfo); if (!ri) goto merr; ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo); if (!ri->d.kekri) goto merr; ri->type = CMS_RECIPINFO_KEK; kekri = ri->d.kekri; if (otherTypeId) { kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute); if (kekri->kekid->other == NULL) goto merr; } if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) goto merr; /* After this point no calls can fail */ kekri->version = 4; kekri->key = key; kekri->keylen = keylen; ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen); kekri->kekid->date = date; if (kekri->kekid->other) { kekri->kekid->other->keyAttrId = otherTypeId; kekri->kekid->other->keyAttr = otherType; } X509_ALGOR_set0(kekri->keyEncryptionAlgorithm, OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL); return ri; merr: CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE); err: if (ri) M_ASN1_free_of(ri, CMS_RecipientInfo); return NULL; }
CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags) { CMS_RecipientInfo *ri = NULL; CMS_KeyTransRecipientInfo *ktri; CMS_EnvelopedData *env; EVP_PKEY *pk = NULL; int i, type; env = cms_get0_enveloped(cms); if (!env) goto err; /* Initialize recipient info */ ri = M_ASN1_new_of(CMS_RecipientInfo); if (!ri) goto merr; /* Initialize and add key transport recipient info */ ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); if (!ri->d.ktri) goto merr; ri->type = CMS_RECIPINFO_TRANS; ktri = ri->d.ktri; X509_check_purpose(recip, -1, -1); pk = X509_get_pubkey(recip); if (!pk) { CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY); goto err; } CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509); ktri->pkey = pk; ktri->recip = recip; if (flags & CMS_USE_KEYID) { ktri->version = 2; if (env->version < 2) env->version = 2; type = CMS_RECIPINFO_KEYIDENTIFIER; } else { ktri->version = 0; type = CMS_RECIPINFO_ISSUER_SERIAL; } /* Not a typo: RecipientIdentifier and SignerIdentifier are the * same structure. */ if (!cms_set1_SignerIdentifier(ktri->rid, recip, type)) goto err; if (pk->ameth && pk->ameth->pkey_ctrl) { i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE, 0, ri); if (i == -2) { CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (i <= 0) { CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_CTRL_FAILURE); goto err; } } if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) goto merr; return ri; merr: CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE); err: if (ri) M_ASN1_free_of(ri, CMS_RecipientInfo); return NULL; }
static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) { CMS_KeyTransRecipientInfo *ktri; CMS_EncryptedContentInfo *ec; EVP_PKEY_CTX *pctx = NULL; unsigned char *ek = NULL; size_t eklen; int ret = 0; if (ri->type != CMS_RECIPINFO_TRANS) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_NOT_KEY_TRANSPORT); return 0; } ktri = ri->d.ktri; ec = cms->d.envelopedData->encryptedContentInfo; pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); if (!pctx) return 0; if (EVP_PKEY_encrypt_init(pctx) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR); goto err; } if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0) goto err; ek = OPENSSL_malloc(eklen); if (ek == NULL) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0) goto err; ASN1_STRING_set0(ktri->encryptedKey, ek, eklen); ek = NULL; ret = 1; err: if (pctx) EVP_PKEY_CTX_free(pctx); if (ek) OPENSSL_free(ek); return ret; }
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) { CMS_SignedData *sd; CMS_SignerInfo *si = NULL; X509_ALGOR *alg; int i, type; if(!X509_check_private_key(signer, pk)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); return NULL; } sd = cms_signed_data_init(cms); if (!sd) goto err; si = M_ASN1_new_of(CMS_SignerInfo); if (!si) goto merr; X509_check_purpose(signer, -1, -1); CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY); CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); si->pkey = pk; si->signer = signer; if (flags & CMS_USE_KEYID) { si->version = 3; if (sd->version < 3) sd->version = 3; type = CMS_SIGNERINFO_KEYIDENTIFIER; } else { type = CMS_SIGNERINFO_ISSUER_SERIAL; si->version = 1; } if (!cms_set1_SignerIdentifier(si->sid, signer, type)) goto err; if (md == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) goto err; md = EVP_get_digestbynid(def_nid); if (md == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST); goto err; } } if (!md) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET); goto err; } cms_DigestAlgorithm_set(si->digestAlgorithm, md); /* See if digest is present in digestAlgorithms */ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) { ASN1_OBJECT *aoid; alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); X509_ALGOR_get0(&aoid, NULL, NULL, alg); if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) break; } if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) { alg = X509_ALGOR_new(); if (!alg) goto merr; cms_DigestAlgorithm_set(alg, md); if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) { X509_ALGOR_free(alg); goto merr; } } if (pk->ameth && pk->ameth->pkey_ctrl) { i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN, 0, si); if (i == -2) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (i <= 0) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE); goto err; } } if (!(flags & CMS_NOATTR)) { /* Initialialize signed attributes strutucture so other * attributes such as signing time etc are added later * even if we add none here. */ if (!si->signedAttrs) { si->signedAttrs = sk_X509_ATTRIBUTE_new_null(); if (!si->signedAttrs) goto merr; } if (!(flags & CMS_NOSMIMECAP)) { STACK_OF(X509_ALGOR) *smcap = NULL; i = CMS_add_standard_smimecap(&smcap); if (i) i = CMS_add_smimecap(si, smcap); sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); if (!i) goto merr; } if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; if (!(flags & CMS_PARTIAL) && !CMS_SignerInfo_sign(si)) goto err; } } if (!(flags & CMS_NOCERTS)) { /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) goto merr; } if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) goto merr; return si; merr: CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); err: if (si) M_ASN1_free_of(si, CMS_SignerInfo); return NULL; }
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) { CMS_SignedData *sd; CMS_SignerInfo *si = NULL; X509_ALGOR *alg; int i, type; if(!X509_check_private_key(signer, pk)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); return NULL; } sd = cms_signed_data_init(cms); if (!sd) goto err; si = M_ASN1_new_of(CMS_SignerInfo); if (!si) goto merr; X509_check_purpose(signer, -1, -1); CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY); CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); si->pkey = pk; si->signer = signer; if (flags & CMS_USE_KEYID) { si->version = 3; if (sd->version < 3) sd->version = 3; type = CMS_SIGNERINFO_KEYIDENTIFIER; } else { type = CMS_SIGNERINFO_ISSUER_SERIAL; si->version = 1; } if (!cms_set1_SignerIdentifier(si->sid, signer, type)) goto err; /* Since no EVP_PKEY_METHOD in 0.9.8 hard code SHA1 as default */ if (md == NULL) md = EVP_sha1(); /* OpenSSL 0.9.8 only supports SHA1 with non-RSA keys */ if ((pk->type != EVP_PKEY_RSA) && (EVP_MD_type(md) != NID_sha1)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } cms_DigestAlgorithm_set(si->digestAlgorithm, md); /* See if digest is present in digestAlgorithms */ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) { ASN1_OBJECT *aoid; alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); X509_ALGOR_get0(&aoid, NULL, NULL, alg); if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) break; } if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) { alg = X509_ALGOR_new(); if (!alg) goto merr; cms_DigestAlgorithm_set(alg, md); if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) { X509_ALGOR_free(alg); goto merr; } } /* Since we have no EVP_PKEY_ASN1_METHOD in OpenSSL 0.9.8, * hard code algorithm parameters. */ switch (pk->type) { case EVP_PKEY_RSA: X509_ALGOR_set0(si->signatureAlgorithm, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0); break; case EVP_PKEY_DSA: X509_ALGOR_set0(si->signatureAlgorithm, OBJ_nid2obj(NID_dsaWithSHA1), V_ASN1_UNDEF, 0); break; case EVP_PKEY_EC: X509_ALGOR_set0(si->signatureAlgorithm, OBJ_nid2obj(NID_ecdsa_with_SHA1), V_ASN1_UNDEF, 0); break; default: CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (!(flags & CMS_NOATTR)) { /* Initialialize signed attributes strutucture so other * attributes such as signing time etc are added later * even if we add none here. */ if (!si->signedAttrs) { si->signedAttrs = sk_X509_ATTRIBUTE_new_null(); if (!si->signedAttrs) goto merr; } if (!(flags & CMS_NOSMIMECAP)) { STACK_OF(X509_ALGOR) *smcap = NULL; i = CMS_add_standard_smimecap(&smcap); if (i) i = CMS_add_smimecap(si, smcap); sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); if (!i) goto merr; } if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; if (!(flags & CMS_PARTIAL) && !CMS_SignerInfo_sign(si)) goto err; } } if (!(flags & CMS_NOCERTS)) { /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) goto merr; } if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) goto merr; return si; merr: CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); err: if (si) M_ASN1_free_of(si, CMS_SignerInfo); return NULL; }
CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags) { CMS_RecipientInfo *ri = NULL; CMS_KeyTransRecipientInfo *ktri; CMS_EnvelopedData *env; EVP_PKEY *pk = NULL; int type; env = cms_get0_enveloped(cms); if (!env) goto err; /* Initialize recipient info */ ri = M_ASN1_new_of(CMS_RecipientInfo); if (!ri) goto merr; /* Initialize and add key transport recipient info */ ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); if (!ri->d.ktri) goto merr; ri->type = CMS_RECIPINFO_TRANS; ktri = ri->d.ktri; X509_check_purpose(recip, -1, -1); pk = X509_get_pubkey(recip); if (!pk) { CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY); goto err; } CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509); ktri->pkey = pk; ktri->recip = recip; if (flags & CMS_USE_KEYID) { ktri->version = 2; type = CMS_RECIPINFO_KEYIDENTIFIER; } else { ktri->version = 0; type = CMS_RECIPINFO_ISSUER_SERIAL; } /* Not a typo: RecipientIdentifier and SignerIdentifier are the * same structure. */ if (!cms_set1_SignerIdentifier(ktri->rid, recip, type)) goto err; /* Since we have no EVP_PKEY_ASN1_METHOD in OpenSSL 0.9.8, * hard code algorithm parameters. */ if (pk->type == EVP_PKEY_RSA) { X509_ALGOR_set0(ktri->keyEncryptionAlgorithm, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0); } else { CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) goto merr; return ri; merr: CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE); err: if (ri) M_ASN1_free_of(ri, CMS_RecipientInfo); return NULL; }
CMS_RecipientInfo * CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid, int pbe_nid, unsigned char *pass, ssize_t passlen, const EVP_CIPHER *kekciph) { CMS_RecipientInfo *ri = NULL; CMS_EnvelopedData *env; CMS_PasswordRecipientInfo *pwri; EVP_CIPHER_CTX ctx; X509_ALGOR *encalg = NULL; unsigned char iv[EVP_MAX_IV_LENGTH]; int ivlen; env = cms_get0_enveloped(cms); if (!env) return NULL; if (wrap_nid <= 0) wrap_nid = NID_id_alg_PWRI_KEK; if (pbe_nid <= 0) pbe_nid = NID_id_pbkdf2; /* Get from enveloped data */ if (kekciph == NULL) kekciph = env->encryptedContentInfo->cipher; if (kekciph == NULL) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER); return NULL; } if (wrap_nid != NID_id_alg_PWRI_KEK) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); return NULL; } /* Setup algorithm identifier for cipher */ encalg = X509_ALGOR_new(); EVP_CIPHER_CTX_init(&ctx); if (EVP_EncryptInit_ex(&ctx, kekciph, NULL, NULL, NULL) <= 0) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB); goto err; } ivlen = EVP_CIPHER_CTX_iv_length(&ctx); if (ivlen > 0) { arc4random_buf(iv, ivlen); if (EVP_EncryptInit_ex(&ctx, NULL, NULL, NULL, iv) <= 0) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB); goto err; } encalg->parameter = ASN1_TYPE_new(); if (!encalg->parameter) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE); goto err; } if (EVP_CIPHER_param_to_asn1(&ctx, encalg->parameter) <= 0) { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } } encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(&ctx)); EVP_CIPHER_CTX_cleanup(&ctx); /* Initialize recipient info */ ri = M_ASN1_new_of(CMS_RecipientInfo); if (!ri) goto merr; ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo); if (!ri->d.pwri) goto merr; ri->type = CMS_RECIPINFO_PASS; pwri = ri->d.pwri; /* Since this is overwritten, free up empty structure already there */ X509_ALGOR_free(pwri->keyEncryptionAlgorithm); pwri->keyEncryptionAlgorithm = X509_ALGOR_new(); if (!pwri->keyEncryptionAlgorithm) goto merr; pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid); pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new(); if (!pwri->keyEncryptionAlgorithm->parameter) goto merr; if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR), &pwri->keyEncryptionAlgorithm->parameter->value.sequence)) goto merr; pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE; X509_ALGOR_free(encalg); encalg = NULL; /* Setup PBE algorithm */ pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1); if (!pwri->keyDerivationAlgorithm) goto err; CMS_RecipientInfo_set0_password(ri, pass, passlen); pwri->version = 0; if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) goto merr; return ri; merr: CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE); err: EVP_CIPHER_CTX_cleanup(&ctx); if (ri) M_ASN1_free_of(ri, CMS_RecipientInfo); if (encalg) X509_ALGOR_free(encalg); return NULL; }
int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, int en_de) { CMS_EncryptedContentInfo *ec; CMS_PasswordRecipientInfo *pwri; const unsigned char *p = NULL; int plen; int r = 0; X509_ALGOR *algtmp, *kekalg = NULL; EVP_CIPHER_CTX kekctx; const EVP_CIPHER *kekcipher; unsigned char *key = NULL; size_t keylen; ec = cms->d.envelopedData->encryptedContentInfo; pwri = ri->d.pwri; EVP_CIPHER_CTX_init(&kekctx); if (!pwri->pass) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD); return 0; } algtmp = pwri->keyEncryptionAlgorithm; if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); return 0; } if (algtmp->parameter->type == V_ASN1_SEQUENCE) { p = algtmp->parameter->value.sequence->data; plen = algtmp->parameter->value.sequence->length; kekalg = d2i_X509_ALGOR(NULL, &p, plen); } if (kekalg == NULL) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); return 0; } kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); if (!kekcipher) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNKNOWN_CIPHER); goto err; } /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ if (!EVP_CipherInit_ex(&kekctx, kekcipher, NULL, NULL, NULL, en_de)) goto err; EVP_CIPHER_CTX_set_padding(&kekctx, 0); if (EVP_CIPHER_asn1_to_param(&kekctx, kekalg->parameter) < 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } algtmp = pwri->keyDerivationAlgorithm; /* Finish password based key derivation to setup key in "ctx" */ if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass, pwri->passlen, algtmp->parameter, &kekctx, en_de) < 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB); goto err; } /* Finally wrap/unwrap the key */ if (en_de) { if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, &kekctx)) goto err; key = malloc(keylen); if (!key) goto err; if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, &kekctx)) goto err; pwri->encryptedKey->data = key; pwri->encryptedKey->length = keylen; } else { key = malloc(pwri->encryptedKey->length); if (!key) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE); goto err; } if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, pwri->encryptedKey->length, &kekctx)) { CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNWRAP_FAILURE); goto err; } ec->key = key; ec->keylen = keylen; } r = 1; err: EVP_CIPHER_CTX_cleanup(&kekctx); if (!r && key) free(key); X509_ALGOR_free(kekalg); return r; }