]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/cms/cms_env.c
Don't use the low level AES key wrap APIs in CMS
[thirdparty/openssl.git] / crypto / cms / cms_env.c
index 8d4594353084882dd6f0f0c86c66ff10fd1ec1b7..ac34f3efd685c4f481e1dc4fd0fe16e2360af13f 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
- * Licensed under the OpenSSL license (the "License").  You may not use
+ * 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 <openssl/x509v3.h>
 #include <openssl/err.h>
 #include <openssl/cms.h>
-#include <openssl/aes.h>
-#include "cms_lcl.h"
-#include "internal/asn1_int.h"
-#include "internal/evp_int.h"
+#include <openssl/evp.h>
+#include "cms_local.h"
+#include "crypto/asn1.h"
+#include "crypto/evp.h"
 
 /* CMS EnvelopedData Utilities */
 
@@ -56,14 +56,15 @@ int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
         pkey = ri->d.ktri->pkey;
     else if (ri->type == CMS_RECIPINFO_AGREE) {
         EVP_PKEY_CTX *pctx = ri->d.kari->pctx;
-        if (!pctx)
+
+        if (pctx == NULL)
             return 0;
         pkey = EVP_PKEY_CTX_get0_pkey(pctx);
-        if (!pkey)
+        if (pkey == NULL)
             return 0;
     } else
         return 0;
-    if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
+    if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL)
         return 1;
     i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
     if (i == -2) {
@@ -191,7 +192,7 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
         goto merr;
 
     pk = X509_get0_pubkey(recip);
-    if (!pk) {
+    if (pk == NULL) {
         CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY);
         goto err;
     }
@@ -282,13 +283,14 @@ int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
         CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, CMS_R_NOT_KEY_TRANSPORT);
         return 0;
     }
+    EVP_PKEY_free(ri->d.ktri->pkey);
     ri->d.ktri->pkey = pkey;
     return 1;
 }
 
 /* Encrypt content key in key transport recipient info */
 
-static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
+static int cms_RecipientInfo_ktri_encrypt(const CMS_ContentInfo *cms,
                                           CMS_RecipientInfo *ri)
 {
     CMS_KeyTransRecipientInfo *ktri;
@@ -362,6 +364,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
     unsigned char *ek = NULL;
     size_t eklen;
     int ret = 0;
+    size_t fixlen = 0;
     CMS_EncryptedContentInfo *ec;
     ec = cms->d.envelopedData->encryptedContentInfo;
 
@@ -370,6 +373,19 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
         return 0;
     }
 
+    if (cms->d.envelopedData->encryptedContentInfo->havenocert
+            && !cms->d.envelopedData->encryptedContentInfo->debug) {
+        X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
+        const EVP_CIPHER *ciph = EVP_get_cipherbyobj(calg->algorithm);
+
+        if (ciph == NULL) {
+            CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_UNKNOWN_CIPHER);
+            return 0;
+        }
+
+        fixlen = EVP_CIPHER_key_length(ciph);
+    }
+
     ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL);
     if (ktri->pctx == NULL)
         return 0;
@@ -400,7 +416,9 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
 
     if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen,
                          ktri->encryptedKey->data,
-                         ktri->encryptedKey->length) <= 0) {
+                         ktri->encryptedKey->length) <= 0
+            || eklen == 0
+            || (fixlen != 0 && eklen != fixlen)) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
         goto err;
     }
@@ -607,43 +625,74 @@ int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
     return 1;
 }
 
+static const EVP_CIPHER *cms_get_key_wrap_cipher(size_t keylen)
+{
+    switch(keylen) {
+    case 16:
+        return EVP_aes_128_wrap();
+
+    case 24:
+        return EVP_aes_192_wrap();
+
+    case 32:
+        return EVP_aes_256_wrap();
+    }
+
+    return NULL;
+}
+
+
 /* Encrypt content key in KEK recipient info */
 
