static LUA_FUNCTION(openssl_cipher_ctx_info) { EVP_CIPHER_CTX *ctx = CHECK_OBJECT(1, EVP_CIPHER_CTX, "openssl.evp_cipher_ctx"); lua_newtable(L); AUXILIAR_SET(L, -1, "block_size", EVP_CIPHER_CTX_block_size(ctx), integer); AUXILIAR_SET(L, -1, "key_length", EVP_CIPHER_CTX_key_length(ctx), integer); AUXILIAR_SET(L, -1, "iv_length", EVP_CIPHER_CTX_iv_length(ctx), integer); AUXILIAR_SET(L, -1, "flags", EVP_CIPHER_CTX_flags(ctx), integer); AUXILIAR_SET(L, -1, "nid", EVP_CIPHER_CTX_nid(ctx), integer); AUXILIAR_SET(L, -1, "type", EVP_CIPHER_CTX_mode(ctx), integer); AUXILIAR_SET(L, -1, "mode", EVP_CIPHER_CTX_type(ctx), integer); AUXILIAR_SETOBJECT(L, EVP_CIPHER_CTX_cipher(ctx), "openssl.evp_cipher", -1, "cipher"); return 1; }
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) { 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) { 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 (piv) { calg->parameter = ASN1_TYPE_new(); if (!calg->parameter) { 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; } } ok = 1; err: if (!keep_key) { OPENSSL_clear_free(ec->key, ec->keylen); ec->key = NULL; } OPENSSL_clear_free(tkey, tkeylen); if (ok) return b; BIO_free(b); return NULL; }
static int dh_cms_encrypt(CMS_RecipientInfo *ri) { EVP_PKEY_CTX *pctx; EVP_PKEY *pkey; EVP_CIPHER_CTX *ctx; int keylen; X509_ALGOR *talg, *wrap_alg = NULL; ASN1_OBJECT *aoid; ASN1_BIT_STRING *pubkey; ASN1_STRING *wrap_str; ASN1_OCTET_STRING *ukm; unsigned char *penc = NULL, *dukm = NULL; int penclen; size_t dukmlen = 0; int rv = 0; int kdf_type, wrap_nid; const EVP_MD *kdf_md; pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!pctx) return 0; /* Get ephemeral key */ pkey = EVP_PKEY_CTX_get0_pkey(pctx); if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, NULL, NULL, NULL)) goto err; X509_ALGOR_get0(&aoid, NULL, NULL, talg); /* Is everything uninitialised? */ if (aoid == OBJ_nid2obj(NID_undef)) { ASN1_INTEGER *pubk; pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL); if (!pubk) goto err; /* Set the key */ penclen = i2d_ASN1_INTEGER(pubk, &penc); ASN1_INTEGER_free(pubk); if (penclen <= 0) goto err; ASN1_STRING_set0(pubkey, penc, penclen); pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber), V_ASN1_UNDEF, NULL); } /* See if custom paraneters set */ kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx); if (kdf_type <= 0) goto err; if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md)) goto err; if (kdf_type == EVP_PKEY_DH_KDF_NONE) { kdf_type = EVP_PKEY_DH_KDF_X9_42; if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0) goto err; } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42) /* Unknown KDF */ goto err; if (kdf_md == NULL) { /* Only SHA1 supported */ kdf_md = EVP_sha1(); if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0) goto err; } else if (EVP_MD_type(kdf_md) != NID_sha1) /* Unsupported digest */ goto err; if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) goto err; /* Get wrap NID */ ctx = CMS_RecipientInfo_kari_get0_ctx(ri); wrap_nid = EVP_CIPHER_CTX_type(ctx); if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0) goto err; keylen = EVP_CIPHER_CTX_key_length(ctx); /* Package wrap algorithm in an AlgorithmIdentifier */ wrap_alg = X509_ALGOR_new(); if (!wrap_alg) goto err; wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); wrap_alg->parameter = ASN1_TYPE_new(); if (!wrap_alg->parameter) goto err; if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) goto err; if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { ASN1_TYPE_free(wrap_alg->parameter); wrap_alg->parameter = NULL; } if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) goto err; if (ukm) { dukmlen = ASN1_STRING_length(ukm); dukm = BUF_memdup(ASN1_STRING_data(ukm), dukmlen); if (!dukm) goto err; } if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) goto err; dukm = NULL; /* * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter * of another AlgorithmIdentifier. */ penc = NULL; penclen = i2d_X509_ALGOR(wrap_alg, &penc); if (!penc || !penclen) goto err; wrap_str = ASN1_STRING_new(); if (!wrap_str) goto err; ASN1_STRING_set0(wrap_str, penc, penclen); penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH), V_ASN1_SEQUENCE, wrap_str); rv = 1; err: if (penc) OPENSSL_free(penc); if (wrap_alg) X509_ALGOR_free(wrap_alg); return rv; }
static int ecdh_cms_encrypt(CMS_RecipientInfo *ri) { EVP_PKEY_CTX *pctx; EVP_PKEY *pkey; EVP_CIPHER_CTX *ctx; int keylen; X509_ALGOR *talg, *wrap_alg = NULL; ASN1_OBJECT *aoid; ASN1_BIT_STRING *pubkey; ASN1_STRING *wrap_str; ASN1_OCTET_STRING *ukm; unsigned char *penc = NULL; int penclen; int rv = 0; int ecdh_nid, kdf_type, kdf_nid, wrap_nid; const EVP_MD *kdf_md; pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!pctx) return 0; /* Get ephemeral key */ pkey = EVP_PKEY_CTX_get0_pkey(pctx); if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, NULL, NULL, NULL)) goto err; X509_ALGOR_get0(&aoid, NULL, NULL, talg); /* Is everything uninitialised? */ if (aoid == OBJ_nid2obj(NID_undef)) { EC_KEY *eckey = pkey->pkey.ec; /* Set the key */ unsigned char *p; penclen = i2o_ECPublicKey(eckey, NULL); if (penclen <= 0) goto err; penc = OPENSSL_malloc(penclen); if (!penc) goto err; p = penc; penclen = i2o_ECPublicKey(eckey, &p); if (penclen <= 0) goto err; ASN1_STRING_set0(pubkey, penc, penclen); pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), V_ASN1_UNDEF, NULL); } /* See if custom paraneters set */ kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx); if (kdf_type <= 0) goto err; if (!EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md)) goto err; ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx); if (ecdh_nid < 0) goto err; else if (ecdh_nid == 0) ecdh_nid = NID_dh_std_kdf; else if (ecdh_nid == 1) ecdh_nid = NID_dh_cofactor_kdf; if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) { kdf_type = EVP_PKEY_ECDH_KDF_X9_62; if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0) goto err; } else /* Uknown KDF */ goto err; if (kdf_md == NULL) { /* Fixme later for better MD */ kdf_md = EVP_sha1(); if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0) goto err; } if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) goto err; /* Lookup NID for KDF+cofactor+digest */ if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_type(kdf_md), ecdh_nid)) goto err; /* Get wrap NID */ ctx = CMS_RecipientInfo_kari_get0_ctx(ri); wrap_nid = EVP_CIPHER_CTX_type(ctx); keylen = EVP_CIPHER_CTX_key_length(ctx); /* Package wrap algorithm in an AlgorithmIdentifier */ wrap_alg = X509_ALGOR_new(); if (!wrap_alg) goto err; wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); wrap_alg->parameter = ASN1_TYPE_new(); if (!wrap_alg->parameter) goto err; if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) goto err; if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { ASN1_TYPE_free(wrap_alg->parameter); wrap_alg->parameter = NULL; } if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) goto err; penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen); if (!penclen) goto err; if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0) goto err; penc = NULL; /* * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter * of another AlgorithmIdentifier. */ penclen = i2d_X509_ALGOR(wrap_alg, &penc); if (!penc || !penclen) goto err; wrap_str = ASN1_STRING_new(); if (!wrap_str) goto err; ASN1_STRING_set0(wrap_str, penc, penclen); penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str); rv = 1; err: OPENSSL_free(penc); X509_ALGOR_free(wrap_alg); return rv; }
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; }