/** * gnutls_pkcs12_verify_mac: * @pkcs12: should contain a gnutls_pkcs12_t structure * @pass: The password for the MAC * * This function will verify the MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_verify_mac (gnutls_pkcs12_t pkcs12, const char *pass) { opaque key[20]; int result; unsigned int iter; int len; digest_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }, salt = { NULL, 0}; opaque sha_mac[20]; opaque sha_mac_orig[20]; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* read the iterations */ result = _gnutls_x509_read_uint (pkcs12->pkcs12, "macData.iterations", &iter); if (result < 0) { iter = 1; /* the default */ } /* Read the salt from the structure. */ result = _gnutls_x509_read_value (pkcs12->pkcs12, "macData.macSalt", &salt, 0); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key (3 /*MAC*/, salt.data, salt.size, iter, pass, sizeof (key), key); if (result < 0) { gnutls_assert (); goto cleanup; } _gnutls_free_datum (&salt); /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert (); goto cleanup; } /* MAC the data */ result = _gnutls_hmac_init (&td1, GNUTLS_MAC_SHA1, key, sizeof (key)); if (result < 0) { gnutls_assert (); goto cleanup; } _gnutls_hmac (&td1, tmp.data, tmp.size); _gnutls_free_datum (&tmp); _gnutls_hmac_deinit (&td1, sha_mac); len = sizeof (sha_mac_orig); result = asn1_read_value (pkcs12->pkcs12, "macData.mac.digest", sha_mac_orig, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (memcmp (sha_mac_orig, sha_mac, sizeof (sha_mac)) != 0) { gnutls_assert (); return GNUTLS_E_MAC_VERIFY_FAILED; } return 0; cleanup: _gnutls_free_datum (&tmp); _gnutls_free_datum (&salt); return result; }
/** * gnutls_pkcs12_generate_mac: * @pkcs12: should contain a gnutls_pkcs12_t structure * @pass: The password for the MAC * * This function will generate a MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_generate_mac (gnutls_pkcs12_t pkcs12, const char *pass) { opaque salt[8], key[20]; int result; const int iter = 1; digest_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }; opaque sha_mac[20]; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* Generate the salt. */ result = _gnutls_rnd (GNUTLS_RND_NONCE, salt, sizeof (salt)); if (result < 0) { gnutls_assert (); return result; } /* Write the salt into the structure. */ result = asn1_write_value (pkcs12->pkcs12, "macData.macSalt", salt, sizeof (salt)); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* write the iterations */ if (iter > 1) { result = _gnutls_x509_write_uint32 (pkcs12->pkcs12, "macData.iterations", iter); if (result < 0) { gnutls_assert (); goto cleanup; } } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key (3 /*MAC*/, salt, sizeof (salt), iter, pass, sizeof (key), key); if (result < 0) { gnutls_assert (); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert (); goto cleanup; } /* MAC the data */ result = _gnutls_hmac_init (&td1, GNUTLS_MAC_SHA1, key, sizeof (key)); if (result < 0) { gnutls_assert (); goto cleanup; } _gnutls_hmac (&td1, tmp.data, tmp.size); _gnutls_free_datum (&tmp); _gnutls_hmac_deinit (&td1, sha_mac); result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digest", sha_mac, sizeof (sha_mac)); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digestAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", HASH_OID_SHA1, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } return 0; cleanup: _gnutls_free_datum (&tmp); return result; }
/** * gnutls_pkcs12_set_bag: * @pkcs12: should contain a gnutls_pkcs12_t structure * @bag: An initialized bag * * This function will insert a Bag into the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_set_bag (gnutls_pkcs12_t pkcs12, gnutls_pkcs12_bag_t bag) { ASN1_TYPE c2 = ASN1_TYPE_EMPTY; ASN1_TYPE safe_cont = ASN1_TYPE_EMPTY; int result; int enc = 0, dum = 1; char null; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* Step 1. Check if the pkcs12 structure is empty. In that * case generate an empty PFX. */ result = asn1_read_value (pkcs12->pkcs12, "authSafe.content", &null, &dum); if (result == ASN1_VALUE_NOT_FOUND) { result = create_empty_pfx (pkcs12->pkcs12); if (result < 0) { gnutls_assert (); return result; } } /* Step 2. decode the authenticatedSafe. */ result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, &c2, NULL); if (result < 0) { gnutls_assert (); return result; } /* Step 3. Encode the bag elements into a SafeContents * structure. */ result = _pkcs12_encode_safe_contents (bag, &safe_cont, &enc); if (result < 0) { gnutls_assert (); return result; } /* Step 4. Insert the encoded SafeContents into the AuthenticatedSafe * structure. */ result = asn1_write_value (c2, "", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (enc) result = asn1_write_value (c2, "?LAST.contentType", ENC_DATA_OID, 1); else result = asn1_write_value (c2, "?LAST.contentType", DATA_OID, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (enc) { /* Encrypted packets are written directly. */ result = asn1_write_value (c2, "?LAST.content", bag->element[0].data.data, bag->element[0].data.size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } } else { result = _gnutls_x509_der_encode_and_copy (safe_cont, "", c2, "?LAST.content", 1); if (result < 0) { gnutls_assert (); goto cleanup; } } asn1_delete_structure (&safe_cont); /* Step 5. Reencode and copy the AuthenticatedSafe into the pkcs12 * structure. */ result = _gnutls_x509_der_encode_and_copy (c2, "", pkcs12->pkcs12, "authSafe.content", 1); if (result < 0) { gnutls_assert (); goto cleanup; } asn1_delete_structure (&c2); return 0; cleanup: asn1_delete_structure (&c2); asn1_delete_structure (&safe_cont); return result; }
/** * gnutls_pkcs12_get_bag: * @pkcs12: should contain a gnutls_pkcs12_t structure * @indx: contains the index of the bag to extract * @bag: An initialized bag, where the contents of the bag will be copied * * This function will return a Bag from the PKCS12 structure. * * After the last Bag has been read * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_get_bag (gnutls_pkcs12_t pkcs12, int indx, gnutls_pkcs12_bag_t bag) { ASN1_TYPE c2 = ASN1_TYPE_EMPTY; int result, len; char root2[ASN1_MAX_NAME_SIZE]; char oid[MAX_OID_SIZE]; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* Step 1. decode the data. */ result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, &c2, NULL); if (result < 0) { gnutls_assert (); return result; } /* Step 2. Parse the AuthenticatedSafe */ snprintf (root2, sizeof (root2), "?%u.contentType", indx + 1); len = sizeof (oid) - 1; result = asn1_read_value (c2, root2, oid, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto cleanup; } if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Not encrypted Bag */ snprintf (root2, sizeof (root2), "?%u.content", indx + 1); if (strcmp (oid, DATA_OID) == 0) { result = _parse_safe_contents (c2, root2, bag); goto cleanup; } /* ENC_DATA_OID needs decryption */ bag->element[0].type = GNUTLS_BAG_ENCRYPTED; bag->bag_elements = 1; result = _gnutls_x509_read_value (c2, root2, &bag->element[0].data, 0); if (result < 0) { gnutls_assert (); goto cleanup; } result = 0; cleanup: if (c2) asn1_delete_structure (&c2); return result; }
/** * gnutls_pkcs12_generate_mac2: * @pkcs12: A pkcs12 type * @mac: the MAC algorithm to use * @pass: The password for the MAC * * This function will generate a MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t mac, const char *pass) { uint8_t salt[8], key[MAX_HASH_SIZE]; int result; const int iter = 10*1024; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }; unsigned mac_size, key_len; uint8_t mac_out[MAX_HASH_SIZE]; const mac_entry_st *me = mac_to_entry(mac); if (pkcs12 == NULL || me == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (me->oid == NULL) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); mac_size = _gnutls_mac_get_algo_len(me); key_len = mac_size; /* Generate the salt. */ result = gnutls_rnd(GNUTLS_RND_NONCE, salt, sizeof(salt)); if (result < 0) { gnutls_assert(); return result; } /* Write the salt into the structure. */ result = asn1_write_value(pkcs12->pkcs12, "macData.macSalt", salt, sizeof(salt)); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* write the iterations */ if (iter > 1) { result = _gnutls_x509_write_uint32(pkcs12->pkcs12, "macData.iterations", iter); if (result < 0) { gnutls_assert(); goto cleanup; } } /* Generate the key. */ #if ENABLE_GOST if (me->id == GNUTLS_MAC_GOSTR_94 || me->id == GNUTLS_MAC_STREEBOG_256 || me->id == GNUTLS_MAC_STREEBOG_512) { key_len = 32; result = _gnutls_pkcs12_gost_string_to_key(me->id, salt, sizeof(salt), iter, pass, mac_size, key); } else #endif result = _gnutls_pkcs12_string_to_key(me, 3 /*MAC*/, salt, sizeof(salt), iter, pass, mac_size, key); if (result < 0) { gnutls_assert(); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } /* MAC the data */ result = _gnutls_mac_init(&td1, me, key, key_len); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_free_datum(&tmp); _gnutls_mac_deinit(&td1, mac_out); result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digest", mac_out, mac_size); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", me->oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } return 0; cleanup: _gnutls_free_datum(&tmp); return result; }
/** * gnutls_pkcs12_verify_mac: * @pkcs12: should contain a gnutls_pkcs12_t type * @pass: The password for the MAC * * This function will verify the MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass) { uint8_t key[MAX_HASH_SIZE]; char oid[MAX_OID_SIZE]; int result; unsigned int iter; int len; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }, salt = { NULL, 0}; uint8_t mac_output[MAX_HASH_SIZE]; uint8_t mac_output_orig[MAX_HASH_SIZE]; gnutls_mac_algorithm_t algo; unsigned mac_len, key_len; const mac_entry_st *entry; #if ENABLE_GOST int gost_retry = 0; #endif if (pkcs12 == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } /* read the iterations */ result = _gnutls_x509_read_uint(pkcs12->pkcs12, "macData.iterations", &iter); if (result < 0) { iter = 1; /* the default */ } len = sizeof(oid); result = asn1_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } algo = gnutls_oid_to_digest(oid); if (algo == GNUTLS_MAC_UNKNOWN) { unknown_mac: gnutls_assert(); return GNUTLS_E_UNKNOWN_HASH_ALGORITHM; } entry = mac_to_entry(algo); if (entry == NULL) goto unknown_mac; mac_len = _gnutls_mac_get_algo_len(entry); key_len = mac_len; /* Read the salt from the structure. */ result = _gnutls_x509_read_null_value(pkcs12->pkcs12, "macData.macSalt", &salt); if (result < 0) { gnutls_assert(); goto cleanup; } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key(entry, 3 /*MAC*/, salt.data, salt.size, iter, pass, key_len, key); if (result < 0) { gnutls_assert(); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } #if ENABLE_GOST /* GOST PKCS#12 files use either PKCS#12 scheme or proprietary * HMAC-based scheme to generate MAC key. */ pkcs12_try_gost: #endif /* MAC the data */ result = _gnutls_mac_init(&td1, entry, key, key_len); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_mac_deinit(&td1, mac_output); len = sizeof(mac_output_orig); result = asn1_read_value(pkcs12->pkcs12, "macData.mac.digest", mac_output_orig, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if ((unsigned)len != mac_len || memcmp(mac_output_orig, mac_output, len) != 0) { #if ENABLE_GOST /* It is possible that GOST files use proprietary * key generation scheme */ if (!gost_retry && (algo == GNUTLS_MAC_GOSTR_94 || algo == GNUTLS_MAC_STREEBOG_256 || algo == GNUTLS_MAC_STREEBOG_512)) { gost_retry = 1; key_len = 32; result = _gnutls_pkcs12_gost_string_to_key(algo, salt.data, salt.size, iter, pass, key_len, key); if (result < 0) { gnutls_assert(); goto cleanup; } goto pkcs12_try_gost; } #endif gnutls_assert(); result = GNUTLS_E_MAC_VERIFY_FAILED; goto cleanup; } result = 0; cleanup: _gnutls_free_datum(&tmp); _gnutls_free_datum(&salt); return result; }