1 /*
2 * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <assert.h>
11 #include <limits.h>
12 #include <openssl/cms.h>
13 #include <openssl/core_names.h>
14 #include <openssl/err.h>
15 #include <openssl/decoder.h>
16 #include "internal/sizes.h"
17 #include "crypto/asn1.h"
18 #include "crypto/evp.h"
19 #include "cms_local.h"
20
kem_cms_decrypt(CMS_RecipientInfo * ri)21 static int kem_cms_decrypt(CMS_RecipientInfo *ri)
22 {
23 uint32_t *kekLength;
24 X509_ALGOR *wrap;
25 EVP_PKEY_CTX *pctx;
26 EVP_CIPHER_CTX *kekctx;
27 uint32_t cipher_length;
28 char name[OSSL_MAX_NAME_SIZE];
29 EVP_CIPHER *kekcipher = NULL;
30 int rv = 0;
31
32 if (!ossl_cms_RecipientInfo_kemri_get0_alg(ri, &kekLength, &wrap))
33 goto err;
34
35 pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
36 if (pctx == NULL)
37 goto err;
38
39 kekctx = CMS_RecipientInfo_kemri_get0_ctx(ri);
40 if (kekctx == NULL)
41 goto err;
42
43 OBJ_obj2txt(name, sizeof(name), wrap->algorithm, 0);
44 kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery);
45 if (kekcipher == NULL || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
46 goto err;
47 if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
48 goto err;
49 if (EVP_CIPHER_asn1_to_param(kekctx, wrap->parameter) <= 0)
50 goto err;
51
52 cipher_length = EVP_CIPHER_CTX_get_key_length(kekctx);
53 if (cipher_length != *kekLength) {
54 ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH);
55 goto err;
56 }
57
58 rv = 1;
59 err:
60 EVP_CIPHER_free(kekcipher);
61 return rv;
62 }
63
kem_cms_encrypt(CMS_RecipientInfo * ri)64 static int kem_cms_encrypt(CMS_RecipientInfo *ri)
65 {
66 uint32_t *kekLength;
67 X509_ALGOR *wrap;
68 X509_ALGOR *kdf;
69 EVP_PKEY_CTX *pctx;
70 EVP_PKEY *pkey;
71 int security_bits;
72 const ASN1_OBJECT *kdf_obj = NULL;
73 unsigned char kemri_x509_algor[OSSL_MAX_ALGORITHM_ID_SIZE];
74 OSSL_PARAM params[2];
75 X509_ALGOR *x509_algor = NULL;
76 EVP_CIPHER_CTX *kekctx;
77 int wrap_nid;
78 int rv = 0;
79
80 if (!ossl_cms_RecipientInfo_kemri_get0_alg(ri, &kekLength, &wrap))
81 goto err;
82
83 kdf = CMS_RecipientInfo_kemri_get0_kdf_alg(ri);
84 if (kdf == NULL)
85 goto err;
86
87 pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
88 if (pctx == NULL)
89 goto err;
90
91 pkey = EVP_PKEY_CTX_get0_pkey(pctx);
92 if (pkey == NULL)
93 goto err;
94
95 security_bits = EVP_PKEY_get_security_bits(pkey);
96 if (security_bits == 0)
97 goto err;
98
99 X509_ALGOR_get0(&kdf_obj, NULL, NULL, kdf);
100 if (kdf_obj == NULL || OBJ_obj2nid(kdf_obj) == NID_undef) {
101 /*
102 * If the KDF OID hasn't already been set, then query the provider
103 * for a default KDF.
104 */
105 params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_CMS_KEMRI_KDF_ALGORITHM,
106 kemri_x509_algor, sizeof(kemri_x509_algor));
107 params[1] = OSSL_PARAM_construct_end();
108 if (!EVP_PKEY_get_params(pkey, params))
109 goto err;
110 if (OSSL_PARAM_modified(¶ms[0])) {
111 const unsigned char *p = kemri_x509_algor;
112
113 x509_algor = d2i_X509_ALGOR(NULL, &p, (long)params[0].return_size);
114 if (x509_algor == NULL)
115 goto err;
116 if (!X509_ALGOR_copy(kdf, x509_algor))
117 goto err;
118 } else {
119 if (!X509_ALGOR_set0(kdf, OBJ_nid2obj(NID_HKDF_SHA256), V_ASN1_UNDEF, NULL))
120 return 0;
121 }
122 }
123
124 /* Get wrap NID */
125 kekctx = CMS_RecipientInfo_kemri_get0_ctx(ri);
126 if (kekctx == NULL)
127 goto err;
128 *kekLength = EVP_CIPHER_CTX_get_key_length(kekctx);
129 wrap_nid = EVP_CIPHER_CTX_get_type(kekctx);
130
131 /* Package wrap algorithm in an AlgorithmIdentifier */
132 ASN1_OBJECT_free(wrap->algorithm);
133 ASN1_TYPE_free(wrap->parameter);
134 wrap->algorithm = OBJ_nid2obj(wrap_nid);
135 wrap->parameter = ASN1_TYPE_new();
136 if (wrap->parameter == NULL)
137 goto err;
138 if (EVP_CIPHER_param_to_asn1(kekctx, wrap->parameter) <= 0)
139 goto err;
140 if (ASN1_TYPE_get(wrap->parameter) == NID_undef) {
141 ASN1_TYPE_free(wrap->parameter);
142 wrap->parameter = NULL;
143 }
144
145 rv = 1;
146 err:
147 X509_ALGOR_free(x509_algor);
148 return rv;
149 }
150
ossl_cms_kem_envelope(CMS_RecipientInfo * ri,int decrypt)151 int ossl_cms_kem_envelope(CMS_RecipientInfo *ri, int decrypt)
152 {
153 assert(decrypt == 0 || decrypt == 1);
154
155 if (decrypt == 1)
156 return kem_cms_decrypt(ri);
157
158 if (decrypt == 0)
159 return kem_cms_encrypt(ri);
160
161 ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
162 return 0;
163 }
164