123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- /*
- * Copyright 2009-2018 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- #include "internal/cryptlib.h"
- #include <openssl/asn1t.h>
- #include <openssl/pem.h>
- #include <openssl/x509v3.h>
- #include <openssl/err.h>
- #include <openssl/cms.h>
- #include <openssl/rand.h>
- #include <openssl/aes.h>
- #include "cms_local.h"
- #include "crypto/asn1.h"
- int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
- unsigned char *pass, ossl_ssize_t passlen)
- {
- CMS_PasswordRecipientInfo *pwri;
- if (ri->type != CMS_RECIPINFO_PASS) {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);
- return 0;
- }
- pwri = ri->d.pwri;
- pwri->pass = pass;
- if (pass && passlen < 0)
- passlen = strlen((char *)pass);
- pwri->passlen = passlen;
- return 1;
- }
- CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
- int iter, int wrap_nid,
- int pbe_nid,
- unsigned char *pass,
- ossl_ssize_t passlen,
- const EVP_CIPHER *kekciph)
- {
- CMS_RecipientInfo *ri = NULL;
- CMS_EnvelopedData *env;
- CMS_PasswordRecipientInfo *pwri;
- EVP_CIPHER_CTX *ctx = NULL;
- 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();
- if (encalg == NULL) {
- goto merr;
- }
- ctx = EVP_CIPHER_CTX_new();
- 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) {
- if (RAND_bytes(iv, ivlen) <= 0)
- goto err;
- 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_free(ctx);
- ctx = NULL;
- /* Initialize recipient info */
- ri = M_ASN1_new_of(CMS_RecipientInfo);
- if (ri == NULL)
- goto merr;
- ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
- if (ri->d.pwri == NULL)
- 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 == NULL)
- goto merr;
- pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
- pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
- if (pwri->keyEncryptionAlgorithm->parameter == NULL)
- 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 == NULL)
- 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_free(ctx);
- if (ri)
- M_ASN1_free_of(ri, CMS_RecipientInfo);
- X509_ALGOR_free(encalg);
- return NULL;
- }
- /*
- * This is an implementation of the key wrapping mechanism in RFC3211, at
- * some point this should go into EVP.
- */
- static int kek_unwrap_key(unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen,
- EVP_CIPHER_CTX *ctx)
- {
- size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
- unsigned char *tmp;
- int outl, rv = 0;
- if (inlen < 2 * blocklen) {
- /* too small */
- return 0;
- }
- if (inlen % blocklen) {
- /* Invalid size */
- return 0;
- }
- if ((tmp = OPENSSL_malloc(inlen)) == NULL) {
- CMSerr(CMS_F_KEK_UNWRAP_KEY, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- /* setup IV by decrypting last two blocks */
- if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
- in + inlen - 2 * blocklen, blocklen * 2)
- /*
- * Do a decrypt of last decrypted block to set IV to correct value
- * output it to start of buffer so we don't corrupt decrypted block
- * this works because buffer is at least two block lengths long.
- */
- || !EVP_DecryptUpdate(ctx, tmp, &outl,
- tmp + inlen - blocklen, blocklen)
- /* Can now decrypt first n - 1 blocks */
- || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
- /* Reset IV to original value */
- || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
- /* Decrypt again */
- || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
- goto err;
- /* Check check bytes */
- if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
- /* Check byte failure */
- goto err;
- }
- if (inlen < (size_t)(tmp[0] - 4)) {
- /* Invalid length value */
- goto err;
- }
- *outlen = (size_t)tmp[0];
- memcpy(out, tmp + 4, *outlen);
- rv = 1;
- err:
- OPENSSL_clear_free(tmp, inlen);
- return rv;
- }
- static int kek_wrap_key(unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen,
- EVP_CIPHER_CTX *ctx)
- {
- size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
- size_t olen;
- int dummy;
- /*
- * First decide length of output buffer: need header and round up to
- * multiple of block length.
- */
- olen = (inlen + 4 + blocklen - 1) / blocklen;
- olen *= blocklen;
- if (olen < 2 * blocklen) {
- /* Key too small */
- return 0;
- }
- if (inlen > 0xFF) {
- /* Key too large */
- return 0;
- }
- if (out) {
- /* Set header */
- out[0] = (unsigned char)inlen;
- out[1] = in[0] ^ 0xFF;
- out[2] = in[1] ^ 0xFF;
- out[3] = in[2] ^ 0xFF;
- memcpy(out + 4, in, inlen);
- /* Add random padding to end */
- if (olen > inlen + 4
- && RAND_bytes(out + 4 + inlen, olen - 4 - inlen) <= 0)
- return 0;
- /* Encrypt twice */
- if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
- || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
- return 0;
- }
- *outlen = olen;
- return 1;
- }
- /* Encrypt/Decrypt content key in PWRI recipient info */
- int cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
- int en_de)
- {
- CMS_EncryptedContentInfo *ec;
- CMS_PasswordRecipientInfo *pwri;
- int r = 0;
- X509_ALGOR *algtmp, *kekalg = NULL;
- EVP_CIPHER_CTX *kekctx = NULL;
- const EVP_CIPHER *kekcipher;
- unsigned char *key = NULL;
- size_t keylen;
- ec = cms->d.envelopedData->encryptedContentInfo;
- pwri = ri->d.pwri;
- if (pwri->pass == NULL) {
- 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;
- }
- kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
- algtmp->parameter);
- 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);
- return 0;
- }
- kekctx = EVP_CIPHER_CTX_new();
- if (kekctx == NULL) {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- /* 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 = OPENSSL_malloc(keylen);
- if (key == NULL)
- 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 = OPENSSL_malloc(pwri->encryptedKey->length);
- if (key == NULL) {
- 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;
- }
- OPENSSL_clear_free(ec->key, ec->keylen);
- ec->key = key;
- ec->keylen = keylen;
- }
- r = 1;
- err:
- EVP_CIPHER_CTX_free(kekctx);
- if (!r)
- OPENSSL_free(key);
- X509_ALGOR_free(kekalg);
- return r;
- }
|