diff options
author | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2016-11-09 14:02:56 +0300 |
---|---|---|
committer | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2018-06-23 12:20:16 +0300 |
commit | b8d3b99c4eedaa52537c9a2caf957e0215a7e313 (patch) | |
tree | 73023f12297b1a48cca2a86efc311ed0592abdf0 | |
parent | 8062f19086f9e54e87359a3924072927e20104ee (diff) | |
download | gnutls-b8d3b99c4eedaa52537c9a2caf957e0215a7e313.tar.gz |
Add support for PBES2/PBKDF2 using GOST algorithms
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-rw-r--r-- | lib/includes/gnutls/x509.h | 17 | ||||
-rw-r--r-- | lib/pkix.asn | 6 | ||||
-rw-r--r-- | lib/pkix_asn1_tab.c | 3 | ||||
-rw-r--r-- | lib/x509/pkcs7-crypt.c | 233 | ||||
-rw-r--r-- | lib/x509/pkcs7_int.h | 6 |
5 files changed, 233 insertions, 32 deletions
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 7f9c29e253..cd54e8c4ca 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -1098,6 +1098,11 @@ unsigned gnutls_x509_crt_check_key_purpose(gnutls_x509_crt_t cert, * @GNUTLS_PKCS_PBES2_AES_256: PBES2 AES-256. * @GNUTLS_PKCS_PBES2_DES: PBES2 single DES. * @GNUTLS_PKCS_PBES2_DES_MD5: PBES1 with single DES; for compatibility with openssl only. + * @GNUTLS_PKCS_PBES2_GOST_TC26Z: PBES2 GOST 28147-89 CFB with TC26-Z S-box. + * @GNUTLS_PKCS_PBES2_GOST_CPA: PBES2 GOST 28147-89 CFB with CryptoPro-A S-box. + * @GNUTLS_PKCS_PBES2_GOST_CPB: PBES2 GOST 28147-89 CFB with CryptoPro-B S-box. + * @GNUTLS_PKCS_PBES2_GOST_CPC: PBES2 GOST 28147-89 CFB with CryptoPro-C S-box. + * @GNUTLS_PKCS_PBES2_GOST_CPD: PBES2 GOST 28147-89 CFB with CryptoPro-D S-box. * * Enumeration of different PKCS encryption flags. */ @@ -1112,7 +1117,12 @@ typedef enum gnutls_pkcs_encrypt_flags_t { GNUTLS_PKCS_PBES2_AES_256 = 1<<7, GNUTLS_PKCS_NULL_PASSWORD = 1<<8, GNUTLS_PKCS_PBES2_DES = 1<<9, - GNUTLS_PKCS_PBES1_DES_MD5 = 1<<10 + GNUTLS_PKCS_PBES1_DES_MD5 = 1<<10, + GNUTLS_PKCS_PBES2_GOST_TC26Z = 1<<11, + GNUTLS_PKCS_PBES2_GOST_CPA = 1<<12, + GNUTLS_PKCS_PBES2_GOST_CPB = 1<<13, + GNUTLS_PKCS_PBES2_GOST_CPC = 1<<14, + GNUTLS_PKCS_PBES2_GOST_CPD = 1<<15 } gnutls_pkcs_encrypt_flags_t; #define GNUTLS_PKCS_CIPHER_MASK(x) ((x)&(~(GNUTLS_PKCS_NULL_PASSWORD))) @@ -1124,6 +1134,11 @@ typedef enum gnutls_pkcs_encrypt_flags_t { #define GNUTLS_PKCS_USE_PBES2_AES_128 GNUTLS_PKCS_PBES2_AES_128 #define GNUTLS_PKCS_USE_PBES2_AES_192 GNUTLS_PKCS_PBES2_AES_192 #define GNUTLS_PKCS_USE_PBES2_AES_256 GNUTLS_PKCS_PBES2_AES_256 +#define GNUTLS_PKCS_USE_PBES2_GOST_TC26Z GNUTLS_PKCS_PBES2_GOST_TC26Z +#define GNUTLS_PKCS_USE_PBES2_GOST_CPA GNUTLS_PKCS_PBES2_GOST_CPA +#define GNUTLS_PKCS_USE_PBES2_GOST_CPB GNUTLS_PKCS_PBES2_GOST_CPB +#define GNUTLS_PKCS_USE_PBES2_GOST_CPC GNUTLS_PKCS_PBES2_GOST_CPC +#define GNUTLS_PKCS_USE_PBES2_GOST_CPD GNUTLS_PKCS_PBES2_GOST_CPD const char *gnutls_pkcs_schema_get_name(unsigned int schema); const char *gnutls_pkcs_schema_get_oid(unsigned int schema); diff --git a/lib/pkix.asn b/lib/pkix.asn index 47d14f9f23..22b5b8d9f6 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -368,6 +368,12 @@ pkcs-5-aes128-CBC-params ::= OCTET STRING (SIZE(16)) pkcs-5-aes192-CBC-params ::= OCTET STRING (SIZE(16)) pkcs-5-aes256-CBC-params ::= OCTET STRING (SIZE(16)) +-- GOST extension +Gost28147-89-Parameters ::= SEQUENCE { + iv OCTET STRING, -- (SIZE (8)) + encryptionParamSet OBJECT IDENTIFIER +} + pkcs-5-PBE-params ::= SEQUENCE { salt OCTET STRING, iterationCount INTEGER } diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c index 83086cdbb1..50f4196da0 100644 --- a/lib/pkix_asn1_tab.c +++ b/lib/pkix_asn1_tab.c @@ -271,6 +271,9 @@ const asn1_static_node pkix_asn1_tab[] = { { NULL, 1048586, "16"}, { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, { NULL, 1048586, "16"}, + { "Gost28147-89-Parameters", 1610612741, NULL }, + { "iv", 1073741831, NULL }, + { "encryptionParamSet", 12, NULL }, { "pkcs-5-PBE-params", 1610612741, NULL }, { "salt", 1073741831, NULL }, { "iterationCount", 3, NULL }, diff --git a/lib/x509/pkcs7-crypt.c b/lib/x509/pkcs7-crypt.c index 1f6298d36c..b04922685e 100644 --- a/lib/x509/pkcs7-crypt.c +++ b/lib/x509/pkcs7-crypt.c @@ -37,6 +37,9 @@ #include <random.h> #include <pk.h> #include <nettle/pbkdf2.h> +#if ENABLE_GOST +#include "../nettle/gost/pbkdf2-gost.h" +#endif #define PBES1_DES_MD5_OID "1.2.840.113549.1.5.3" @@ -63,6 +66,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = PBES1_DES_MD5_OID, .write_oid = PBES1_DES_MD5_OID, .desc = NULL, + .iv_name = NULL, .decrypt_only = 1}, { .schema = PBES2_3DES, @@ -73,6 +77,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = DES_EDE3_CBC_OID, .write_oid = PBES2_OID, .desc = "PKIX1.pkcs-5-des-EDE3-CBC-params", + .iv_name = "", .decrypt_only = 0}, { .schema = PBES2_DES, @@ -83,6 +88,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = DES_CBC_OID, .write_oid = PBES2_OID, .desc = "PKIX1.pkcs-5-des-CBC-params", + .iv_name = "", .decrypt_only = 0}, { .schema = PBES2_AES_128, @@ -93,6 +99,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = AES_128_CBC_OID, .write_oid = PBES2_OID, .desc = "PKIX1.pkcs-5-aes128-CBC-params", + .iv_name = "", .decrypt_only = 0}, { .schema = PBES2_AES_192, @@ -103,6 +110,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = AES_192_CBC_OID, .write_oid = PBES2_OID, .desc = "PKIX1.pkcs-5-aes192-CBC-params", + .iv_name = "", .decrypt_only = 0}, { .schema = PBES2_AES_256, @@ -113,6 +121,62 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = AES_256_CBC_OID, .write_oid = PBES2_OID, .desc = "PKIX1.pkcs-5-aes256-CBC-params", + .iv_name = "", + .decrypt_only = 0}, + { + .schema = PBES2_GOST28147_89_TC26Z, + .name = "PBES2-GOST28147-89-TC26Z", + .flag = GNUTLS_PKCS_PBES2_GOST_TC26Z, + .cipher = GNUTLS_CIPHER_GOST28147_TC26Z_CFB, + .pbes2 = 1, + .cipher_oid = GOST28147_89_TC26Z_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.Gost28147-89-Parameters", + .iv_name = "iv", + .decrypt_only = 0}, + { + .schema = PBES2_GOST28147_89_CPA, + .name = "PBES2-GOST28147-89-CPA", + .flag = GNUTLS_PKCS_PBES2_GOST_CPA, + .cipher = GNUTLS_CIPHER_GOST28147_CPA_CFB, + .pbes2 = 1, + .cipher_oid = GOST28147_89_CPA_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.Gost28147-89-Parameters", + .iv_name = "iv", + .decrypt_only = 0}, + { + .schema = PBES2_GOST28147_89_CPB, + .name = "PBES2-GOST28147-89-CPB", + .flag = GNUTLS_PKCS_PBES2_GOST_CPB, + .cipher = GNUTLS_CIPHER_GOST28147_CPB_CFB, + .pbes2 = 1, + .cipher_oid = GOST28147_89_CPB_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.Gost28147-89-Parameters", + .iv_name = "iv", + .decrypt_only = 0}, + { + .schema = PBES2_GOST28147_89_CPC, + .name = "PBES2-GOST28147-89-CPC", + .flag = GNUTLS_PKCS_PBES2_GOST_CPC, + .cipher = GNUTLS_CIPHER_GOST28147_CPC_CFB, + .pbes2 = 1, + .cipher_oid = GOST28147_89_CPC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.Gost28147-89-Parameters", + .iv_name = "iv", + .decrypt_only = 0}, + { + .schema = PBES2_GOST28147_89_CPD, + .name = "PBES2-GOST28147-89-CPD", + .flag = GNUTLS_PKCS_PBES2_GOST_CPD, + .cipher = GNUTLS_CIPHER_GOST28147_CPD_CFB, + .pbes2 = 1, + .cipher_oid = GOST28147_89_CPD_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.Gost28147-89-Parameters", + .iv_name = "iv", .decrypt_only = 0}, { .schema = PKCS12_ARCFOUR_SHA1, @@ -123,6 +187,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, .write_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, .desc = NULL, + .iv_name = NULL, .decrypt_only = 0}, { .schema = PKCS12_RC2_40_SHA1, @@ -133,6 +198,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = PKCS12_PBE_RC2_40_SHA1_OID, .write_oid = PKCS12_PBE_RC2_40_SHA1_OID, .desc = NULL, + .iv_name = NULL, .decrypt_only = 0}, { .schema = PKCS12_3DES_SHA1, @@ -143,6 +209,7 @@ static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = { .cipher_oid = PKCS12_PBE_3DES_SHA1_OID, .write_oid = PKCS12_PBE_3DES_SHA1_OID, .desc = NULL, + .iv_name = NULL, .decrypt_only = 0}, {0, 0, 0, 0, 0} }; @@ -785,6 +852,42 @@ write_pkcs12_kdf_params(ASN1_TYPE pasn, const struct pbkdf2_params *kdf_params) } static int +read_pbes2_gost_oid(uint8_t *der, size_t len, char *oid, int oid_size) +{ + int result; + ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY; + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.Gost28147-89-Parameters", &pbe_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = + _asn1_strict_der_decode(&pbe_asn, der, len, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = asn1_read_value(pbe_asn, "encryptionParamSet", + oid, &oid_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = 0; + + error: + asn1_delete_structure(&pbe_asn); + return result; +} + +static int read_pbes2_enc_params(ASN1_TYPE pasn, const gnutls_datum_t * der, struct pbe_enc_params *params) { @@ -805,11 +908,6 @@ read_pbes2_enc_params(ASN1_TYPE pasn, } _gnutls_hard_log("encryptionScheme.algorithm: %s\n", params->pbes2_oid); - if ((result = pbes2_cipher_oid_to_algo(params->pbes2_oid, ¶ms->cipher)) < 0) { - gnutls_assert(); - return result; - } - result = asn1_der_decoding_startEnd(pasn, der->data, der->size, "encryptionScheme.parameters", @@ -820,6 +918,22 @@ read_pbes2_enc_params(ASN1_TYPE pasn, } params_len = params_end - params_start + 1; + /* For GOST we have to read params to determine actual cipher */ + if (!strcmp(params->pbes2_oid, GOST28147_89_OID)) { + len = sizeof(params->pbes2_oid); + result = read_pbes2_gost_oid(&der->data[params_start], + params_len, params->pbes2_oid, len); + if (result < 0) { + gnutls_assert(); + return result; + } + } + + if ((result = pbes2_cipher_oid_to_algo(params->pbes2_oid, ¶ms->cipher)) < 0) { + gnutls_assert(); + return result; + } + /* Now check the encryption parameters. */ p = algo_to_pbes2_cipher_schema(params->cipher); @@ -846,7 +960,9 @@ read_pbes2_enc_params(ASN1_TYPE pasn, /* read the IV */ params->iv_size = sizeof(params->iv); - result = asn1_read_value(pbe_asn, "", params->iv, ¶ms->iv_size); + result = asn1_read_value(pbe_asn, + p->iv_name, + params->iv, ¶ms->iv_size); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -991,6 +1107,47 @@ _gnutls_read_pkcs_schema_params(schema_id * schema, const char *password, return result; } +static int +_gnutls_pbes2_string_to_key(unsigned int pass_len, const char *password, + const struct pbkdf2_params *kdf_params, + int key_size, uint8_t *key) +{ + int result = 0; + + if (kdf_params->mac == GNUTLS_MAC_SHA1) + pbkdf2_hmac_sha1(pass_len, (uint8_t *) password, + kdf_params->iter_count, + kdf_params->salt_size, + kdf_params->salt, key_size, key); + else if (kdf_params->mac == GNUTLS_MAC_SHA256) + pbkdf2_hmac_sha256(pass_len, (uint8_t *) password, + kdf_params->iter_count, + kdf_params->salt_size, + kdf_params->salt, key_size, key); +#if ENABLE_GOST + else if (kdf_params->mac == GNUTLS_MAC_GOSTR_94) + pbkdf2_hmac_gosthash94cp(pass_len, (uint8_t *) password, + kdf_params->iter_count, + kdf_params->salt_size, + kdf_params->salt, key_size, key); + else if (kdf_params->mac == GNUTLS_MAC_STREEBOG_256) + pbkdf2_hmac_streebog256(pass_len, (uint8_t *) password, + kdf_params->iter_count, + kdf_params->salt_size, + kdf_params->salt, key_size, key); + else if (kdf_params->mac == GNUTLS_MAC_STREEBOG_512) + pbkdf2_hmac_streebog512(pass_len, (uint8_t *) password, + kdf_params->iter_count, + kdf_params->salt_size, + kdf_params->salt, key_size, key); +#endif + else + result = + gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + + return result; +} + int _gnutls_pkcs_raw_decrypt_data(schema_id schema, ASN1_TYPE pkcs8_asn, const char *root, const char *_password, @@ -1056,19 +1213,11 @@ _gnutls_pkcs_raw_decrypt_data(schema_id schema, ASN1_TYPE pkcs8_asn, */ p = _gnutls_pkcs_schema_get(schema); if (p != NULL && p->pbes2 != 0) { /* PBES2 */ - if (kdf_params->mac == GNUTLS_MAC_SHA1) - pbkdf2_hmac_sha1(pass_len, (uint8_t *) password, - kdf_params->iter_count, - kdf_params->salt_size, - kdf_params->salt, key_size, key); - else if (kdf_params->mac == GNUTLS_MAC_SHA256) - pbkdf2_hmac_sha256(pass_len, (uint8_t *) password, - kdf_params->iter_count, - kdf_params->salt_size, - kdf_params->salt, key_size, key); - else { - ret = - gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + ret = _gnutls_pbes2_string_to_key(pass_len, password, + kdf_params, + key_size, key); + if (ret < 0) { + gnutls_assert(); goto error; } } else if (p != NULL) { /* PKCS 12 schema */ @@ -1284,6 +1433,7 @@ write_pbes2_enc_params(ASN1_TYPE pasn, const struct pbe_enc_params *params) int result; ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY; const struct pkcs_cipher_schema_st *p; + const char *cipher_oid; /* Write the encryption algorithm */ @@ -1293,15 +1443,6 @@ write_pbes2_enc_params(ASN1_TYPE pasn, const struct pbe_enc_params *params) return GNUTLS_E_INVALID_REQUEST; } - result = - asn1_write_value(pasn, "encryptionScheme.algorithm", p->cipher_oid, - 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - goto error; - } - _gnutls_hard_log("encryptionScheme.algorithm: %s\n", p->cipher_oid); - /* Now check the encryption parameters. */ if ((result = @@ -1311,8 +1452,36 @@ write_pbes2_enc_params(ASN1_TYPE pasn, const struct pbe_enc_params *params) return _gnutls_asn2err(result); } + if (p->schema == PBES2_GOST28147_89_TC26Z || + p->schema == PBES2_GOST28147_89_CPA || + p->schema == PBES2_GOST28147_89_CPB || + p->schema == PBES2_GOST28147_89_CPC || + p->schema == PBES2_GOST28147_89_CPD) { + cipher_oid = GOST28147_89_OID; + result = asn1_write_value(pbe_asn, "encryptionParamSet", + p->cipher_oid, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + } else { + cipher_oid = p->cipher_oid; + } + + result = + asn1_write_value(pasn, "encryptionScheme.algorithm", + cipher_oid, + 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log("encryptionScheme.algorithm: %s\n", cipher_oid); + /* read the salt */ - result = asn1_write_value(pbe_asn, "", params->iv, params->iv_size); + result = asn1_write_value(pbe_asn, p->iv_name, + params->iv, params->iv_size); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -1561,10 +1730,12 @@ _gnutls_pkcs_raw_encrypt_data(const gnutls_datum_t * plain, cipher_hd_st ch; int ch_init = 0; uint8_t pad, pad_size; + const cipher_entry_st *ce; - pad_size = gnutls_cipher_get_block_size(enc_params->cipher); + ce = cipher_to_entry(enc_params->cipher); + pad_size = _gnutls_cipher_get_block_size(ce); - if (pad_size == 1) /* stream */ + if (pad_size == 1 || ce->type == CIPHER_STREAM) /* stream */ pad_size = 0; data = gnutls_malloc(plain->size + pad_size); diff --git a/lib/x509/pkcs7_int.h b/lib/x509/pkcs7_int.h index 9d3ea24e31..d9f07bf9a5 100644 --- a/lib/x509/pkcs7_int.h +++ b/lib/x509/pkcs7_int.h @@ -42,6 +42,11 @@ typedef enum schema_id { PBES2_AES_128, PBES2_AES_192, PBES2_AES_256, + PBES2_GOST28147_89_TC26Z, + PBES2_GOST28147_89_CPA, + PBES2_GOST28147_89_CPB, + PBES2_GOST28147_89_CPC, + PBES2_GOST28147_89_CPD, PKCS12_3DES_SHA1, /* the stuff in PKCS #12 */ PKCS12_ARCFOUR_SHA1, PKCS12_RC2_40_SHA1, @@ -57,6 +62,7 @@ struct pkcs_cipher_schema_st { const char *cipher_oid; const char *write_oid; const char *desc; + const char *iv_name; unsigned decrypt_only; }; |