@@ -1114,6 +1114,44 @@ static int add_encrypted_data(CBB *out, int pbe_nid, const char *password,
1114
1114
return ret ;
1115
1115
}
1116
1116
1117
+ static int pkcs12_gen_and_write_mac (CBB * out_pfx , const uint8_t * auth_safe_data ,
1118
+ size_t auth_safe_data_len ,
1119
+ const char * password , size_t password_len ,
1120
+ uint8_t * mac_salt , size_t salt_len ,
1121
+ int mac_iterations , const EVP_MD * md ) {
1122
+ int ret = 0 ;
1123
+ uint8_t mac_key [EVP_MAX_MD_SIZE ];
1124
+ uint8_t mac [EVP_MAX_MD_SIZE ];
1125
+ unsigned mac_len ;
1126
+ if (!pkcs12_key_gen (password , password_len , mac_salt , salt_len , PKCS12_MAC_ID ,
1127
+ mac_iterations , EVP_MD_size (md ), mac_key , md ) ||
1128
+ !HMAC (md , mac_key , EVP_MD_size (md ), auth_safe_data , auth_safe_data_len ,
1129
+ mac , & mac_len )) {
1130
+ goto out ;
1131
+ }
1132
+
1133
+ CBB mac_data , digest_info , mac_cbb , mac_salt_cbb ;
1134
+ if (!CBB_add_asn1 (out_pfx , & mac_data , CBS_ASN1_SEQUENCE ) ||
1135
+ !CBB_add_asn1 (& mac_data , & digest_info , CBS_ASN1_SEQUENCE ) ||
1136
+ !EVP_marshal_digest_algorithm (& digest_info , md ) ||
1137
+ !CBB_add_asn1 (& digest_info , & mac_cbb , CBS_ASN1_OCTETSTRING ) ||
1138
+ !CBB_add_bytes (& mac_cbb , mac , mac_len ) ||
1139
+ !CBB_add_asn1 (& mac_data , & mac_salt_cbb , CBS_ASN1_OCTETSTRING ) ||
1140
+ !CBB_add_bytes (& mac_salt_cbb , mac_salt , salt_len ) ||
1141
+ // The iteration count has a DEFAULT of 1, but RFC 7292 says "The default
1142
+ // is for historical reasons and its use is deprecated." Thus we
1143
+ // explicitly encode the iteration count, though it is not valid DER.
1144
+ !CBB_add_asn1_uint64 (& mac_data , mac_iterations ) ||
1145
+ !CBB_flush (out_pfx )) {
1146
+ goto out ;
1147
+ }
1148
+ ret = 1 ;
1149
+
1150
+ out :
1151
+ OPENSSL_cleanse (mac_key , sizeof (mac_key ));
1152
+ return ret ;
1153
+ }
1154
+
1117
1155
PKCS12 * PKCS12_create (const char * password , const char * name ,
1118
1156
const EVP_PKEY * pkey , X509 * cert ,
1119
1157
const STACK_OF (X509 )* chain , int key_nid , int cert_nid ,
@@ -1194,9 +1232,7 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
1194
1232
PKCS12 * ret = NULL ;
1195
1233
CBB cbb , pfx , auth_safe , auth_safe_oid , auth_safe_wrapper , auth_safe_data ,
1196
1234
content_infos ;
1197
- uint8_t mac_key [EVP_MAX_MD_SIZE ];
1198
- if (!CBB_init (& cbb , 0 ) ||
1199
- !CBB_add_asn1 (& cbb , & pfx , CBS_ASN1_SEQUENCE ) ||
1235
+ if (!CBB_init (& cbb , 0 ) || !CBB_add_asn1 (& cbb , & pfx , CBS_ASN1_SEQUENCE ) ||
1200
1236
!CBB_add_asn1_uint64 (& pfx , 3 ) ||
1201
1237
// auth_safe is a data ContentInfo.
1202
1238
!CBB_add_asn1 (& pfx , & auth_safe , CBS_ASN1_SEQUENCE ) ||
@@ -1301,30 +1337,11 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
1301
1337
// covers |auth_safe_data|.
1302
1338
const EVP_MD * mac_md = EVP_sha1 ();
1303
1339
uint8_t mac_salt [PKCS5_SALT_LEN ];
1304
- uint8_t mac [EVP_MAX_MD_SIZE ];
1305
- unsigned mac_len ;
1306
1340
if (!CBB_flush (& auth_safe_data ) ||
1307
1341
!RAND_bytes (mac_salt , sizeof (mac_salt )) ||
1308
- !pkcs12_key_gen (password , password_len , mac_salt , sizeof (mac_salt ),
1309
- PKCS12_MAC_ID , mac_iterations , EVP_MD_size (mac_md ),
1310
- mac_key , mac_md ) ||
1311
- !HMAC (mac_md , mac_key , EVP_MD_size (mac_md ), CBB_data (& auth_safe_data ),
1312
- CBB_len (& auth_safe_data ), mac , & mac_len )) {
1313
- goto err ;
1314
- }
1315
-
1316
- CBB mac_data , digest_info , mac_cbb , mac_salt_cbb ;
1317
- if (!CBB_add_asn1 (& pfx , & mac_data , CBS_ASN1_SEQUENCE ) ||
1318
- !CBB_add_asn1 (& mac_data , & digest_info , CBS_ASN1_SEQUENCE ) ||
1319
- !EVP_marshal_digest_algorithm (& digest_info , mac_md ) ||
1320
- !CBB_add_asn1 (& digest_info , & mac_cbb , CBS_ASN1_OCTETSTRING ) ||
1321
- !CBB_add_bytes (& mac_cbb , mac , mac_len ) ||
1322
- !CBB_add_asn1 (& mac_data , & mac_salt_cbb , CBS_ASN1_OCTETSTRING ) ||
1323
- !CBB_add_bytes (& mac_salt_cbb , mac_salt , sizeof (mac_salt )) ||
1324
- // The iteration count has a DEFAULT of 1, but RFC 7292 says "The default
1325
- // is for historical reasons and its use is deprecated." Thus we
1326
- // explicitly encode the iteration count, though it is not valid DER.
1327
- !CBB_add_asn1_uint64 (& mac_data , mac_iterations )) {
1342
+ !pkcs12_gen_and_write_mac (
1343
+ & pfx , CBB_data (& auth_safe_data ), CBB_len (& auth_safe_data ), password ,
1344
+ password_len , mac_salt , sizeof (mac_salt ), mac_iterations , mac_md )) {
1328
1345
goto err ;
1329
1346
}
1330
1347
@@ -1337,7 +1354,6 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
1337
1354
}
1338
1355
1339
1356
err :
1340
- OPENSSL_cleanse (mac_key , sizeof (mac_key ));
1341
1357
CBB_cleanup (& cbb );
1342
1358
return ret ;
1343
1359
}
@@ -1353,3 +1369,98 @@ void PKCS12_free(PKCS12 *p12) {
1353
1369
OPENSSL_free (p12 -> ber_bytes );
1354
1370
OPENSSL_free (p12 );
1355
1371
}
1372
+
1373
+ int PKCS12_set_mac (PKCS12 * p12 , const char * password , int password_len ,
1374
+ unsigned char * salt , int salt_len , int mac_iterations ,
1375
+ const EVP_MD * md ) {
1376
+ GUARD_PTR (p12 );
1377
+ int ret = 0 ;
1378
+
1379
+ if (mac_iterations == 0 ) {
1380
+ mac_iterations = 1 ;
1381
+ }
1382
+ if (salt_len == 0 ) {
1383
+ salt_len = PKCS5_SALT_LEN ;
1384
+ }
1385
+ // Generate |mac_salt| if |salt| is NULL and copy if NULL.
1386
+ uint8_t * mac_salt = OPENSSL_malloc (salt_len );
1387
+ if (salt == NULL ) {
1388
+ if (!RAND_bytes (mac_salt , salt_len )) {
1389
+ goto out ;
1390
+ }
1391
+ } else {
1392
+ OPENSSL_memcpy (mac_salt , salt , salt_len );
1393
+ }
1394
+ // Match OpenSSL in using SHA-1 as the default hash function.
1395
+ if (md == NULL ) {
1396
+ md = EVP_sha1 ();
1397
+ }
1398
+
1399
+ uint8_t * storage = NULL ;
1400
+ CBS ber_bytes , in , pfx , authsafe , content_type , wrapped_authsafes , authsafes ;
1401
+ uint64_t version ;
1402
+ // The input may be in BER format.
1403
+ CBS_init (& ber_bytes , p12 -> ber_bytes , p12 -> ber_len );
1404
+ if (!CBS_asn1_ber_to_der (& ber_bytes , & in , & storage )) {
1405
+ OPENSSL_PUT_ERROR (PKCS8 , PKCS8_R_BAD_PKCS12_DATA );
1406
+ goto out ;
1407
+ }
1408
+ // There's no use case for |storage| anymore, so we free early.
1409
+ OPENSSL_free (storage );
1410
+
1411
+ if (!CBS_get_asn1 (& in , & pfx , CBS_ASN1_SEQUENCE ) || CBS_len (& in ) != 0 ||
1412
+ !CBS_get_asn1_uint64 (& pfx , & version )) {
1413
+ OPENSSL_PUT_ERROR (PKCS8 , PKCS8_R_BAD_PKCS12_DATA );
1414
+ goto out ;
1415
+ }
1416
+ if (version < 3 ) {
1417
+ OPENSSL_PUT_ERROR (PKCS8 , PKCS8_R_BAD_PKCS12_VERSION );
1418
+ goto out ;
1419
+ }
1420
+
1421
+ if (!CBS_get_asn1 (& pfx , & authsafe , CBS_ASN1_SEQUENCE )) {
1422
+ OPENSSL_PUT_ERROR (PKCS8 , PKCS8_R_BAD_PKCS12_DATA );
1423
+ goto out ;
1424
+ }
1425
+ // Save contents of |authsafe| to write back before the CBS is advanced.
1426
+ const uint8_t * orig_authsafe = CBS_data (& authsafe );
1427
+ size_t orig_authsafe_len = CBS_len (& authsafe );
1428
+
1429
+ // Parse for |authsafes| which is the data that we should be running HMAC on.
1430
+ if (!CBS_get_asn1 (& authsafe , & content_type , CBS_ASN1_OBJECT ) ||
1431
+ !CBS_get_asn1 (& authsafe , & wrapped_authsafes ,
1432
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0 ) ||
1433
+ !CBS_get_asn1 (& wrapped_authsafes , & authsafes , CBS_ASN1_OCTETSTRING )) {
1434
+ OPENSSL_PUT_ERROR (PKCS8 , PKCS8_R_BAD_PKCS12_DATA );
1435
+ goto out ;
1436
+ }
1437
+
1438
+ // Rewrite contents of |p12| with the original contents and updated MAC.
1439
+ CBB cbb , out_pfx , out_auth_safe ;
1440
+ if (!CBB_init (& cbb , 0 ) || !CBB_add_asn1 (& cbb , & out_pfx , CBS_ASN1_SEQUENCE ) ||
1441
+ !CBB_add_asn1_uint64 (& out_pfx , version ) ||
1442
+ !CBB_add_asn1 (& out_pfx , & out_auth_safe , CBS_ASN1_SEQUENCE ) ||
1443
+ !CBB_add_bytes (& out_auth_safe , orig_authsafe , orig_authsafe_len ) ||
1444
+ !pkcs12_gen_and_write_mac (& out_pfx , CBS_data (& authsafes ),
1445
+ CBS_len (& authsafes ), password , password_len ,
1446
+ mac_salt , salt_len , mac_iterations , md )) {
1447
+ CBB_cleanup (& cbb );
1448
+ goto out ;
1449
+ }
1450
+
1451
+ // Verify that the new password is consistent with the original. This is
1452
+ // behavior specific to AWS-LC.
1453
+ OPENSSL_free (p12 -> ber_bytes );
1454
+ if (!CBB_finish (& cbb , & p12 -> ber_bytes , & p12 -> ber_len ) ||
1455
+ !PKCS12_verify_mac (p12 , password , password_len )) {
1456
+ CBB_cleanup (& cbb );
1457
+ goto out ;
1458
+ }
1459
+
1460
+ ret = 1 ;
1461
+
1462
+ out :
1463
+ OPENSSL_free (mac_salt );
1464
+ return ret ;
1465
+ }
1466
+
0 commit comments