xref: /freebsd/crypto/openssl/test/cmsapitest.c (revision 78e936b2d0b5e6554425009199be31e76bc67c10)
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