summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2016-11-09 14:19:58 +0300
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2018-06-23 12:20:16 +0300
commited28242308c11cb4dddb930bf8bff22e1f5c8862 (patch)
treec70f1457dfaf8073e42dd7b9ee547c2cc34e9269
parentb8d3b99c4eedaa52537c9a2caf957e0215a7e313 (diff)
downloadgnutls-ed28242308c11cb4dddb930bf8bff22e1f5c8862.tar.gz
Add support for PKCS12 files using GOST MAC
Local PKCS12-based standard derives from RFC 7292 (PKCS #12) in using PBKDF2 to generate MAC key rather than using PKCS12 scheme. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-rw-r--r--lib/x509/pkcs12.c128
1 files changed, 116 insertions, 12 deletions
diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c
index 2b7b8d6402..7164820a8d 100644
--- a/lib/x509/pkcs12.c
+++ b/lib/x509/pkcs12.c
@@ -37,6 +37,10 @@
#include "x509_int.h"
#include "pkcs7_int.h"
#include <random.h>
+#include <nettle/pbkdf2.h>
+#if ENABLE_GOST
+#include "../nettle/gost/pbkdf2-gost.h"
+#endif
/* Decodes the PKCS #12 auth_safe, and returns the allocated raw data,
@@ -843,6 +847,53 @@ int gnutls_pkcs12_set_bag(gnutls_pkcs12_t pkcs12, gnutls_pkcs12_bag_t bag)
return result;
}
+#if ENABLE_GOST
+/*
+ * Russian differs from PKCS#12 here. It described proprietary way
+ * to obtain MAC key instead of using standard mechanism.
+ *
+ * See http://wwwold.tc26.ru/standard/rs/%D0%A0%2050.1.112-2016.pdf
+ * section 5.
+ */
+static int
+_gnutls_pkcs12_gost_string_to_key(gnutls_mac_algorithm_t algo,
+ const uint8_t * salt,
+ unsigned int salt_size, unsigned int iter,
+ const char *pass, unsigned int req_keylen,
+ uint8_t * keybuf)
+{
+ uint8_t temp[96];
+ size_t temp_len = sizeof(temp);
+ unsigned int pass_len = 0;
+
+ if (pass)
+ pass_len = strlen(pass);
+
+ if (algo == GNUTLS_MAC_GOSTR_94)
+ pbkdf2_hmac_gosthash94cp(pass_len, (uint8_t *) pass,
+ iter,
+ salt_size,
+ salt, temp_len, temp);
+ else if (algo == GNUTLS_MAC_STREEBOG_256)
+ pbkdf2_hmac_streebog256(pass_len, (uint8_t *) pass,
+ iter,
+ salt_size,
+ salt, temp_len, temp);
+ else if (algo == GNUTLS_MAC_STREEBOG_512)
+ pbkdf2_hmac_streebog512(pass_len, (uint8_t *) pass,
+ iter,
+ salt_size,
+ salt, temp_len, temp);
+ else
+ /* Should not reach here */
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ memcpy(keybuf, temp + temp_len - req_keylen, req_keylen);
+
+ return 0;
+}
+#endif
+
/**
* gnutls_pkcs12_generate_mac2:
* @pkcs12: A pkcs12 type
@@ -861,7 +912,7 @@ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t m
const int iter = 10*1024;
mac_hd_st td1;
gnutls_datum_t tmp = { NULL, 0 };
- unsigned mac_size;
+ unsigned mac_size, key_len;
uint8_t mac_out[MAX_HASH_SIZE];
const mac_entry_st *me = mac_to_entry(mac);
@@ -872,6 +923,7 @@ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t m
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
mac_size = _gnutls_mac_get_algo_len(me);
+ key_len = mac_size;
/* Generate the salt.
*/
@@ -907,9 +959,24 @@ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t m
/* Generate the key.
*/
- result =
- _gnutls_pkcs12_string_to_key(me, 3 /*MAC*/, salt, sizeof(salt),
- iter, pass, mac_size, 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;
@@ -926,7 +993,7 @@ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t m
/* MAC the data
*/
result = _gnutls_mac_init(&td1, me,
- key, mac_size);
+ key, key_len);
if (result < 0) {
gnutls_assert();
goto cleanup;
@@ -1014,6 +1081,9 @@ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
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();
@@ -1064,16 +1134,15 @@ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
/* Generate the key.
*/
- result =
- _gnutls_pkcs12_string_to_key(entry, 3 /*MAC*/, salt.data, salt.size,
- iter, pass, key_len, 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;
}
- _gnutls_free_datum(&salt);
-
/* Get the data to be MACed
*/
result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp);
@@ -1082,6 +1151,12 @@ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
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);
@@ -1091,7 +1166,6 @@ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
}
_gnutls_mac(&td1, tmp.data, tmp.size);
- _gnutls_free_datum(&tmp);
_gnutls_mac_deinit(&td1, mac_output);
@@ -1107,10 +1181,40 @@ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
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();
- return GNUTLS_E_MAC_VERIFY_FAILED;
+ result = GNUTLS_E_MAC_VERIFY_FAILED;
+ goto cleanup;
}
+ _gnutls_free_datum(&tmp);
+ _gnutls_free_datum(&salt);
+
return 0;
cleanup: