summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2016-11-09 14:02:56 +0300
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2018-06-23 12:20:16 +0300
commitb8d3b99c4eedaa52537c9a2caf957e0215a7e313 (patch)
tree73023f12297b1a48cca2a86efc311ed0592abdf0
parent8062f19086f9e54e87359a3924072927e20104ee (diff)
downloadgnutls-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.h17
-rw-r--r--lib/pkix.asn6
-rw-r--r--lib/pkix_asn1_tab.c3
-rw-r--r--lib/x509/pkcs7-crypt.c233
-rw-r--r--lib/x509/pkcs7_int.h6
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, &params->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, &params->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, &params->iv_size);
+ result = asn1_read_value(pbe_asn,
+ p->iv_name,
+ params->iv, &params->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;
};