1 /*
2 * Copyright 2018-2026 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 <string.h>
11
12 #include <openssl/pem.h>
13 #include <openssl/cms.h>
14 #include <openssl/bio.h>
15 #include <openssl/x509.h>
16 #include "../crypto/cms/cms_local.h" /* for d.signedData and d.envelopedData */
17
18 #include "testutil.h"
19
20 static X509 *cert = NULL;
21 static EVP_PKEY *privkey = NULL;
22 static char *derin = NULL;
23 static char *too_long_iv_cms_in = NULL;
24 static char *pwri_kek_oob_der_in = NULL;
25 static char *ec_recip_in = NULL;
26
27 /*
28 * This is our bad cms data, it contains an AuthEnvelopedData field
29 * with a CIPHER OID set to AES-256-OFB
30 */
31 static const unsigned char bad_cms_der[452] = {
32 0x30, 0x82, 0x01, 0xc0, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
33 0x01, 0x09, 0x10, 0x01, 0x17, 0xa0, 0x82, 0x01, 0xaf, 0x30, 0x82, 0x01,
34 0xab, 0x02, 0x01, 0x00, 0x31, 0x82, 0x01, 0x44, 0x30, 0x82, 0x01, 0x40,
35 0x02, 0x01, 0x00, 0x30, 0x28, 0x30, 0x10, 0x31, 0x0e, 0x30, 0x0c, 0x06,
36 0x03, 0x55, 0x04, 0x03, 0x0c, 0x05, 0x52, 0x65, 0x63, 0x69, 0x70, 0x02,
37 0x14, 0x1a, 0x5c, 0x04, 0x9b, 0x3a, 0x64, 0xff, 0xd4, 0x63, 0xde, 0x4f,
38 0x90, 0xe5, 0x76, 0xe2, 0x18, 0xe8, 0x5c, 0x9e, 0xd7, 0x30, 0x0d, 0x06,
39 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
40 0x04, 0x82, 0x01, 0x00, 0x18, 0xcf, 0x9f, 0x44, 0x95, 0x79, 0xe9, 0x96,
41 0x7d, 0x0f, 0xd1, 0xb4, 0xc2, 0x38, 0xb0, 0xc9, 0x76, 0xd5, 0xba, 0x08,
42 0x5c, 0xbf, 0xc3, 0x30, 0xea, 0x3a, 0x68, 0xa4, 0xba, 0x99, 0x4c, 0x70,
43 0x97, 0xb8, 0xa9, 0xce, 0x71, 0x4c, 0x54, 0xa3, 0xfd, 0x81, 0x9e, 0x15,
44 0x63, 0xb7, 0x23, 0x46, 0x17, 0x69, 0xaf, 0x8f, 0xbd, 0xa3, 0x54, 0x23,
45 0xf3, 0xf5, 0x35, 0xa8, 0xd4, 0x9c, 0xec, 0xe1, 0x17, 0x2c, 0x6d, 0x0b,
46 0xad, 0xc0, 0xe9, 0x1d, 0xd1, 0x8d, 0x59, 0xd5, 0x29, 0xc6, 0x40, 0xc4,
47 0xcd, 0x4e, 0x87, 0x70, 0x19, 0x5d, 0x88, 0x50, 0xbd, 0x4a, 0x13, 0xb3,
48 0xef, 0x0c, 0x6d, 0x6a, 0xc5, 0x51, 0xbb, 0x5c, 0x39, 0x17, 0xda, 0xb1,
49 0x71, 0x17, 0x88, 0xfb, 0x6a, 0xef, 0x7f, 0x85, 0xa7, 0x04, 0x71, 0xc7,
50 0x83, 0x91, 0xb3, 0x30, 0x1b, 0x3d, 0x18, 0x7f, 0x63, 0xbf, 0x42, 0x7c,
51 0xae, 0x6f, 0xae, 0xa1, 0x17, 0x84, 0xfd, 0x67, 0x2a, 0x4f, 0x4c, 0xe9,
52 0x05, 0x26, 0x2c, 0xd5, 0xab, 0x0c, 0xcf, 0xdc, 0x3f, 0x24, 0xcf, 0x71,
53 0x26, 0x7a, 0x1f, 0xf7, 0xc9, 0x92, 0x5e, 0xb6, 0x3d, 0x7f, 0xc3, 0x08,
54 0xd3, 0xad, 0xc0, 0xc8, 0x4f, 0x42, 0x0c, 0xf3, 0xac, 0x23, 0x11, 0xdf,
55 0x75, 0x84, 0x69, 0x8c, 0xa6, 0x59, 0x43, 0xfb, 0xf7, 0x6b, 0x62, 0xf0,
56 0xf7, 0x35, 0x07, 0xc4, 0xf8, 0xd5, 0x12, 0x4a, 0x16, 0x62, 0xbc, 0x04,
57 0xaa, 0x9a, 0x2e, 0xb2, 0x1a, 0xfa, 0x4c, 0x82, 0xce, 0x9e, 0xa8, 0x6d,
58 0xc1, 0x29, 0x59, 0xe0, 0x33, 0xb5, 0xa6, 0x47, 0x09, 0x2e, 0xbf, 0x60,
59 0xa6, 0xb3, 0x21, 0xa0, 0x15, 0xac, 0x92, 0x29, 0xb5, 0xe6, 0xe0, 0xd4,
60 0x8b, 0xd8, 0x21, 0xe2, 0x17, 0x98, 0xd1, 0x11, 0x5d, 0xc5, 0xae, 0x24,
61 0xe8, 0x92, 0xdb, 0x96, 0xa3, 0x5b, 0x58, 0xa7, 0x30, 0x4c, 0x06, 0x09,
62 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1d, 0x06,
63 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2b, 0x04, 0x10,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
66 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
67 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
68 0x41, 0x41, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
70 };
71
72 /*
73 * This array represents a der encoded contentinfo structure addressed to
74 * servercert.pem, with the tag value of the aes-256-gcm cipher used to encrypt
75 * the contents of the mssages down to 1 byte. Decoding it should fail
76 */
77 static const unsigned char one_byte_mac_cms_der[423] = {
78 0x30, 0x82, 0x01, 0xa3, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
79 0x01, 0x09, 0x10, 0x01, 0x17, 0xa0, 0x82, 0x01, 0x92, 0x30, 0x82, 0x01,
80 0x8e, 0x02, 0x01, 0x00, 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, 0x2f,
81 0x02, 0x01, 0x00, 0x30, 0x17, 0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06,
82 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
83 0x41, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
84 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x10,
85 0x3a, 0x8c, 0xee, 0x4e, 0xe2, 0x1f, 0xfe, 0xcc, 0x28, 0x39, 0x9e, 0x46,
86 0xbe, 0xa7, 0xd5, 0x02, 0x2a, 0x53, 0x06, 0x5f, 0x94, 0x6b, 0x69, 0x6d,
87 0x2d, 0xe8, 0x44, 0xa6, 0x43, 0x52, 0x82, 0x89, 0x2d, 0xf1, 0x9b, 0xb9,
88 0x9e, 0xa4, 0x8d, 0x77, 0xf1, 0xd2, 0x8e, 0x86, 0x79, 0x06, 0x3e, 0x90,
89 0xf0, 0xca, 0x9e, 0xb5, 0x35, 0xd5, 0x89, 0xf0, 0x7c, 0x06, 0xa0, 0x91,
90 0xbf, 0xf4, 0x61, 0xaa, 0x5c, 0x99, 0xa3, 0x64, 0x15, 0xfd, 0xf9, 0x90,
91 0xf0, 0xf3, 0x25, 0x5b, 0x48, 0xa1, 0xfb, 0x7a, 0xce, 0x63, 0xdc, 0xa9,
92 0xfe, 0x7c, 0xbe, 0x9c, 0xaa, 0xd3, 0x42, 0x0e, 0x4a, 0xc3, 0x4b, 0x4e,
93 0x76, 0x6d, 0x52, 0x54, 0x85, 0x4e, 0xab, 0x50, 0x2c, 0x5f, 0xc2, 0x8b,
94 0x9f, 0x1f, 0x0f, 0x8a, 0x7c, 0xb3, 0x0a, 0xde, 0x50, 0x9b, 0xef, 0x89,
95 0xf2, 0xea, 0x07, 0xca, 0x11, 0x76, 0x29, 0xaf, 0xe4, 0x59, 0x28, 0x19,
96 0x48, 0x96, 0x67, 0xdd, 0xdd, 0x01, 0xf0, 0x14, 0xbe, 0x3d, 0xa5, 0xa3,
97 0x83, 0x21, 0x39, 0x29, 0xb7, 0x8f, 0xb7, 0xf4, 0x85, 0x05, 0xee, 0xca,
98 0xbb, 0xbd, 0xc0, 0xaf, 0x0d, 0xf1, 0xef, 0x5f, 0x06, 0x05, 0xeb, 0x0e,
99 0x55, 0xf0, 0x7e, 0x13, 0x1a, 0x2a, 0x37, 0xd4, 0xba, 0x26, 0xc8, 0x2e,
100 0x6b, 0xc3, 0xe1, 0xcf, 0x28, 0xab, 0x0d, 0xab, 0xdd, 0xa7, 0xf4, 0xd3,
101 0x59, 0xcd, 0xc7, 0x2d, 0xa1, 0x56, 0x5f, 0x47, 0x77, 0x27, 0x17, 0x71,
102 0xae, 0x75, 0xc8, 0x71, 0x58, 0xf9, 0xab, 0x67, 0xda, 0x23, 0x62, 0xa0,
103 0x6d, 0xe5, 0x2d, 0x06, 0xb8, 0xc0, 0xac, 0xaa, 0x38, 0xa4, 0x0d, 0xb5,
104 0xb2, 0xce, 0xa7, 0x26, 0x0d, 0x3a, 0x88, 0x2f, 0x8d, 0x6c, 0xa0, 0xf6,
105 0x94, 0xf2, 0x2c, 0x37, 0x03, 0xaf, 0x67, 0x5c, 0xf3, 0x2c, 0xfb, 0xe8,
106 0x16, 0x9e, 0x55, 0x30, 0x4f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
107 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1e, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
108 0x65, 0x03, 0x04, 0x01, 0x2e, 0x30, 0x11, 0x04, 0x0c, 0x6b, 0x1d, 0xe5,
109 0xb2, 0x38, 0x0e, 0x17, 0x91, 0x9c, 0x9c, 0x40, 0x35, 0x02, 0x01, 0x10,
110 0x80, 0x22, 0xa0, 0x90, 0x75, 0x74, 0xdf, 0x2d, 0xba, 0x4f, 0xce, 0x4e,
111 0x7e, 0x52, 0xb0, 0x2e, 0x5f, 0xe0, 0x84, 0x01, 0xb1, 0x49, 0x0b, 0x69,
112 0xc7, 0x61, 0x63, 0x84, 0x3a, 0xfc, 0xaa, 0x86, 0xfc, 0x96, 0x4e, 0x6c,
113 0x04, 0x01, 0x92
114 };
115
test_short_mac_on_auth_envelope_data(void)116 static int test_short_mac_on_auth_envelope_data(void)
117 {
118 int ret = 0;
119 const unsigned char *derptr = one_byte_mac_cms_der;
120 BIO *outmsgbio = BIO_new(BIO_s_mem());
121 CMS_ContentInfo *content = d2i_CMS_ContentInfo(NULL, &derptr, OSSL_NELEM(one_byte_mac_cms_der));
122
123 if (!TEST_ptr(content))
124 goto end;
125
126 /*
127 * We expect this to fail, as the tag value in the authEnvelopedData parameter is
128 * a single byte
129 */
130 if (!TEST_false(CMS_decrypt(content, privkey, cert, NULL, outmsgbio, CMS_TEXT)))
131 goto end;
132
133 ret = 1;
134 end:
135 BIO_free(outmsgbio);
136 CMS_ContentInfo_free(content);
137 return ret;
138 }
139
test_non_aead_on_auth_envelope_dec(void)140 static int test_non_aead_on_auth_envelope_dec(void)
141 {
142 int ret = 0;
143 const unsigned char *derptr = bad_cms_der;
144 BIO *outmsgbio = BIO_new(BIO_s_mem());
145 CMS_ContentInfo *content = d2i_CMS_ContentInfo(NULL, &derptr, OSSL_NELEM(bad_cms_der));
146
147 if (!TEST_ptr(content))
148 goto end;
149
150 /*
151 * We expect this to fail
152 */
153 if (!TEST_false(CMS_decrypt(content, privkey, cert, NULL, outmsgbio,
154 CMS_TEXT)))
155 goto end;
156
157 ret = 1;
158 end:
159 BIO_free(outmsgbio);
160 CMS_ContentInfo_free(content);
161 return ret;
162 }
163
test_non_aead_on_auth_envelope_enc(void)164 static int test_non_aead_on_auth_envelope_enc(void)
165 {
166 CMS_ContentInfo *content = NULL;
167 STACK_OF(X509) *certstack = sk_X509_new_null();
168 const EVP_CIPHER *cipher = EVP_aes_128_cbc();
169 const char *msg = "Hello world";
170 BIO *msgbio = BIO_new_mem_buf(msg, (int)strlen(msg));
171 BIO *outmsgbio = BIO_new(BIO_s_mem());
172 X509 *recip;
173 int i;
174 int ret = 0;
175
176 if (!TEST_ptr(certstack) || !TEST_ptr(msgbio) || !TEST_ptr(outmsgbio))
177 goto end;
178
179 if (!TEST_int_gt(sk_X509_push(certstack, cert), 0))
180 goto end;
181
182 /*
183 * Emulate CMS_encrypt here, but use a non AEAD cipher
184 */
185 content = CMS_AuthEnvelopedData_create_ex(cipher, NULL, NULL);
186
187 if (!TEST_ptr(content))
188 goto end;
189
190 for (i = 0; i < sk_X509_num(certstack); i++) {
191 recip = sk_X509_value(certstack, i);
192 if (!TEST_ptr(CMS_add1_recipient_cert(content, recip, CMS_TEXT)))
193 goto end;
194 }
195
196 /*
197 * We expect this to fail as we are using a non-AEAD cipher on
198 * AuthEnvelopedData
199 */
200 if (!TEST_int_eq(CMS_final(content, msgbio, NULL, CMS_TEXT), 0))
201 goto end;
202
203 ret = 1;
204 end:
205 sk_X509_free(certstack);
206 BIO_free(msgbio);
207 BIO_free(outmsgbio);
208 CMS_ContentInfo_free(content);
209 return ret;
210 }
211
test_encrypt_decrypt(const EVP_CIPHER * cipher)212 static int test_encrypt_decrypt(const EVP_CIPHER *cipher)
213 {
214 int testresult = 0;
215 STACK_OF(X509) *certstack = sk_X509_new_null();
216 const char *msg = "Hello world";
217 BIO *msgbio = BIO_new_mem_buf(msg, strlen(msg));
218 BIO *outmsgbio = BIO_new(BIO_s_mem());
219 CMS_ContentInfo *content = NULL;
220 BIO *contentbio = NULL;
221 char buf[80];
222
223 if (!TEST_ptr(certstack) || !TEST_ptr(msgbio) || !TEST_ptr(outmsgbio))
224 goto end;
225
226 if (!TEST_int_gt(sk_X509_push(certstack, cert), 0))
227 goto end;
228
229 content = CMS_encrypt(certstack, msgbio, cipher, CMS_TEXT);
230 if (!TEST_ptr(content))
231 goto end;
232
233 if (!TEST_true(CMS_decrypt(content, privkey, cert, NULL, outmsgbio,
234 CMS_TEXT)))
235 goto end;
236
237 if (!(EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
238 && !TEST_ptr(contentbio = CMS_EnvelopedData_decrypt(content->d.envelopedData,
239 NULL, privkey, cert, NULL,
240 CMS_TEXT, NULL, NULL)))
241 goto end;
242
243 /* Check we got the message we first started with */
244 if (!TEST_int_eq(BIO_gets(outmsgbio, buf, sizeof(buf)), strlen(msg))
245 || !TEST_int_eq(strcmp(buf, msg), 0))
246 goto end;
247
248 testresult = 1;
249 end:
250 BIO_free(contentbio);
251 sk_X509_free(certstack);
252 BIO_free(msgbio);
253 BIO_free(outmsgbio);
254 CMS_ContentInfo_free(content);
255
256 return testresult && TEST_int_eq(ERR_peek_error(), 0);
257 }
258
test_encrypt_decrypt_aes_cbc(void)259 static int test_encrypt_decrypt_aes_cbc(void)
260 {
261 return test_encrypt_decrypt(EVP_aes_128_cbc());
262 }
263
test_encrypt_decrypt_aes_128_gcm(void)264 static int test_encrypt_decrypt_aes_128_gcm(void)
265 {
266 return test_encrypt_decrypt(EVP_aes_128_gcm());
267 }
268
test_encrypt_decrypt_aes_192_gcm(void)269 static int test_encrypt_decrypt_aes_192_gcm(void)
270 {
271 return test_encrypt_decrypt(EVP_aes_192_gcm());
272 }
273
test_encrypt_decrypt_aes_256_gcm(void)274 static int test_encrypt_decrypt_aes_256_gcm(void)
275 {
276 return test_encrypt_decrypt(EVP_aes_256_gcm());
277 }
278
test_CMS_add1_cert(void)279 static int test_CMS_add1_cert(void)
280 {
281 CMS_ContentInfo *cms = NULL;
282 int ret = 0;
283
284 ret = TEST_ptr(cms = CMS_ContentInfo_new())
285 && TEST_ptr(CMS_add1_signer(cms, cert, privkey, NULL, 0))
286 && TEST_true(CMS_add1_cert(cms, cert)); /* add cert again */
287
288 CMS_ContentInfo_free(cms);
289 return ret;
290 }
291
test_d2i_CMS_bio_NULL(void)292 static int test_d2i_CMS_bio_NULL(void)
293 {
294 BIO *bio, *content = NULL;
295 CMS_ContentInfo *cms = NULL;
296 unsigned int flags = CMS_NO_SIGNER_CERT_VERIFY;
297 int ret = 0;
298
299 /*
300 * Test data generated using:
301 * openssl cms -sign -md sha256 -signer ./test/certs/rootCA.pem -inkey \
302 * ./test/certs/rootCA.key -nodetach -outform DER -in ./in.txt -out out.der \
303 * -nosmimecap
304 */
305 static const unsigned char cms_data[] = {
306 0x30, 0x82, 0x05, 0xc5, 0x06, 0x09, 0x2a, 0x86,
307 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
308 0x82, 0x05, 0xb6, 0x30, 0x82, 0x05, 0xb2, 0x02,
309 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09,
310 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
311 0x01, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48,
312 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x0f,
313 0x04, 0x0d, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
314 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0d, 0x0a, 0xa0,
315 0x82, 0x03, 0x83, 0x30, 0x82, 0x03, 0x7f, 0x30,
316 0x82, 0x02, 0x67, 0xa0, 0x03, 0x02, 0x01, 0x02,
317 0x02, 0x09, 0x00, 0x88, 0x43, 0x29, 0xcb, 0xc2,
318 0xeb, 0x15, 0x9a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
319 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
320 0x05, 0x00, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09,
321 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
322 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
323 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
324 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
325 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
326 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
327 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
328 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
329 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
330 0x04, 0x03, 0x0c, 0x06, 0x72, 0x6f, 0x6f, 0x74,
331 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35,
332 0x30, 0x37, 0x30, 0x32, 0x31, 0x33, 0x31, 0x35,
333 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x33, 0x35, 0x30,
334 0x37, 0x30, 0x32, 0x31, 0x33, 0x31, 0x35, 0x31,
335 0x31, 0x5a, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09,
336 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
337 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
338 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
339 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
340 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
341 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
342 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
343 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
344 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
345 0x04, 0x03, 0x0c, 0x06, 0x72, 0x6f, 0x6f, 0x74,
346 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
347 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
348 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
349 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
350 0x01, 0x01, 0x00, 0xc0, 0xf1, 0x6b, 0x77, 0x88,
351 0xac, 0x35, 0xdf, 0xfb, 0x73, 0x53, 0x2f, 0x92,
352 0x80, 0x2f, 0x74, 0x16, 0x32, 0x4d, 0xf5, 0x10,
353 0x20, 0x6f, 0x6c, 0x3a, 0x8e, 0xd1, 0xdc, 0x6b,
354 0xe1, 0x2e, 0x3e, 0xc3, 0x04, 0x0f, 0xbf, 0x9b,
355 0xc4, 0xc9, 0x12, 0xd1, 0xe4, 0x0b, 0x45, 0x97,
356 0xe5, 0x06, 0xcd, 0x66, 0x3a, 0xe1, 0xe0, 0xe2,
357 0x2b, 0xdf, 0xa2, 0xc4, 0xec, 0x7b, 0xd3, 0x3d,
358 0x3c, 0x8a, 0xff, 0x5e, 0x74, 0xa0, 0xab, 0xa7,
359 0x03, 0x6a, 0x16, 0x5b, 0x5e, 0x92, 0xc4, 0x7e,
360 0x5b, 0x79, 0x8a, 0x69, 0xd4, 0xbc, 0x83, 0x5e,
361 0xae, 0x42, 0x92, 0x74, 0xa5, 0x2b, 0xe7, 0x00,
362 0xc1, 0xa9, 0xdc, 0xd5, 0xb1, 0x53, 0x07, 0x0f,
363 0x73, 0xf7, 0x8e, 0xad, 0x14, 0x3e, 0x25, 0x9e,
364 0xe5, 0x1e, 0xe6, 0xcc, 0x91, 0xcd, 0x95, 0x0c,
365 0x80, 0x44, 0x20, 0xc3, 0xfd, 0x17, 0xcf, 0x91,
366 0x3d, 0x63, 0x10, 0x1c, 0x14, 0x5b, 0xfb, 0xc3,
367 0xa8, 0xc1, 0x88, 0xb2, 0x77, 0xff, 0x9c, 0xdb,
368 0xfc, 0x6a, 0x44, 0x44, 0x44, 0xf7, 0x85, 0xec,
369 0x08, 0x2c, 0xd4, 0xdf, 0x81, 0xa3, 0x79, 0xc9,
370 0xfe, 0x1e, 0x9b, 0x93, 0x16, 0x53, 0xb7, 0x97,
371 0xab, 0xbe, 0x4f, 0x1a, 0xa5, 0xe2, 0xfa, 0x46,
372 0x05, 0xe4, 0x0d, 0x9c, 0x2a, 0xa4, 0xcc, 0xb9,
373 0x1e, 0x21, 0xa0, 0x6c, 0xc4, 0xab, 0x59, 0xb0,
374 0x40, 0x39, 0xbb, 0xf9, 0x88, 0xad, 0xfd, 0xdf,
375 0x8d, 0xb4, 0x0b, 0xaf, 0x7e, 0x41, 0xe0, 0x21,
376 0x3c, 0xc8, 0x33, 0x45, 0x49, 0x84, 0x2f, 0x93,
377 0x06, 0xee, 0xfd, 0x4f, 0xed, 0x4f, 0xf3, 0xbc,
378 0x9b, 0xde, 0xfc, 0x25, 0x5e, 0x55, 0xd5, 0x75,
379 0xd4, 0xc5, 0x7b, 0x3a, 0x40, 0x35, 0x06, 0x9f,
380 0xc4, 0x84, 0xb4, 0x6c, 0x93, 0x0c, 0xaf, 0x37,
381 0x5a, 0xaf, 0xb6, 0x41, 0x4d, 0x26, 0x23, 0x1c,
382 0xb8, 0x02, 0xb3, 0x02, 0x03, 0x01, 0x00, 0x01,
383 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x0c, 0x06, 0x03,
384 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01,
385 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
386 0x0e, 0x04, 0x16, 0x04, 0x14, 0x85, 0x56, 0x89,
387 0x35, 0xe2, 0x9f, 0x00, 0x1a, 0xe1, 0x86, 0x03,
388 0x0b, 0x4b, 0xaf, 0x76, 0x12, 0x6b, 0x33, 0x6d,
389 0xfd, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
390 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x85, 0x56,
391 0x89, 0x35, 0xe2, 0x9f, 0x00, 0x1a, 0xe1, 0x86,
392 0x03, 0x0b, 0x4b, 0xaf, 0x76, 0x12, 0x6b, 0x33,
393 0x6d, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
394 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
395 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x32, 0x0a,
396 0xbf, 0x2a, 0x0a, 0xe2, 0xbb, 0x4f, 0x43, 0xce,
397 0x88, 0xda, 0x5a, 0x39, 0x10, 0x37, 0x80, 0xbb,
398 0x37, 0x2d, 0x5e, 0x2d, 0x88, 0xdd, 0x26, 0x69,
399 0x9c, 0xe7, 0xb4, 0x98, 0x20, 0xb1, 0x25, 0xe6,
400 0x61, 0x59, 0x6d, 0x12, 0xec, 0x9b, 0x87, 0xbe,
401 0x57, 0xe1, 0x12, 0x05, 0xc5, 0x04, 0xf1, 0x17,
402 0xce, 0x14, 0xb8, 0x1c, 0x92, 0xd4, 0x95, 0x95,
403 0x2c, 0x5b, 0x28, 0x89, 0xfb, 0x72, 0x9c, 0x20,
404 0xd3, 0x32, 0x81, 0xa8, 0x85, 0xec, 0xc8, 0x08,
405 0x7b, 0xa8, 0x59, 0x5b, 0x3a, 0x6c, 0x31, 0xab,
406 0x52, 0xe2, 0x66, 0xcd, 0x14, 0x49, 0x5c, 0xf3,
407 0xd3, 0x3e, 0x62, 0xbc, 0x91, 0x16, 0xb4, 0x1c,
408 0xf5, 0xdd, 0x54, 0xaa, 0x3c, 0x61, 0x97, 0x79,
409 0xac, 0xe4, 0xc8, 0x43, 0x35, 0xc3, 0x0f, 0xfc,
410 0xf3, 0x70, 0x1d, 0xaf, 0xf0, 0x9c, 0x8a, 0x2a,
411 0x92, 0x93, 0x48, 0xaa, 0xd0, 0xe8, 0x47, 0xbe,
412 0x35, 0xc1, 0xc6, 0x7b, 0x6d, 0xda, 0xfa, 0x5d,
413 0x57, 0x45, 0xf3, 0xea, 0x41, 0x8f, 0x36, 0xc1,
414 0x3c, 0xf4, 0x52, 0x7f, 0x6e, 0x31, 0xdd, 0xba,
415 0x9a, 0xbc, 0x70, 0x56, 0x71, 0x38, 0xdc, 0x49,
416 0x57, 0x0c, 0xfd, 0x91, 0x17, 0xc5, 0xea, 0x87,
417 0xe5, 0x23, 0x74, 0x19, 0xb2, 0xb6, 0x99, 0x0c,
418 0x6b, 0xa2, 0x05, 0xf8, 0x51, 0x68, 0xed, 0x97,
419 0xe0, 0xdf, 0x62, 0xf9, 0x7e, 0x7a, 0x3a, 0x44,
420 0x71, 0x83, 0x57, 0x28, 0x49, 0x88, 0x69, 0xb5,
421 0x14, 0x1e, 0xda, 0x46, 0xe3, 0x6e, 0x78, 0xe1,
422 0xcb, 0x8f, 0xb5, 0x98, 0xb3, 0x2d, 0x6e, 0x5b,
423 0xb7, 0xf6, 0x93, 0x24, 0x14, 0x1f, 0xa4, 0xf6,
424 0x69, 0xbd, 0xff, 0x4c, 0x52, 0x50, 0x02, 0xc5,
425 0x43, 0x8d, 0x14, 0xe2, 0xd0, 0x75, 0x9f, 0x12,
426 0x5e, 0x94, 0x89, 0xd1, 0xef, 0x77, 0x89, 0x7d,
427 0x89, 0xd9, 0x9e, 0x76, 0x99, 0x24, 0x31, 0x82,
428 0x01, 0xf7, 0x30, 0x82, 0x01, 0xf3, 0x02, 0x01,
429 0x01, 0x30, 0x63, 0x30, 0x56, 0x31, 0x0b, 0x30,
430 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
431 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
432 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d,
433 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
434 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
435 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
436 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
437 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
438 0x74, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
439 0x55, 0x04, 0x03, 0x0c, 0x06, 0x72, 0x6f, 0x6f,
440 0x74, 0x43, 0x41, 0x02, 0x09, 0x00, 0x88, 0x43,
441 0x29, 0xcb, 0xc2, 0xeb, 0x15, 0x9a, 0x30, 0x0b,
442 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
443 0x04, 0x02, 0x01, 0xa0, 0x69, 0x30, 0x18, 0x06,
444 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
445 0x09, 0x03, 0x31, 0x0b, 0x06, 0x09, 0x2a, 0x86,
446 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30,
447 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
448 0x0d, 0x01, 0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d,
449 0x32, 0x30, 0x31, 0x32, 0x31, 0x31, 0x30, 0x39,
450 0x30, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x2f, 0x06,
451 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
452 0x09, 0x04, 0x31, 0x22, 0x04, 0x20, 0xb0, 0x80,
453 0x22, 0xd3, 0x15, 0xcf, 0x1e, 0xb1, 0x2d, 0x26,
454 0x65, 0xbd, 0xed, 0x0e, 0x6a, 0xf4, 0x06, 0x53,
455 0xc0, 0xa0, 0xbe, 0x97, 0x52, 0x32, 0xfb, 0x49,
456 0xbc, 0xbd, 0x02, 0x1c, 0xfc, 0x36, 0x30, 0x0d,
457 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
458 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01,
459 0x00, 0x37, 0x44, 0x39, 0x08, 0xb2, 0x19, 0x52,
460 0x35, 0x9c, 0xd0, 0x67, 0x87, 0xae, 0xb8, 0x1c,
461 0x80, 0xf4, 0x03, 0x29, 0x2e, 0xe3, 0x76, 0x4a,
462 0xb0, 0x98, 0x10, 0x00, 0x9a, 0x30, 0xdb, 0x05,
463 0x28, 0x53, 0x34, 0x31, 0x14, 0xbd, 0x87, 0xb9,
464 0x4d, 0x45, 0x07, 0x97, 0xa3, 0x57, 0x0b, 0x7e,
465 0xd1, 0x67, 0xfb, 0x4e, 0x0f, 0x5b, 0x90, 0xb2,
466 0x6f, 0xe6, 0xce, 0x49, 0xdd, 0x72, 0x46, 0x71,
467 0x26, 0xa1, 0x1b, 0x98, 0x23, 0x7d, 0x69, 0x73,
468 0x84, 0xdc, 0xf9, 0xd2, 0x1c, 0x6d, 0xf6, 0xf5,
469 0x17, 0x49, 0x6e, 0x9d, 0x4d, 0xf1, 0xe2, 0x43,
470 0x29, 0x53, 0x55, 0xa5, 0x22, 0x1e, 0x89, 0x2c,
471 0xaf, 0xf2, 0x43, 0x47, 0xd5, 0xfa, 0xad, 0xe7,
472 0x89, 0x60, 0xbf, 0x96, 0x35, 0x6f, 0xc2, 0x99,
473 0xb7, 0x55, 0xc5, 0xe3, 0x04, 0x25, 0x1b, 0xf6,
474 0x7e, 0xf2, 0x2b, 0x14, 0xa9, 0x57, 0x96, 0xbe,
475 0xbd, 0x6e, 0x95, 0x44, 0x94, 0xbd, 0xaf, 0x9a,
476 0x6d, 0x77, 0x55, 0x5e, 0x6c, 0xf6, 0x32, 0x37,
477 0xec, 0xef, 0xe5, 0x81, 0xb0, 0xe3, 0x35, 0xc7,
478 0x86, 0xea, 0x47, 0x59, 0x38, 0xb6, 0x16, 0xfb,
479 0x1d, 0x10, 0x55, 0x48, 0xb1, 0x44, 0x33, 0xde,
480 0xf6, 0x29, 0xbe, 0xbf, 0xbc, 0x71, 0x3e, 0x49,
481 0xba, 0xe7, 0x9f, 0x4d, 0x6c, 0xfb, 0xec, 0xd2,
482 0xe0, 0x12, 0xa9, 0x7c, 0xc9, 0x9a, 0x7b, 0x85,
483 0x83, 0xb8, 0xca, 0xdd, 0xf6, 0xb7, 0x15, 0x75,
484 0x7b, 0x4a, 0x69, 0xcf, 0x0a, 0xc7, 0x80, 0x01,
485 0xe7, 0x94, 0x16, 0x7f, 0x8d, 0x3c, 0xfa, 0x1f,
486 0x05, 0x71, 0x76, 0x15, 0xb0, 0xf6, 0x61, 0x30,
487 0x58, 0x16, 0xbe, 0x1b, 0xd1, 0x93, 0xc4, 0x1a,
488 0x91, 0x0c, 0x48, 0xe2, 0x1c, 0x8e, 0xa5, 0xc5,
489 0xa7, 0x81, 0x44, 0x48, 0x3b, 0x10, 0xc2, 0x74,
490 0x07, 0xdf, 0xa8, 0xae, 0x57, 0xee, 0x7f, 0xe3,
491 0x6a
492 };
493
494 ret = TEST_ptr(bio = BIO_new_mem_buf(cms_data, sizeof(cms_data)))
495 && TEST_ptr(cms = d2i_CMS_bio(bio, NULL))
496 && TEST_true(CMS_verify(cms, NULL, NULL, NULL, NULL, flags))
497 && TEST_ptr(content = CMS_SignedData_verify(cms->d.signedData, NULL, NULL, NULL,
498 NULL, NULL, flags, NULL, NULL));
499 BIO_free(content);
500 CMS_ContentInfo_free(cms);
501 BIO_free(bio);
502 return ret && TEST_int_eq(ERR_peek_error(), 0);
503 }
504
read_all(BIO * bio,long * p_len)505 static unsigned char *read_all(BIO *bio, long *p_len)
506 {
507 const int step = 256;
508 unsigned char *buf = NULL;
509 unsigned char *tmp = NULL;
510 int ret;
511
512 *p_len = 0;
513 for (;;) {
514 tmp = OPENSSL_realloc(buf, *p_len + step);
515 if (tmp == NULL)
516 break;
517 buf = tmp;
518 ret = BIO_read(bio, buf + *p_len, step);
519 if (ret < 0)
520 break;
521
522 if (LONG_MAX - ret < *p_len)
523 break;
524
525 *p_len += ret;
526
527 if (ret < step)
528 return buf;
529 }
530
531 /* Error */
532 OPENSSL_free(buf);
533 *p_len = 0;
534 return NULL;
535 }
536
test_d2i_CMS_decode(const int idx)537 static int test_d2i_CMS_decode(const int idx)
538 {
539 BIO *bio = NULL;
540 CMS_ContentInfo *cms = NULL;
541 unsigned char *buf = NULL;
542 const unsigned char *tmp = NULL;
543 long buf_len = 0;
544 int ret = 0;
545
546 if (!TEST_ptr(bio = BIO_new_file(derin, "r")))
547 goto end;
548
549 switch (idx) {
550 case 0:
551 if (!TEST_ptr(cms = d2i_CMS_bio(bio, NULL)))
552 goto end;
553 break;
554 case 1:
555 if (!TEST_ptr(buf = read_all(bio, &buf_len)))
556 goto end;
557 tmp = buf;
558 if (!TEST_ptr(cms = d2i_CMS_ContentInfo(NULL, &tmp, buf_len)))
559 goto end;
560 break;
561 }
562
563 if (!TEST_int_eq(ERR_peek_error(), 0))
564 goto end;
565
566 ret = 1;
567 end:
568 CMS_ContentInfo_free(cms);
569 BIO_free(bio);
570 OPENSSL_free(buf);
571
572 return ret;
573 }
574
test_CMS_set1_key_mem_leak(void)575 static int test_CMS_set1_key_mem_leak(void)
576 {
577 CMS_ContentInfo *cms;
578 unsigned char key[32] = { 0 };
579 int ret = 0;
580
581 if (!TEST_ptr(cms = CMS_ContentInfo_new()))
582 return 0;
583
584 if (!TEST_true(CMS_EncryptedData_set1_key(cms, EVP_aes_256_cbc(),
585 key, 32)))
586 goto end;
587
588 if (!TEST_true(CMS_EncryptedData_set1_key(cms, EVP_aes_128_cbc(),
589 key, 16)))
590 goto end;
591
592 ret = 1;
593 end:
594 CMS_ContentInfo_free(cms);
595 return ret;
596 }
597
test_encrypted_data(void)598 static int test_encrypted_data(void)
599 {
600 const char *msg = "Hello world";
601 BIO *msgbio = BIO_new_mem_buf(msg, (int)strlen(msg));
602 uint8_t key[16] = { 0 };
603 size_t keylen = 16;
604 CMS_ContentInfo *cms;
605 BIO *decryptbio = BIO_new(BIO_s_mem());
606 char buf[80];
607 int ret = 0;
608
609 cms = CMS_EncryptedData_encrypt(msgbio, EVP_aes_128_cbc(), key, keylen, SMIME_BINARY);
610 if (!TEST_ptr(cms))
611 goto end;
612
613 if (!TEST_true(CMS_EncryptedData_decrypt(cms, key, keylen, NULL, decryptbio, SMIME_BINARY)))
614 goto end;
615
616 /* Check we got the message we first started with */
617 if (!TEST_int_eq(BIO_gets(decryptbio, buf, sizeof(buf)), (int)strlen(msg))
618 || !TEST_int_eq(strcmp(buf, msg), 0))
619 goto end;
620
621 ret = 1;
622 end:
623 CMS_ContentInfo_free(cms);
624 BIO_free(msgbio);
625 BIO_free(decryptbio);
626 return ret;
627 }
628
test_encrypted_data_aead(void)629 static int test_encrypted_data_aead(void)
630 {
631 const char *msg = "Hello world";
632 BIO *msgbio = BIO_new_mem_buf(msg, (int)strlen(msg));
633 uint8_t key[16] = { 0 };
634 size_t keylen = 16;
635 CMS_ContentInfo *cms;
636 BIO *decryptbio = BIO_new(BIO_s_mem());
637 int ret = 0;
638
639 cms = CMS_ContentInfo_new();
640 if (!TEST_ptr(cms))
641 goto end;
642
643 /*
644 * AEAD algorithms are not supported by the CMS EncryptedData so setting
645 * the cipher to AES GCM 128 will result in a failure
646 */
647 if (!TEST_false(CMS_EncryptedData_set1_key(cms, EVP_aes_128_gcm(), key, keylen)))
648 goto end;
649
650 CMS_ContentInfo_free(cms);
651 cms = NULL;
652
653 /*
654 * AEAD algorithms are not supported by the CMS EncryptedData so setting
655 * the cipher to AES GCM 128 will result in a failure
656 */
657 cms = CMS_EncryptedData_encrypt(msgbio, EVP_aes_128_gcm(), key, keylen, SMIME_BINARY);
658 if (!TEST_ptr_null(cms))
659 goto end;
660
661 ret = 1;
662
663 end:
664 CMS_ContentInfo_free(cms);
665 BIO_free(msgbio);
666 BIO_free(decryptbio);
667 return ret;
668 }
669
test_cms_aesgcm_iv_too_long(void)670 static int test_cms_aesgcm_iv_too_long(void)
671 {
672 int ret = 0;
673 BIO *cmsbio = NULL, *out = NULL;
674 CMS_ContentInfo *cms = NULL;
675 unsigned long err = 0;
676
677 if (!TEST_ptr(cmsbio = BIO_new_file(too_long_iv_cms_in, "r")))
678 goto end;
679
680 if (!TEST_ptr(cms = PEM_read_bio_CMS(cmsbio, NULL, NULL, NULL)))
681 goto end;
682
683 /* Must fail cleanly (no crash) */
684 if (!TEST_false(CMS_decrypt(cms, privkey, cert, NULL, out, 0)))
685 goto end;
686 err = ERR_peek_last_error();
687 if (!TEST_ulong_ne(err, 0))
688 goto end;
689 if (!TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_CMS))
690 goto end;
691 if (!TEST_int_eq(ERR_GET_REASON(err), CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR))
692 goto end;
693
694 ret = 1;
695 end:
696 CMS_ContentInfo_free(cms);
697 BIO_free(cmsbio);
698 BIO_free(out);
699 return ret;
700 }
701
702 /*
703 * CMS EnvelopedData with a single PasswordRecipientInfo using
704 * id-alg-PWRI-KEK and an AES-128-CFB key encryption cipher
705 * (1-byte effective block size). The encryptedKey OCTET STRING is
706 * only two bytes long, so the wrapped key buffer is shorter than
707 * the seven octets read by the check-byte test in kek_unwrap_key().
708 * Prior to CVE-2026-9076 this triggered an out-of-bounds heap read;
709 * CMS_decrypt() must now fail cleanly.
710 */
test_pwri_kek_unwrap_short_encrypted_key(void)711 static int test_pwri_kek_unwrap_short_encrypted_key(void)
712 {
713 BIO *in = NULL;
714 CMS_ContentInfo *cms = NULL;
715 unsigned long err = 0;
716 int ret = 0;
717
718 if (!TEST_ptr(in = BIO_new_file(pwri_kek_oob_der_in, "rb"))
719 || !TEST_ptr(cms = d2i_CMS_bio(in, NULL)))
720 goto end;
721
722 /*
723 * The unwrap is attempted eagerly inside CMS_decrypt_set1_password().
724 * It must fail cleanly (no OOB read) and report CMS_R_UNWRAP_FAILURE.
725 */
726 if (!TEST_false(CMS_decrypt_set1_password(cms,
727 (unsigned char *)"password", -1)))
728 goto end;
729
730 err = ERR_peek_last_error();
731 if (!TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_CMS)
732 || !TEST_int_eq(ERR_GET_REASON(err), CMS_R_UNWRAP_FAILURE))
733 goto end;
734
735 ERR_clear_error();
736 ret = 1;
737 end:
738 CMS_ContentInfo_free(cms);
739 BIO_free(in);
740 return ret;
741 }
742
743 #ifndef OPENSSL_NO_EC
744
745 /*
746 * Regression test for CVE-2026-63072: an 8-byte out-of-bounds heap write
747 * reachable through CMS_decrypt() when a KeyAgreeRecipientInfo names an
748 * id-aesNNN-wrap-pad key-wrap OID. CMS sizes the unwrap output buffer from
749 * the cipher's length query (inlen - 8), but AES-WRAP-PAD unwrap cleanses
750 * inlen bytes of it on every RFC 5649 integrity-failure path.
751 *
752 * We build a valid ECDH KARI message (which uses non-padded id-aes256-wrap),
753 * flip the single OID byte an attacker would flip on the wire to turn it into
754 * id-aes256-wrap-pad (key length unchanged), and decrypt with the matching
755 * private key. The unwrap must fail its integrity check without writing past
756 * the CMS-allocated buffer; CMS_decrypt() must fail cleanly. Under a
757 * memory-checking build (e.g. valgrind) the overflow is flagged directly.
758 */
test_kari_wrap_pad_unwrap_overflow(void)759 static int test_kari_wrap_pad_unwrap_overflow(void)
760 {
761 /* DER encoding of the id-aes256-wrap OID (2.16.840.1.101.3.4.1.45). */
762 static const unsigned char aes256_wrap_oid[] = {
763 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d
764 };
765 int ret = 0;
766 X509 *eccert = NULL;
767 EVP_PKEY *eckey = NULL;
768 BIO *certbio = NULL, *keybio = NULL, *msgbio = NULL, *outbio = NULL;
769 STACK_OF(X509) *recips = NULL;
770 CMS_ContentInfo *cms = NULL, *cms2 = NULL;
771 unsigned char *der = NULL;
772 const unsigned char *p;
773 int derlen, i, patched = 0;
774 const char *msg = "secret content for kari";
775
776 if ((certbio = BIO_new_file(ec_recip_in, "r")) == NULL
777 || PEM_read_bio_X509(certbio, &eccert, NULL, NULL) == NULL
778 || (keybio = BIO_new_file(ec_recip_in, "r")) == NULL
779 || PEM_read_bio_PrivateKey(keybio, &eckey, NULL, NULL) == NULL) {
780 goto end;
781 }
782
783 if (!TEST_ptr(recips = sk_X509_new_null())
784 || !TEST_int_gt(sk_X509_push(recips, eccert), 0))
785 goto end;
786
787 /* Build a normal ECDH KARI message; it uses non-padded id-aes256-wrap. */
788 if (!TEST_ptr(msgbio = BIO_new_mem_buf(msg, (int)strlen(msg)))
789 || !TEST_ptr(cms = CMS_encrypt(recips, msgbio, EVP_aes_256_cbc(),
790 CMS_BINARY)))
791 goto end;
792
793 if (!TEST_int_gt(derlen = i2d_CMS_ContentInfo(cms, &der), 0))
794 goto end;
795
796 /* Swap id-aes256-wrap -> id-aes256-wrap-pad (0x2d -> 0x30). */
797 for (i = 0; i + (int)sizeof(aes256_wrap_oid) <= derlen; i++) {
798 if (memcmp(der + i, aes256_wrap_oid, sizeof(aes256_wrap_oid)) == 0) {
799 der[i + sizeof(aes256_wrap_oid) - 1] = 0x30;
800 patched = 1;
801 break;
802 }
803 }
804 if (!TEST_true(patched))
805 goto end;
806
807 p = der;
808 if (!TEST_ptr(cms2 = d2i_CMS_ContentInfo(NULL, &p, derlen)))
809 goto end;
810
811 /*
812 * The wrap-pad unwrap fails the AIV check; with the fix it does so without
813 * writing past the CMS-allocated buffer. CMS_decrypt() must fail cleanly.
814 */
815 if (!TEST_ptr(outbio = BIO_new(BIO_s_mem()))
816 || !TEST_false(CMS_decrypt(cms2, eckey, eccert, NULL, outbio, 0)))
817 goto end;
818
819 ret = 1;
820 end:
821 ERR_clear_error();
822 OPENSSL_free(der);
823 sk_X509_free(recips);
824 CMS_ContentInfo_free(cms);
825 CMS_ContentInfo_free(cms2);
826 BIO_free(certbio);
827 BIO_free(keybio);
828 BIO_free(msgbio);
829 BIO_free(outbio);
830 X509_free(eccert);
831 EVP_PKEY_free(eckey);
832 return ret;
833 }
834 #endif
835
836 OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer ecrecip\n")
837
setup_tests(void)838 int setup_tests(void)
839 {
840 char *certin = NULL, *privkeyin = NULL;
841 BIO *certbio = NULL, *privkeybio = NULL;
842
843 if (!test_skip_common_options()) {
844 TEST_error("Error parsing test options\n");
845 return 0;
846 }
847
848 if (!TEST_ptr(certin = test_get_argument(0))
849 || !TEST_ptr(privkeyin = test_get_argument(1))
850 || !TEST_ptr(derin = test_get_argument(2))
851 || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3))
852 || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4))
853 || !TEST_ptr(ec_recip_in = test_get_argument(5)))
854 return 0;
855
856 certbio = BIO_new_file(certin, "r");
857 if (!TEST_ptr(certbio))
858 return 0;
859 if (!TEST_true(PEM_read_bio_X509(certbio, &cert, NULL, NULL))) {
860 BIO_free(certbio);
861 return 0;
862 }
863 BIO_free(certbio);
864
865 privkeybio = BIO_new_file(privkeyin, "r");
866 if (!TEST_ptr(privkeybio)) {
867 X509_free(cert);
868 cert = NULL;
869 return 0;
870 }
871 if (!TEST_true(PEM_read_bio_PrivateKey(privkeybio, &privkey, NULL, NULL))) {
872 BIO_free(privkeybio);
873 X509_free(cert);
874 cert = NULL;
875 return 0;
876 }
877 BIO_free(privkeybio);
878
879 ADD_TEST(test_encrypt_decrypt_aes_cbc);
880 ADD_TEST(test_encrypt_decrypt_aes_128_gcm);
881 ADD_TEST(test_encrypt_decrypt_aes_192_gcm);
882 ADD_TEST(test_encrypt_decrypt_aes_256_gcm);
883 ADD_TEST(test_non_aead_on_auth_envelope_enc);
884 ADD_TEST(test_non_aead_on_auth_envelope_dec);
885 ADD_TEST(test_short_mac_on_auth_envelope_data);
886 ADD_TEST(test_CMS_add1_cert);
887 ADD_TEST(test_d2i_CMS_bio_NULL);
888 ADD_TEST(test_CMS_set1_key_mem_leak);
889 ADD_TEST(test_encrypted_data);
890 ADD_TEST(test_encrypted_data_aead);
891 ADD_ALL_TESTS(test_d2i_CMS_decode, 2);
892 ADD_TEST(test_cms_aesgcm_iv_too_long);
893 ADD_TEST(test_pwri_kek_unwrap_short_encrypted_key);
894
895 #ifndef OPENSSL_NO_EC
896 ADD_TEST(test_kari_wrap_pad_unwrap_overflow);
897 #endif
898 return 1;
899 }
900
cleanup_tests(void)901 void cleanup_tests(void)
902 {
903 X509_free(cert);
904 EVP_PKEY_free(privkey);
905 }
906