summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Belyavsky <beldmit@gmail.com>2015-11-17 15:32:30 +0000
committerMatt Caswell <matt@openssl.org>2015-11-23 16:09:42 +0000
commite44380a990a3edf1cd0c190c6459c8c026d53646 (patch)
treecb605454d30bf0eeca8c6369fed11fa5ffd29726
parent76eba0d94bb418325be6409b272eac5e2bd4a0a9 (diff)
Patch containing TLS implementation for GOST 2012
This patch contains the necessary changes to provide GOST 2012 ciphersuites in TLS. It requires the use of an external GOST 2012 engine. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Rich Salz <rsalz@openssl.org>
-rw-r--r--crypto/x509/x509type.c2
-rw-r--r--include/openssl/ssl.h13
-rw-r--r--include/openssl/tls1.h13
-rw-r--r--ssl/s3_lib.c30
-rw-r--r--ssl/ssl_ciph.c65
-rw-r--r--ssl/ssl_lib.c20
-rw-r--r--ssl/ssl_locl.h25
-rw-r--r--ssl/statem/statem_clnt.c69
-rw-r--r--ssl/statem/statem_lib.c4
-rw-r--r--ssl/statem/statem_srvr.c78
-rw-r--r--ssl/t1_lib.c120
-rw-r--r--ssl/t1_trce.c10
12 files changed, 365 insertions, 84 deletions
diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
index 8332d9e9d4..a7695cad77 100644
--- a/crypto/x509/x509type.c
+++ b/crypto/x509/x509type.c
@@ -94,6 +94,8 @@ int X509_certificate_type(X509 *x, EVP_PKEY *pkey)
ret = EVP_PK_DH | EVP_PKT_EXCH;
break;
case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2012_256:
+ case NID_id_GostR3410_2012_512:
ret = EVP_PKT_EXCH | EVP_PKT_SIGN;
break;
default:
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 14b8f6dadc..1fd9bc8e07 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -216,9 +216,10 @@ extern "C" {
# define SSL_TXT_aECDH "aECDH"
# define SSL_TXT_aECDSA "aECDSA"
# define SSL_TXT_aPSK "aPSK"
-# define SSL_TXT_aGOST94 "aGOST94"
-# define SSL_TXT_aGOST01 "aGOST01"
-# define SSL_TXT_aGOST "aGOST"
+# define SSL_TXT_aGOST94 "aGOST94"
+# define SSL_TXT_aGOST01 "aGOST01"
+# define SSL_TXT_aGOST12 "aGOST12"
+# define SSL_TXT_aGOST "aGOST"
# define SSL_TXT_aSRP "aSRP"
# define SSL_TXT_DSS "DSS"
@@ -250,12 +251,15 @@ extern "C" {
# define SSL_TXT_CAMELLIA128 "CAMELLIA128"
# define SSL_TXT_CAMELLIA256 "CAMELLIA256"
# define SSL_TXT_CAMELLIA "CAMELLIA"
+# define SSL_TXT_GOST "GOST89"
# define SSL_TXT_MD5 "MD5"
# define SSL_TXT_SHA1 "SHA1"
# define SSL_TXT_SHA "SHA"/* same as "SHA1" */
# define SSL_TXT_GOST94 "GOST94"
-# define SSL_TXT_GOST89MAC "GOST89MAC"
+# define SSL_TXT_GOST89MAC "GOST89MAC"
+# define SSL_TXT_GOST12 "GOST12"
+# define SSL_TXT_GOST89MAC12 "GOST89MAC12"
# define SSL_TXT_SHA256 "SHA256"
# define SSL_TXT_SHA384 "SHA384"
@@ -2208,6 +2212,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_BAD_ECC_CERT 304
# define SSL_R_BAD_ECDSA_SIGNATURE 305
# define SSL_R_BAD_ECPOINT 306
+# define SSL_R_BAD_GOST_SIGNATURE 406
# define SSL_R_BAD_HANDSHAKE_LENGTH 332
# define SSL_R_BAD_HELLO_REQUEST 105
# define SSL_R_BAD_LENGTH 271
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 5d7b64fbfe..cdc56c634b 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -280,9 +280,12 @@ extern "C" {
# define TLSEXT_signature_rsa 1
# define TLSEXT_signature_dsa 2
# define TLSEXT_signature_ecdsa 3
+# define TLSEXT_signature_gostr34102001 237
+# define TLSEXT_signature_gostr34102012_256 238
+# define TLSEXT_signature_gostr34102012_512 239
/* Total number of different signature algorithms */
-# define TLSEXT_signature_num 4
+# define TLSEXT_signature_num 7
# define TLSEXT_hash_none 0
# define TLSEXT_hash_md5 1
@@ -291,10 +294,13 @@ extern "C" {
# define TLSEXT_hash_sha256 4
# define TLSEXT_hash_sha384 5
# define TLSEXT_hash_sha512 6
+# define TLSEXT_hash_gostr3411 237
+# define TLSEXT_hash_gostr34112012_256 238
+# define TLSEXT_hash_gostr34112012_512 239
/* Total number of different digest algorithms */
-# define TLSEXT_hash_num 7
+# define TLSEXT_hash_num 10
/* Flag set for unrecognised algorithms */
# define TLSEXT_nid_unknown 0x1000000
@@ -920,6 +926,9 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
# define TLS_CT_RSA_FIXED_ECDH 65
# define TLS_CT_ECDSA_FIXED_ECDH 66
# define TLS_CT_GOST01_SIGN 22
+# define TLS_CT_GOST12_SIGN 238
+# define TLS_CT_GOST12_512_SIGN 239
+
/*
* when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see
* comment there)
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index d5e593a640..f40b143793 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3770,6 +3770,34 @@ OPENSSL_GLOBAL const SSL_CIPHER ssl3_ciphers[] = {
256,
},
+ {
+ 1,
+ "GOST2012-GOST8912-GOST8912",
+ 0x0300ff85,
+ SSL_kGOST,
+ SSL_aGOST12 | SSL_aGOST01,
+ SSL_eGOST2814789CNT12,
+ SSL_GOST89MAC12,
+ SSL_TLSV1,
+ SSL_NOT_EXP | SSL_HIGH,
+ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_STREAM_MAC,
+ 256,
+ 256},
+ {
+ 1,
+ "GOST2012-NULL-GOST12",
+ 0x0300ff87,
+ SSL_kGOST,
+ SSL_aGOST12 | SSL_aGOST01,
+ SSL_eNULL,
+ SSL_GOST12_256,
+ SSL_TLSV1,
+ SSL_NOT_EXP | SSL_STRONG_NONE,
+ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256,
+ 0,
+ 0},
+
+
/* end of list */
};
@@ -4936,6 +4964,8 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
if (s->version >= TLS1_VERSION) {
if (alg_k & SSL_kGOST) {
p[ret++] = TLS_CT_GOST01_SIGN;
+ p[ret++] = TLS_CT_GOST12_SIGN;
+ p[ret++] = TLS_CT_GOST12_512_SIGN;
return (ret);
}
}
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index fe30ab47a1..47f5e0f130 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -168,7 +168,8 @@
#define SSL_ENC_AES256CCM_IDX 15
#define SSL_ENC_AES128CCM8_IDX 16
#define SSL_ENC_AES256CCM8_IDX 17
-#define SSL_ENC_NUM_IDX 18
+#define SSL_ENC_GOST8912_IDX 18
+#define SSL_ENC_NUM_IDX 19
/* NB: make sure indices in these tables match values above */
@@ -196,7 +197,8 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
{SSL_AES128CCM, NID_aes_128_ccm}, /* SSL_ENC_AES128CCM_IDX 14 */
{SSL_AES256CCM, NID_aes_256_ccm}, /* SSL_ENC_AES256CCM_IDX 15 */
{SSL_AES128CCM8, NID_aes_128_ccm}, /* SSL_ENC_AES128CCM8_IDX 16 */
- {SSL_AES256CCM8, NID_aes_256_ccm} /* SSL_ENC_AES256CCM8_IDX 17 */
+ {SSL_AES256CCM8, NID_aes_256_ccm}, /* SSL_ENC_AES256CCM8_IDX 17 */
+ {SSL_eGOST2814789CNT12, NID_gost89_cnt_12}, /* SSL_ENC_GOST8912_IDX */
};
static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX] = {
@@ -216,6 +218,9 @@ static STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;
#define SSL_MD_GOST89MAC_IDX 3
#define SSL_MD_SHA256_IDX 4
#define SSL_MD_SHA384_IDX 5
+#define SSL_MD_GOST12_256_IDX 6
+#define SSL_MD_GOST89MAC12_IDX 7
+#define SSL_MD_GOST12_512_IDX 8
/*
* Constant SSL_MAX_DIGEST equal to size of digests array should be defined
* in the ssl_locl.h
@@ -230,11 +235,14 @@ static const ssl_cipher_table ssl_cipher_table_mac[SSL_MD_NUM_IDX] = {
{SSL_GOST94, NID_id_GostR3411_94}, /* SSL_MD_GOST94_IDX 2 */
{SSL_GOST89MAC, NID_id_Gost28147_89_MAC}, /* SSL_MD_GOST89MAC_IDX 3 */
{SSL_SHA256, NID_sha256}, /* SSL_MD_SHA256_IDX 4 */
- {SSL_SHA384, NID_sha384} /* SSL_MD_SHA384_IDX 5 */
+ {SSL_SHA384, NID_sha384}, /* SSL_MD_SHA384_IDX 5 */
+ {SSL_GOST12_256, NID_id_GostR3411_2012_256}, /* SSL_MD_GOST12_256_IDX 6 */
+ {SSL_GOST89MAC12, NID_gost_mac_12}, /* SSL_MD_GOST89MAC12_IDX 7 */
+ {SSL_GOST12_512, NID_id_GostR3411_2012_512} /* SSL_MD_GOST12_512_IDX 8 */
};
static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = {
- NULL, NULL, NULL, NULL, NULL, NULL
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
/* Utility function for table lookup */
@@ -258,18 +266,23 @@ static int ssl_cipher_info_find(const ssl_cipher_table * table,
* found
*/
static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = {
+ /* MD5, SHA, GOST94, MAC89 */
EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef,
- EVP_PKEY_HMAC, EVP_PKEY_HMAC
+ /* SHA256, SHA384, GOST2012_256, MAC89-12 */
+ EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef,
+ /* GOST2012_512 */
+ EVP_PKEY_HMAC,
};
static int ssl_mac_secret_size[SSL_MD_NUM_IDX] = {
- 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const int ssl_handshake_digest_flag[SSL_MD_NUM_IDX] = {
SSL_HANDSHAKE_MAC_MD5, SSL_HANDSHAKE_MAC_SHA,
SSL_HANDSHAKE_MAC_GOST94, 0, SSL_HANDSHAKE_MAC_SHA256,
- SSL_HANDSHAKE_MAC_SHA384
+ SSL_HANDSHAKE_MAC_SHA384, SSL_HANDSHAKE_MAC_GOST12_256, 0,
+ SSL_HANDSHAKE_MAC_GOST12_512,
};
#define CIPHER_ADD 1
@@ -339,7 +352,9 @@ static const SSL_CIPHER cipher_aliases[] = {
{0, SSL_TXT_ECDSA, 0, 0, SSL_aECDSA, 0, 0, 0, 0, 0, 0, 0},
{0, SSL_TXT_aPSK, 0, 0, SSL_aPSK, 0, 0, 0, 0, 0, 0, 0},
{0, SSL_TXT_aGOST01, 0, 0, SSL_aGOST01, 0, 0, 0, 0, 0, 0, 0},
- {0, SSL_TXT_aGOST, 0, 0, SSL_aGOST01, 0, 0, 0, 0, 0, 0, 0},
+ {0, SSL_TXT_aGOST12, 0, 0, SSL_aGOST12, 0, 0, 0, 0, 0, 0, 0},
+ {0, SSL_TXT_aGOST, 0, 0, SSL_aGOST01 | SSL_aGOST12, 0, 0, 0,
+ 0, 0, 0, 0},
{0, SSL_TXT_aSRP, 0, 0, SSL_aSRP, 0, 0, 0, 0, 0, 0, 0},
/* aliases combining key exchange and server authentication */
@@ -362,6 +377,8 @@ static const SSL_CIPHER cipher_aliases[] = {
{0, SSL_TXT_IDEA, 0, 0, 0, SSL_IDEA, 0, 0, 0, 0, 0, 0},
{0, SSL_TXT_SEED, 0, 0, 0, SSL_SEED, 0, 0, 0, 0, 0, 0},
{0, SSL_TXT_eNULL, 0, 0, 0, SSL_eNULL, 0, 0, 0, 0, 0, 0},
+ {0, SSL_TXT_GOST, 0, 0, 0, SSL_eGOST2814789CNT | SSL_eGOST2814789CNT12, 0,
+ 0, 0, 0, 0, 0},
{0, SSL_TXT_AES128, 0, 0, 0, SSL_AES128 | SSL_AES128GCM | SSL_AES128CCM | SSL_AES128CCM8, 0,
0, 0, 0, 0, 0},
{0, SSL_TXT_AES256, 0, 0, 0, SSL_AES256 | SSL_AES256GCM | SSL_AES256CCM | SSL_AES256CCM8, 0,
@@ -383,9 +400,11 @@ static const SSL_CIPHER cipher_aliases[] = {
{0, SSL_TXT_SHA1, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0},
{0, SSL_TXT_SHA, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0},
{0, SSL_TXT_GOST94, 0, 0, 0, 0, SSL_GOST94, 0, 0, 0, 0, 0},
- {0, SSL_TXT_GOST89MAC, 0, 0, 0, 0, SSL_GOST89MAC, 0, 0, 0, 0, 0},
+ {0, SSL_TXT_GOST89MAC, 0, 0, 0, 0, SSL_GOST89MAC | SSL_GOST89MAC12, 0, 0,
+ 0, 0, 0},
{0, SSL_TXT_SHA256, 0, 0, 0, 0, SSL_SHA256, 0, 0, 0, 0, 0},
{0, SSL_TXT_SHA384, 0, 0, 0, 0, SSL_SHA384, 0, 0, 0, 0, 0},
+ {0, SSL_TXT_GOST12, 0, 0, 0, 0, SSL_GOST12_256, 0, 0, 0, 0, 0},
/* protocol version aliases */
{0, SSL_TXT_SSLV3, 0, 0, 0, 0, 0, SSL_SSLV3, 0, 0, 0, 0},
@@ -542,12 +561,23 @@ void ssl_load_ciphers(void)
disabled_mac_mask |= SSL_GOST89MAC;
}
+ ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX] = get_optional_pkey_id("gost-mac-12");
+ if (ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX]) {
+ ssl_mac_secret_size[SSL_MD_GOST89MAC12_IDX] = 32;
+ } else {
+ disabled_mac_mask |= SSL_GOST89MAC12;
+ }
+
if (!get_optional_pkey_id("gost2001"))
- disabled_auth_mask |= SSL_aGOST01;
+ disabled_auth_mask |= SSL_aGOST01 | SSL_aGOST12;
+ if (!get_optional_pkey_id("gost2012_256"))
+ disabled_auth_mask |= SSL_aGOST12;
+ if (!get_optional_pkey_id("gost2012_512"))
+ disabled_auth_mask |= SSL_aGOST12;
/*
* Disable GOST key exchange if no GOST signature algs are available *
*/
- if ((disabled_auth_mask & SSL_aGOST01) == SSL_aGOST01)
+ if ((disabled_auth_mask & (SSL_aGOST01 | SSL_aGOST12)) == (SSL_aGOST01 | SSL_aGOST12))
disabled_mkey_mask |= SSL_kGOST;
}
@@ -1704,6 +1734,10 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
case SSL_aGOST01:
au = "GOST01";
break;
+ /* New GOST ciphersuites have both SSL_aGOST12 and SSL_aGOST01 bits */
+ case (SSL_aGOST12 | SSL_aGOST01):
+ au = "GOST12";
+ break;
default:
au = "unknown";
break;
@@ -1762,6 +1796,7 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
enc = "SEED(128)";
break;
case SSL_eGOST2814789CNT:
+ case SSL_eGOST2814789CNT12:
enc = "GOST89(256)";
break;
default:
@@ -1786,11 +1821,16 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
mac = "AEAD";
break;
case SSL_GOST89MAC:
+ case SSL_GOST89MAC12:
mac = "GOST89";
break;
case SSL_GOST94:
mac = "GOST94";
break;
+ case SSL_GOST12_256:
+ case SSL_GOST12_512:
+ mac = "GOST2012";
+ break;
default:
mac = "unknown";
break;
@@ -1998,8 +2038,11 @@ int ssl_cipher_get_cert_index(const SSL_CIPHER *c)
return SSL_PKEY_DSA_SIGN;
else if (alg_a & SSL_aRSA)
return SSL_PKEY_RSA_ENC;
+ else if (alg_a & SSL_aGOST12)
+ return SSL_PKEY_GOST_EC;
else if (alg_a & SSL_aGOST01)
return SSL_PKEY_GOST01;
+
return -1;
}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 44374b47e9..5068c15964 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2069,6 +2069,16 @@ void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
rsa_enc_export, rsa_sign, dsa_sign, dh_rsa, dh_dsa);
#endif
+ cpk = &(c->pkeys[SSL_PKEY_GOST12_512]);
+ if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST12;
+ }
+ cpk = &(c->pkeys[SSL_PKEY_GOST12_256]);
+ if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST12;
+ }
cpk = &(c->pkeys[SSL_PKEY_GOST01]);
if (cpk->x509 != NULL && cpk->privatekey != NULL) {
mask_k |= SSL_kGOST;
@@ -2255,6 +2265,16 @@ static int ssl_get_server_cert_index(const SSL *s)
idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509)
idx = SSL_PKEY_RSA_SIGN;
+ if (idx == SSL_PKEY_GOST_EC) {
+ if (s->cert->pkeys[SSL_PKEY_GOST12_512].x509)
+ idx = SSL_PKEY_GOST12_512;
+ else if (s->cert->pkeys[SSL_PKEY_GOST12_256].x509)
+ idx = SSL_PKEY_GOST12_256;
+ else if (s->cert->pkeys[SSL_PKEY_GOST01].x509)
+ idx = SSL_PKEY_GOST01;
+ else
+ idx = -1;
+ }
if (idx == -1)
SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX, ERR_R_INTERNAL_ERROR);
return idx;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 0657c20d34..95a9c62776 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -345,6 +345,8 @@
# define SSL_aGOST01 0x00000200U
/* SRP auth */
# define SSL_aSRP 0x00000400U
+/* GOST R 34.10-2012 signature auth */
+# define SSL_aGOST12 0x00000800U
/* Bits for algorithm_enc (symmetric encryption) */
# define SSL_DES 0x00000001U
@@ -365,6 +367,7 @@
# define SSL_AES256CCM 0x00008000U
# define SSL_AES128CCM8 0x00010000U
# define SSL_AES256CCM8 0x00020000U
+# define SSL_eGOST2814789CNT12 0x00040000U
# define SSL_AES (SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM|SSL_AES128CCM|SSL_AES256CCM|SSL_AES128CCM8|SSL_AES256CCM8)
# define SSL_CAMELLIA (SSL_CAMELLIA128|SSL_CAMELLIA256)
@@ -379,6 +382,9 @@
# define SSL_SHA384 0x00000020U
/* Not a real MAC, just an indication it is part of cipher */
# define SSL_AEAD 0x00000040U
+# define SSL_GOST12_256 0x00000080U
+# define SSL_GOST89MAC12 0x00000100U
+# define SSL_GOST12_512 0x00000200U
/* Bits for algorithm_ssl (protocol version) */
# define SSL_SSLV3 0x00000002U
@@ -392,13 +398,15 @@
# define SSL_HANDSHAKE_MAC_GOST94 0x40
# define SSL_HANDSHAKE_MAC_SHA256 0x80
# define SSL_HANDSHAKE_MAC_SHA384 0x100
+# define SSL_HANDSHAKE_MAC_GOST12_256 0x200
+# define SSL_HANDSHAKE_MAC_GOST12_512 0x400
# define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)
/*
- * When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX make
+ * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make
* sure to update this constant too
*/
-# define SSL_MAX_DIGEST 6
+# define SSL_MAX_DIGEST 9
# define TLS1_PRF_DGST_SHIFT 10
# define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
@@ -406,6 +414,8 @@
# define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_GOST12_256 (SSL_HANDSHAKE_MAC_GOST12_256 << TLS1_PRF_DGST_SHIFT)
+# define TLS1_PRF_GOST12_512 (SSL_HANDSHAKE_MAC_GOST12_512 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
/*
@@ -516,7 +526,14 @@
# define SSL_PKEY_DH_DSA 4
# define SSL_PKEY_ECC 5
# define SSL_PKEY_GOST01 7
-# define SSL_PKEY_NUM 8
+# define SSL_PKEY_GOST12_256 8
+# define SSL_PKEY_GOST12_512 9
+# define SSL_PKEY_NUM 10
+/*
+ * Pseudo-constant. GOST cipher suites can use different certs for 1
+ * SSL_CIPHER. So let's see which one we have in fact.
+ */
+# define SSL_PKEY_GOST_EC SSL_PKEY_NUM+1
/*-
* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) |
@@ -1249,7 +1266,7 @@ typedef struct ssl3_state_st {
int num_renegotiations;
int in_read_app_data;
struct {
- /* actually only needs to be 16+20 */
+ /* actually needs to be 32+32+64 for GOST */
unsigned char cert_verify_md[EVP_MAX_MD_SIZE * 2];
/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
unsigned char finish_md[EVP_MAX_MD_SIZE * 2];
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 7b7fc229d9..9b1846bd10 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1365,7 +1365,10 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
* Don't digest cached records if no sigalgs: we may need them for client
* authentication.
*/
- if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, 0))
+ if (!(SSL_USE_SIGALGS(s)
+ || (s->s3->tmp.new_cipher->algorithm_auth
+ & (SSL_aGOST12|SSL_aGOST01)))
+ && !ssl3_digest_cached_records(s, 0))
goto f_err;
/* lets get the compression algorithm */
/* COMPRESSION */
@@ -1556,7 +1559,10 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
}
exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
- if (exp_idx >= 0 && i != exp_idx) {
+ if (exp_idx >= 0 && i != exp_idx
+ && (exp_idx != SSL_PKEY_GOST_EC ||
+ (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256
+ && i != SSL_PKEY_GOST01))) {
x = NULL;
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
@@ -2771,6 +2777,10 @@ psk_err:
unsigned char shared_ukm[32], tmp[256];
EVP_MD_CTX *ukm_hash;
EVP_PKEY *pub_key;
+ int dgst_nid = NID_id_GostR3411_94;
+ if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0)
+ dgst_nid = NID_id_GostR3411_2012_256;
+
pmslen = 32;
pms = OPENSSL_malloc(pmslen);
@@ -2830,7 +2840,7 @@ psk_err:
*/
ukm_hash = EVP_MD_CTX_create();
if (EVP_DigestInit(ukm_hash,
- EVP_get_digestbynid(NID_id_GostR3411_94)) <= 0
+ EVP_get_digestbynid(dgst_nid)) <= 0
|| EVP_DigestUpdate(ukm_hash, s->s3->client_random,
SSL3_RANDOM_SIZE) <= 0
|| EVP_DigestUpdate(ukm_hash, s->s3->server_random,
@@ -3003,7 +3013,7 @@ int tls_client_key_exchange_post_work(SSL *s)
int tls_construct_client_verify(SSL *s)
{
unsigned char *p;
- unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+ unsigned char data[EVP_MAX_MD_SIZE]; /* GOST R 34.11-2012-256*/
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx = NULL;
EVP_MD_CTX mctx;
@@ -3034,20 +3044,33 @@ int tls_construct_client_verify(SSL *s)
} else {
ERR_clear_error();
}
+
/*
* For TLS v1.2 send signature algorithm and signature using agreed
* digest and cached handshake records.
*/
- if (SSL_USE_SIGALGS(s)) {
+ if (SSL_USE_SIGALGS(s) || pkey->type == NID_id_GostR3410_2001
+ || pkey->type == NID_id_GostR3410_2012_256
+ || pkey->type == NID_id_GostR3410_2012_512) {
long hdatalen = 0;
void *hdata;
const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (!SSL_USE_SIGALGS(s)) {
+ int dgst_nid;
+ if (EVP_PKEY_get_default_digest_nid(pkey, &dgst_nid) <= 0
+ || (md = EVP_get_digestbynid(dgst_nid)) == NULL) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
}
- p += 2;
+ if (SSL_USE_SIGALGS(s) ) {
+ p += 2;
+ }
#ifdef SSL_DEBUG
fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
EVP_MD_name(md));
@@ -3058,8 +3081,20 @@ int tls_construct_client_verify(SSL *s)
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
goto err;
}
+ if (pkey->type == NID_id_GostR3410_2001
+ || pkey->type == NID_id_GostR3410_2012_256
+ || pkey->type == NID_id_GostR3410_2012_512) {
+ unsigned int i, k;
+ for (i = u - 1, k = 0; k < u/2; k++, i--) {
+ char c = p[2 + k];
+ p[2 + k] = p[2 + i];
+ p[2 + i] = c;
+ }
+ }
s2n(u, p);
- n = u + 4;
+ n = u + 2;
+ if (SSL_USE_SIGALGS(s))
+ n += 2;
/* Digest cached records and discard handshake buffer */
if (!ssl3_digest_cached_records(s, 0))
goto err;
@@ -3103,17 +3138,23 @@ int tls_construct_client_verify(SSL *s)
n = j + 2;
} else
#endif
- if (pkey->type == NID_id_GostR3410_2001) {
- unsigned char signbuf[64];
+ if (pkey->type == NID_id_GostR3410_2001
+ || pkey->type == NID_id_GostR3410_2012_256
+ || pkey->type == NID_id_GostR3410_2012_512) {
+ unsigned char signbuf[128];
int i;
- size_t sigsize = 64;
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_id_GostR3411_94, data);
- if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
+ size_t sigsize =
+ (pkey->type == NID_id_GostR3410_2012_512) ? 128 : 64;
+ int dgst_nid = NID_undef;
+
+ EVP_PKEY_get_default_digest_nid(pkey, &dgst_nid);
+ s->method->ssl3_enc->cert_verify_mac(s, dgst_nid, data);
+ if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data,
+ EVP_MD_size(EVP_get_digestbynid(dgst_nid))) <= 0) {
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
}
- for (i = 63, j = 0; i >= 0; j++, i--) {
+ for (i = sigsize - 1, j = 0; i >= 0; j++, i--) {
p[2 + j] = signbuf[i];
}
s2n(j, p);
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 2f13e92111..24bbded5eb 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -625,6 +625,10 @@ int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
#endif
else if (i == NID_id_GostR3410_2001) {
ret = SSL_PKEY_GOST01;
+ } else if (i == NID_id_GostR3410_2012_256) {
+ ret = SSL_PKEY_GOST12_256;
+ } else if (i == NID_id_GostR3410_2012_512) {
+ ret = SSL_PKEY_GOST12_512;
} else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX)) {
/*
* For DH two cases: DH certificate signed with RSA and DH
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 61a79f5993..ab9b163671 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1550,7 +1550,8 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
s->s3->tmp.new_cipher = s->session->cipher;
}
- if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
+ if (!(SSL_USE_SIGALGS(s) || (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aGOST12|SSL_aGOST01)) )
+ || !(s->verify_mode & SSL_VERIFY_PEER)) {
if (!ssl3_digest_cached_records(s, 0)) {
al = SSL_AD_INTERNAL_ERROR;
goto f_err;
@@ -2810,8 +2811,20 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
/* Get our certificate private key */
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if (alg_a & SSL_aGOST01)
+ if (alg_a & SSL_aGOST12) {
+ /*
+ * New GOST ciphersuites have SSL_aGOST01 bit too
+ */
+ pk = s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey;
+ if (pk == NULL) {
+ pk = s->cert->pkeys[SSL_PKEY_GOST12_256].privatekey;
+ }
+ if (pk == NULL) {
+ pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+ }
+ } else if (alg_a & SSL_aGOST01) {
pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+ }
pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
if (pkey_ctx == NULL) {
@@ -2955,8 +2968,10 @@ WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst)
if (s->statem.no_cert_verify) {
/* No certificate verify so we no longer need the handshake_buffer */
BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
return WORK_FINISHED_CONTINUE;
- } else if (SSL_USE_SIGALGS(s)) {
+ } else if (SSL_USE_SIGALGS(s) || (s->s3->tmp.new_cipher->algorithm_auth
+ & (SSL_aGOST12|SSL_aGOST01) )) {
if (!s->session->peer) {
/* No peer certificate so we no longer need the handshake_buffer */
BIO_free(s->s3->handshake_buffer);
@@ -3042,7 +3057,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
/* Check for broken implementations of GOST ciphersuites */
/*
* If key is GOST and n is exactly 64, it is bare signature without
- * length field
+ * length field (CryptoPro implementations at least till CSP 4.0)
*/
if (PACKET_remaining(pkt) == 64 && pkey->type == NID_id_GostR3410_2001) {
len = 64;
@@ -3085,7 +3100,10 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
goto f_err;
}
- if (SSL_USE_SIGALGS(s)) {
+ if (SSL_USE_SIGALGS(s)
+ || pkey->type == NID_id_GostR3410_2001
+ || pkey->type == NID_id_GostR3410_2012_256
+ || pkey->type == NID_id_GostR3410_2012_512) {
long hdatalen = 0;
void *hdata;
hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
@@ -3098,6 +3116,15 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
EVP_MD_name(md));
#endif
+ if (!SSL_USE_SIGALGS(s)) {
+ int dgst_nid;
+ if (EVP_PKEY_get_default_digest_nid(pkey, &dgst_nid) <= 0
+ || (md = EVP_get_digestbynid(dgst_nid)) == NULL) {
+ SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
if (!EVP_VerifyInit_ex(&mctx, md, NULL)
|| !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) {
SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB);
@@ -3105,6 +3132,17 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
goto f_err;
}
+ if (pkey->type == NID_id_GostR3410_2001
+ || pkey->type == NID_id_GostR3410_2012_256
+ || pkey->type == NID_id_GostR3410_2012_512) {
+ unsigned int j1, j2;
+ for (j1 = len - 1, j2 = 0; j2 < len/2; j2++, j1--) {
+ char c = data[j2];
+ data[j2] = data[j1];
+ data[j1] = c;
+ }
+ }
+
if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
al = SSL_AD_DECRYPT_ERROR;
SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
@@ -3154,35 +3192,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
}
} else
#endif
- if (pkey->type == NID_id_GostR3410_2001) {
- unsigned char signature[64];
- int idx;
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (pctx == NULL) {
- al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_MALLOC_FAILURE);
- goto f_err;
- }
- if (EVP_PKEY_verify_init(pctx) <= 0) {
- al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
- goto f_err;
- }
- if (len != 64) {
- fprintf(stderr, "GOST signature length is %d", len);
- }
- for (idx = 0; idx < 64; idx++) {
- signature[63 - idx] = data[idx];
- }
- j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
- 32);
- EVP_PKEY_CTX_free(pctx);
- if (j <= 0) {
- al = SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
- goto f_err;
- }
- } else {
+ {
SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
al = SSL_AD_UNSUPPORTED_CERTIFICATE;
goto f_err;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 1439eaab22..2ba76e3835 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -954,6 +954,11 @@ static const unsigned char tls12_sigalgs[] = {
tlsext_sigalg(TLSEXT_hash_sha256)
tlsext_sigalg(TLSEXT_hash_sha224)
tlsext_sigalg(TLSEXT_hash_sha1)
+#ifndef OPENSSL_NO_GOST
+ TLSEXT_hash_gostr3411, TLSEXT_signature_gostr34102001,
+ TLSEXT_hash_gostr34112012_256, TLSEXT_signature_gostr34102012_256,
+ TLSEXT_hash_gostr34112012_512, TLSEXT_signature_gostr34102012_512
+#endif
};
#ifndef OPENSSL_NO_EC
@@ -992,7 +997,22 @@ size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
return s->cert->conf_sigalgslen;
} else {
*psigs = tls12_sigalgs;
+#ifndef OPENSSL_NO_GOST
+ /*
+ * We expect that GOST 2001 signature and GOST 34.11-94 hash are present in all engines
+ * and GOST 2012 algorithms are not always present.
+ * It may change when the old algorithms are deprecated.
+ */
+ if ((EVP_get_digestbynid(NID_id_GostR3411_94) != NULL)
+ && (EVP_get_digestbynid(NID_id_GostR3411_2012_256) == NULL)) {
+ return sizeof(tls12_sigalgs) - 4;
+ } else if (EVP_get_digestbynid(NID_id_GostR3411_94) == NULL) {
+ return sizeof(tls12_sigalgs) - 6;
+ }
return sizeof(tls12_sigalgs);
+#else
+ return sizeof(tls12_sigalgs);
+#endif
}
}
@@ -1714,7 +1734,9 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
* for other cases too.
*/
if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4)
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12)
s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
else {
s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
@@ -2696,6 +2718,11 @@ static void ssl_set_default_md(SSL *s)
#ifndef OPENSSL_NO_EC
pmd[SSL_PKEY_ECC] = EVP_sha1(