-static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
+static int cms_RecipientInfo_kekri_encrypt(const CMS_ContentInfo *cms,
                                            CMS_RecipientInfo *ri)
 {
     CMS_EncryptedContentInfo *ec;
     CMS_KEKRecipientInfo *kekri;
-    AES_KEY actx;
     unsigned char *wkey = NULL;
     int wkeylen;
     int r = 0;
+    const EVP_CIPHER *cipher = NULL;
+    int outlen = 0;
+    EVP_CIPHER_CTX *ctx = NULL;
 
     ec = cms->d.envelopedData->encryptedContentInfo;
 
     kekri = ri->d.kekri;
 
-    if (!kekri->key) {
+    if (kekri->key == NULL) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
         return 0;
     }
 
-    if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
-        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
-               CMS_R_ERROR_SETTING_KEY);
+    cipher = cms_get_key_wrap_cipher(kekri->keylen);
+    if (cipher == NULL) {
+        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_INVALID_KEY_LENGTH);
         goto err;
     }
 
+    /* 8 byte prefix for AES wrap ciphers */
     wkey = OPENSSL_malloc(ec->keylen + 8);
-
     if (wkey == NULL) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
-    wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
+    ctx = EVP_CIPHER_CTX_new();
+    if (ctx == NULL) {
+        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
 
-    if (wkeylen <= 0) {
+    EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+    if (!EVP_EncryptInit_ex(ctx, cipher, NULL, kekri->key, NULL)
+            || !EVP_EncryptUpdate(ctx, wkey, &wkeylen, ec->key, ec->keylen)
+            || !EVP_EncryptFinal_ex(ctx, wkey + wkeylen, &outlen)) {
+        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
+        goto err;
+    }
+    wkeylen += outlen;
+    if (!ossl_assert((size_t)wkeylen == ec->keylen + 8)) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
         goto err;
     }
@@ -653,10 +702,9 @@ static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
     r = 1;
 
  err:
-
     if (!r)
         OPENSSL_free(wkey);
-    OPENSSL_cleanse(&actx, sizeof(actx));
+    EVP_CIPHER_CTX_free(ctx);
 
     return r;
 
@@ -669,10 +717,12 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
 {
     CMS_EncryptedContentInfo *ec;
     CMS_KEKRecipientInfo *kekri;
-    AES_KEY actx;
     unsigned char *ukey = NULL;
     int ukeylen;
     int r = 0, wrap_nid;
+    const EVP_CIPHER *cipher = NULL;
+    int outlen = 0;
+    EVP_CIPHER_CTX *ctx = NULL;
 
     ec = cms->d.envelopedData->encryptedContentInfo;
 
@@ -698,27 +748,33 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
         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);
+    cipher = cms_get_key_wrap_cipher(kekri->keylen);
+    if (cipher == NULL) {
+        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_INVALID_KEY_LENGTH);
         goto err;
     }
 
     ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
-
     if (ukey == NULL) {
         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);
+    ctx = EVP_CIPHER_CTX_new();
+    if (ctx == NULL) {
+        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
 
-    if (ukeylen <= 0) {
+    if (!EVP_DecryptInit_ex(ctx, cipher, NULL, kekri->key, NULL)
+            || !EVP_DecryptUpdate(ctx, ukey, &ukeylen,
+                                  kekri->encryptedKey->data,
+                                  kekri->encryptedKey->length)
+            || !EVP_DecryptFinal_ex(ctx, ukey + ukeylen, &outlen)) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR);
         goto err;
     }
+    ukeylen += outlen;
 
     ec->key = ukey;
     ec->keylen = ukeylen;
@@ -726,10 +782,9 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
     r = 1;
 
  err:
-
     if (!r)
         OPENSSL_free(ukey);
-    OPENSSL_cleanse(&actx, sizeof(actx));
+    EVP_CIPHER_CTX_free(ctx);
 
     return r;
 
@@ -749,12 +804,12 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
 
     default:
         CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
-               CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
+               CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE);
         return 0;
     }
 }
 
-int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
+int CMS_RecipientInfo_encrypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
 {
     switch (ri->type) {
     case CMS_RECIPINFO_TRANS:
@@ -839,7 +894,7 @@ static void cms_env_set_version(CMS_EnvelopedData *env)
     env->version = 0;
 }
 
-BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
+BIO *cms_EnvelopedData_init_bio(const CMS_ContentInfo *cms)
 {
     CMS_EncryptedContentInfo *ec;
     STACK_OF(CMS_RecipientInfo) *rinfos;