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