[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Mon Nov 23 16:19:10 UTC 2015


The branch master has been updated
       via  e44380a990a3edf1cd0c190c6459c8c026d53646 (commit)
      from  76eba0d94bb418325be6409b272eac5e2bd4a0a9 (commit)


- Log -----------------------------------------------------------------
commit e44380a990a3edf1cd0c190c6459c8c026d53646
Author: Dmitry Belyavsky <beldmit at gmail.com>
Date:   Tue Nov 17 15:32:30 2015 +0000

    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 at openssl.org>
    Reviewed-by: Rich Salz <rsalz at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 crypto/x509/x509type.c   |   2 +
 include/openssl/ssl.h    |  13 +++--
 include/openssl/tls1.h   |  13 ++++-
 ssl/s3_lib.c             |  30 ++++++++++++
 ssl/ssl_ciph.c           |  65 ++++++++++++++++++++-----
 ssl/ssl_lib.c            |  20 ++++++++
 ssl/ssl_locl.h           |  25 ++++++++--
 ssl/statem/statem_clnt.c |  69 +++++++++++++++++++++------
 ssl/statem/statem_lib.c  |   4 ++
 ssl/statem/statem_srvr.c |  78 ++++++++++++++++--------------
 ssl/t1_lib.c             | 120 ++++++++++++++++++++++++++++++++++++++++++-----
 ssl/t1_trce.c            |  10 +++-
 12 files changed, 365 insertions(+), 84 deletions(-)

diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
index 8332d9e..a7695ca 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 14b8f6d..1fd9bc8 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 5d7b64f..cdc56c6 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 d5e593a..f40b143 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 fe30ab4..47f5e0f 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 44374b4..5068c15 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 0657c20..95a9c62 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 7b7fc22..9b1846b 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 2f13e92..24bbded 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 61a79f5..ab9b163 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 1439eaa..2ba76e3 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();
 #endif
+#ifndef OPENSSL_NO_GOST
+    pmd[SSL_PKEY_GOST01] = EVP_get_digestbynid(NID_id_GostR3411_94);
+    pmd[SSL_PKEY_GOST12_256] = EVP_get_digestbynid(NID_id_GostR3411_2012_256);
+    pmd[SSL_PKEY_GOST12_512] = EVP_get_digestbynid(NID_id_GostR3411_2012_512);
+#endif
 }
 
 int tls1_set_server_sigalgs(SSL *s)
@@ -3167,13 +3194,19 @@ static const tls12_lookup tls12_md[] = {
     {NID_sha224, TLSEXT_hash_sha224},
     {NID_sha256, TLSEXT_hash_sha256},
     {NID_sha384, TLSEXT_hash_sha384},
-    {NID_sha512, TLSEXT_hash_sha512}
+    {NID_sha512, TLSEXT_hash_sha512},
+    {NID_id_GostR3411_94, TLSEXT_hash_gostr3411},
+    {NID_id_GostR3411_2012_256, TLSEXT_hash_gostr34112012_256},
+    {NID_id_GostR3411_2012_512, TLSEXT_hash_gostr34112012_512},
 };
 
 static const tls12_lookup tls12_sig[] = {
     {EVP_PKEY_RSA, TLSEXT_signature_rsa},
     {EVP_PKEY_DSA, TLSEXT_signature_dsa},
-    {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+    {EVP_PKEY_EC, TLSEXT_signature_ecdsa},
+    {NID_id_GostR3410_2001, TLSEXT_signature_gostr34102001},
+    {NID_id_GostR3410_2012_256, TLSEXT_signature_gostr34102012_256},
+    {NID_id_GostR3410_2012_512, TLSEXT_signature_gostr34102012_512}
 };
 
 static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen)
@@ -3222,28 +3255,53 @@ typedef struct {
     int nid;
     int secbits;
     const EVP_MD *(*mfunc) (void);
+    unsigned char tlsext_hash;
 } tls12_hash_info;
 
+static const EVP_MD* md_gost94()
+{
+	return EVP_get_digestbynid(NID_id_GostR3411_94);
+}
+
+static const EVP_MD* md_gost2012_256()
+{
+	return EVP_get_digestbynid(NID_id_GostR3411_2012_256);
+}
+
+static const EVP_MD* md_gost2012_512()
+{
+	return EVP_get_digestbynid(NID_id_GostR3411_2012_512);
+}
+
 static const tls12_hash_info tls12_md_info[] = {
 #ifdef OPENSSL_NO_MD5
-    {NID_md5, 64, 0},
+    {NID_md5, 64, 0, TLSEXT_hash_md5},
 #else
-    {NID_md5, 64, EVP_md5},
+    {NID_md5, 64, EVP_md5, TLSEXT_hash_md5},
 #endif
-    {NID_sha1, 80, EVP_sha1},
-    {NID_sha224, 112, EVP_sha224},
-    {NID_sha256, 128, EVP_sha256},
-    {NID_sha384, 192, EVP_sha384},
-    {NID_sha512, 256, EVP_sha512}
+    {NID_sha1, 80, EVP_sha1, TLSEXT_hash_sha1},
+    {NID_sha224, 112, EVP_sha224, TLSEXT_hash_sha224},
+    {NID_sha256, 128, EVP_sha256, TLSEXT_hash_sha256},
+    {NID_sha384, 192, EVP_sha384, TLSEXT_hash_sha384},
+    {NID_sha512, 256, EVP_sha512, TLSEXT_hash_sha512},
+    {NID_id_GostR3411_94,       128, md_gost94, TLSEXT_hash_gostr3411},
+    {NID_id_GostR3411_2012_256, 128, md_gost2012_256, TLSEXT_hash_gostr34112012_256},
+    {NID_id_GostR3411_2012_512, 256, md_gost2012_512, TLSEXT_hash_gostr34112012_512},
 };
 
 static const tls12_hash_info *tls12_get_hash_info(unsigned char hash_alg)
 {
+    unsigned int i;
     if (hash_alg == 0)
         return NULL;
-    if (hash_alg > OSSL_NELEM(tls12_md_info))
-        return NULL;
-    return tls12_md_info + hash_alg - 1;
+
+    for (i=0; i < OSSL_NELEM(tls12_md_info); i++)
+    {
+        if (tls12_md_info[i].tlsext_hash == hash_alg)
+            return tls12_md_info + i;
+    }
+
+    return NULL;
 }
 
 const EVP_MD *tls12_get_hash(unsigned char hash_alg)
@@ -3272,6 +3330,16 @@ static int tls12_get_pkey_idx(unsigned char sig_alg)
     case TLSEXT_signature_ecdsa:
         return SSL_PKEY_ECC;
 #endif
+# ifndef OPENSSL_NO_GOST
+    case TLSEXT_signature_gostr34102001:
+        return SSL_PKEY_GOST01;
+
+    case TLSEXT_signature_gostr34102012_256:
+        return SSL_PKEY_GOST12_256;
+
+    case TLSEXT_signature_gostr34102012_512:
+        return SSL_PKEY_GOST12_512;
+# endif
     }
     return -1;
 }
@@ -3546,6 +3614,14 @@ int tls1_process_sigalgs(SSL *s)
         if (pmd[SSL_PKEY_ECC] == NULL)
             pmd[SSL_PKEY_ECC] = EVP_sha1();
 #endif
+# ifndef OPENSSL_NO_GOST
+        if (pmd[SSL_PKEY_GOST01] == NULL)
+            pmd[SSL_PKEY_GOST01] = EVP_get_digestbynid(NID_id_GostR3411_94);
+        if (pmd[SSL_PKEY_GOST12_256] == NULL)
+            pmd[SSL_PKEY_GOST12_256] = EVP_get_digestbynid(NID_id_GostR3411_2012_256);
+        if (pmd[SSL_PKEY_GOST12_512] == NULL)
+            pmd[SSL_PKEY_GOST12_512] = EVP_get_digestbynid(NID_id_GostR3411_2012_512);
+# endif
     }
     return 1;
 }
@@ -3993,6 +4069,21 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
                 default_nid = NID_ecdsa_with_SHA1;
                 break;
 
+            case SSL_PKEY_GOST01:
+                rsign = TLSEXT_signature_gostr34102001;
+                default_nid = NID_id_GostR3411_94_with_GostR3410_2001;
+                break;
+
+            case SSL_PKEY_GOST12_256:
+                rsign = TLSEXT_signature_gostr34102012_256;
+                default_nid = NID_id_tc26_signwithdigest_gost3410_2012_256;
+                break;
+
+            case SSL_PKEY_GOST12_512:
+                rsign = TLSEXT_signature_gostr34102012_512;
+                default_nid = NID_id_tc26_signwithdigest_gost3410_2012_512;
+                break;
+
             default:
                 default_nid = -1;
                 break;
@@ -4163,6 +4254,9 @@ void tls1_set_cert_validity(SSL *s)
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_RSA);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_DSA);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST01);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_256);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_512);
 }
 
 /* User level utiity function to check a chain is suitable */
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 74d157d..dc595ac 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -543,14 +543,20 @@ static ssl_trace_tbl ssl_md_tbl[] = {
     {3, "sha224"},
     {4, "sha256"},
     {5, "sha384"},
-    {6, "sha512"}
+    {6, "sha512"},
+    {237, "md_gost94"},
+    {238, "md_gost2012_256"},
+    {239, "md_gost2012_512"},
 };
 
 static ssl_trace_tbl ssl_sig_tbl[] = {
     {0, "anonymous"},
     {1, "rsa"},
     {2, "dsa"},
-    {3, "ecdsa"}
+    {3, "ecdsa"},
+    {237, "gost2001"},
+    {238, "gost2012_256"},
+    {239, "gost2012_512"},
 };
 
 static ssl_trace_tbl ssl_hb_tbl[] = {


More information about the openssl-commits mailing list