mirror of
https://abf.rosa.ru/djam/libressl.git
synced 2025-02-23 08:02:54 +00:00
412 lines
12 KiB
Diff
412 lines
12 KiB
Diff
![]() |
From e2409a33a5ffb21c41de9f213fecaf26e384d6a8 Mon Sep 17 00:00:00 2001
|
||
|
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
||
|
Date: Wed, 1 Apr 2020 17:15:42 +0300
|
||
|
Subject: [PATCH 78/87] ssl: add support for GOST-KDF key exchange
|
||
|
|
||
|
Add support for GOST-KDF key exchange used by CTR-OMAC cipher suites.
|
||
|
|
||
|
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
||
|
---
|
||
|
src/lib/libssl/s3_lib.c | 2 +
|
||
|
src/lib/libssl/ssl_ciph.c | 2 +-
|
||
|
src/lib/libssl/ssl_clnt.c | 87 +++++++++++++++++++---------------
|
||
|
src/lib/libssl/ssl_lib.c | 2 +-
|
||
|
src/lib/libssl/ssl_locl.h | 2 +
|
||
|
src/lib/libssl/ssl_srvr.c | 98 +++++++++++++++++++++++++--------------
|
||
|
src/lib/libssl/t1_lib.c | 42 +++++++++++++++++
|
||
|
7 files changed, 162 insertions(+), 73 deletions(-)
|
||
|
|
||
|
diff --git a/src/lib/libssl/s3_lib.c b/src/lib/libssl/s3_lib.c
|
||
|
index 18b9ad62f..106a2567a 100644
|
||
|
--- a/src/lib/libssl/s3_lib.c
|
||
|
+++ b/src/lib/libssl/s3_lib.c
|
||
|
@@ -2598,6 +2598,8 @@ ssl3_get_req_cert_types(SSL *s, CBB *cbb)
|
||
|
if ((alg_k & SSL_kGOST) != 0) {
|
||
|
if (!CBB_add_u8(cbb, TLS_CT_GOST01_SIGN))
|
||
|
return 0;
|
||
|
+ }
|
||
|
+ if (((alg_k & SSL_kGOST) != 0) || ((alg_k & SSL_kGOST_KDF) != 0)) {
|
||
|
if (!CBB_add_u8(cbb, TLS_CT_GOST12_256_SIGN))
|
||
|
return 0;
|
||
|
if (!CBB_add_u8(cbb, TLS_CT_GOST12_512_SIGN))
|
||
|
diff --git a/src/lib/libssl/ssl_ciph.c b/src/lib/libssl/ssl_ciph.c
|
||
|
index 9ef17e052..a3e0d396b 100644
|
||
|
--- a/src/lib/libssl/ssl_ciph.c
|
||
|
+++ b/src/lib/libssl/ssl_ciph.c
|
||
|
@@ -653,7 +653,7 @@ ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth,
|
||
|
*/
|
||
|
if (EVP_PKEY_meth_find(NID_id_GostR3410_2001) == NULL) {
|
||
|
*auth |= SSL_aGOST01;
|
||
|
- *mkey |= SSL_kGOST;
|
||
|
+ *mkey |= SSL_kGOST | SSL_kGOST_KDF;
|
||
|
}
|
||
|
|
||
|
#ifdef SSL_FORBID_ENULL
|
||
|
diff --git a/src/lib/libssl/ssl_clnt.c b/src/lib/libssl/ssl_clnt.c
|
||
|
index 0a1b6ea24..731104253 100644
|
||
|
--- a/src/lib/libssl/ssl_clnt.c
|
||
|
+++ b/src/lib/libssl/ssl_clnt.c
|
||
|
@@ -2141,18 +2141,14 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sc, CBB *cbb)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
|
||
|
+ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb, unsigned int psexp)
|
||
|
{
|
||
|
- unsigned char premaster_secret[32], shared_ukm[32], tmp[256];
|
||
|
+ unsigned char premaster_secret[32], *tmp = NULL;
|
||
|
EVP_PKEY *pub_key = NULL;
|
||
|
EVP_PKEY_CTX *pkey_ctx;
|
||
|
X509 *peer_cert;
|
||
|
size_t msglen;
|
||
|
- unsigned int md_len;
|
||
|
- EVP_MD_CTX *ukm_hash;
|
||
|
int ret = -1;
|
||
|
- int nid;
|
||
|
- CBB gostblob;
|
||
|
|
||
|
/* Get server sertificate PKEY and create ctx from it */
|
||
|
peer_cert = sess_cert->peer_pkeys[SSL_PKEY_GOST01].x509;
|
||
|
@@ -2172,12 +2168,13 @@ ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
|
||
|
EVP_PKEY_encrypt_init(pkey_ctx);
|
||
|
|
||
|
/* Generate session key. */
|
||
|
- arc4random_buf(premaster_secret, 32);
|
||
|
+ arc4random_buf(premaster_secret, sizeof(premaster_secret));
|
||
|
|
||
|
/*
|
||
|
* If we have client certificate, use its secret as peer key.
|
||
|
+ * Only for old (non-PSexp) key exchange.
|
||
|
*/
|
||
|
- if (S3I(s)->tmp.cert_req && s->cert->key->privatekey) {
|
||
|
+ if (!psexp && S3I(s)->tmp.cert_req && s->cert->key->privatekey) {
|
||
|
if (EVP_PKEY_derive_set_peer(pkey_ctx,
|
||
|
s->cert->key->privatekey) <=0) {
|
||
|
/*
|
||
|
@@ -2186,49 +2183,62 @@ ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
|
||
|
*/
|
||
|
ERR_clear_error();
|
||
|
}
|
||
|
+ } else if (psexp) {
|
||
|
+ int format;
|
||
|
+
|
||
|
+ if (S3I(s)->hs.new_cipher->algorithm_enc == SSL_MAGMA_CTR_ACPKM)
|
||
|
+ format = GOST_ENC_FORMAT_PSKEY_MAGMA;
|
||
|
+ else
|
||
|
+ format = GOST_ENC_FORMAT_PSKEY_KUZNYECHIK;
|
||
|
+
|
||
|
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
|
||
|
+ EVP_PKEY_CTRL_GOST_ENC_FORMAT,
|
||
|
+ format, NULL) <= 0) {
|
||
|
+ SSLerror(s, ERR_R_EVP_LIB);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Compute shared IV and store it in algorithm-specific context data.
|
||
|
*/
|
||
|
- ukm_hash = EVP_MD_CTX_new();
|
||
|
- if (ukm_hash == NULL) {
|
||
|
- SSLerror(s, ERR_R_MALLOC_FAILURE);
|
||
|
+ if (!tls1_set_gost_ukm(s, pkey_ctx, psexp))
|
||
|
goto err;
|
||
|
- }
|
||
|
-
|
||
|
- if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94)
|
||
|
- nid = NID_id_GostR3411_94;
|
||
|
- else
|
||
|
- nid = NID_id_tc26_gost3411_2012_256;
|
||
|
- if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid)))
|
||
|
- goto err;
|
||
|
- EVP_DigestUpdate(ukm_hash, s->s3->client_random, SSL3_RANDOM_SIZE);
|
||
|
- EVP_DigestUpdate(ukm_hash, s->s3->server_random, SSL3_RANDOM_SIZE);
|
||
|
- EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
|
||
|
- EVP_MD_CTX_free(ukm_hash);
|
||
|
- if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
|
||
|
- EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) {
|
||
|
- SSLerror(s, SSL_R_LIBRARY_BUG);
|
||
|
- goto err;
|
||
|
- }
|
||
|
|
||
|
/*
|
||
|
* Make GOST keytransport blob message, encapsulate it into sequence.
|
||
|
*/
|
||
|
- msglen = 255;
|
||
|
- if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret,
|
||
|
- 32) < 0) {
|
||
|
+ if (EVP_PKEY_encrypt(pkey_ctx, NULL, &msglen,
|
||
|
+ premaster_secret, sizeof(premaster_secret)) < 0) {
|
||
|
SSLerror(s, SSL_R_LIBRARY_BUG);
|
||
|
goto err;
|
||
|
}
|
||
|
-
|
||
|
- if (!CBB_add_asn1(cbb, &gostblob, CBS_ASN1_SEQUENCE))
|
||
|
- goto err;
|
||
|
- if (!CBB_add_bytes(&gostblob, tmp, msglen))
|
||
|
+ if ((tmp = malloc(msglen)) == NULL) {
|
||
|
+ SSLerror(s, ERR_R_MALLOC_FAILURE);
|
||
|
goto err;
|
||
|
- if (!CBB_flush(cbb))
|
||
|
+ }
|
||
|
+ if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen,
|
||
|
+ premaster_secret, sizeof(premaster_secret)) < 0) {
|
||
|
+ SSLerror(s, SSL_R_LIBRARY_BUG);
|
||
|
goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (psexp) {
|
||
|
+ if (!CBB_add_bytes(cbb, tmp, msglen))
|
||
|
+ goto err;
|
||
|
+ if (!CBB_flush(cbb))
|
||
|
+ goto err;
|
||
|
+ } else {
|
||
|
+ CBB gostblob;
|
||
|
+
|
||
|
+ if (!CBB_add_asn1(cbb, &gostblob, CBS_ASN1_SEQUENCE))
|
||
|
+ goto err;
|
||
|
+ if (!CBB_add_bytes(&gostblob, tmp, msglen))
|
||
|
+ goto err;
|
||
|
+ if (!CBB_flush(cbb))
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
|
||
|
/* Check if pubkey from client certificate was used. */
|
||
|
if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2,
|
||
|
@@ -2283,7 +2293,10 @@ ssl3_send_client_key_exchange(SSL *s)
|
||
|
if (ssl3_send_client_kex_ecdhe(s, sess_cert, &kex) != 1)
|
||
|
goto err;
|
||
|
} else if (alg_k & SSL_kGOST) {
|
||
|
- if (ssl3_send_client_kex_gost(s, sess_cert, &kex) != 1)
|
||
|
+ if (ssl3_send_client_kex_gost(s, sess_cert, &kex, 0) != 1)
|
||
|
+ goto err;
|
||
|
+ } else if (alg_k & SSL_kGOST_KDF) {
|
||
|
+ if (ssl3_send_client_kex_gost(s, sess_cert, &kex, 1) != 1)
|
||
|
goto err;
|
||
|
} else {
|
||
|
ssl3_send_alert(s, SSL3_AL_FATAL,
|
||
|
diff --git a/src/lib/libssl/ssl_lib.c b/src/lib/libssl/ssl_lib.c
|
||
|
index 6ef2083f5..5495a74ad 100644
|
||
|
--- a/src/lib/libssl/ssl_lib.c
|
||
|
+++ b/src/lib/libssl/ssl_lib.c
|
||
|
@@ -2000,7 +2000,7 @@ ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
|
||
|
|
||
|
cpk = &(c->pkeys[SSL_PKEY_GOST01]);
|
||
|
if (cpk->x509 != NULL && cpk->privatekey != NULL) {
|
||
|
- mask_k |= SSL_kGOST;
|
||
|
+ mask_k |= SSL_kGOST | SSL_kGOST_KDF;
|
||
|
mask_a |= SSL_aGOST01;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h
|
||
|
index 72646fa8c..b07be5ab2 100644
|
||
|
--- a/src/lib/libssl/ssl_locl.h
|
||
|
+++ b/src/lib/libssl/ssl_locl.h
|
||
|
@@ -1373,6 +1373,8 @@ int ssl_check_serverhello_tlsext(SSL *s);
|
||
|
int tls1_process_ticket(SSL *s, CBS *session_id, CBS *ext_block,
|
||
|
SSL_SESSION **ret);
|
||
|
|
||
|
+int tls1_set_gost_ukm(SSL *s, EVP_PKEY_CTX *pkey_ctx, unsigned int psexp);
|
||
|
+
|
||
|
long ssl_get_algorithm2(SSL *s);
|
||
|
|
||
|
int tls1_check_ec_server_key(SSL *s);
|
||
|
diff --git a/src/lib/libssl/ssl_srvr.c b/src/lib/libssl/ssl_srvr.c
|
||
|
index 69e547cbe..1d924617c 100644
|
||
|
--- a/src/lib/libssl/ssl_srvr.c
|
||
|
+++ b/src/lib/libssl/ssl_srvr.c
|
||
|
@@ -1935,10 +1935,10 @@ ssl3_get_client_kex_ecdhe(SSL *s, CBS *cbs)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-ssl3_get_client_kex_gost(SSL *s, CBS *cbs)
|
||
|
+ssl3_get_client_kex_gost(SSL *s, CBS *cbs, int psexp)
|
||
|
{
|
||
|
EVP_PKEY_CTX *pkey_ctx;
|
||
|
- EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
|
||
|
+ EVP_PKEY *pk = NULL;
|
||
|
unsigned char premaster_secret[32];
|
||
|
unsigned long alg_a;
|
||
|
size_t outlen = 32;
|
||
|
@@ -1954,56 +1954,83 @@ ssl3_get_client_kex_gost(SSL *s, CBS *cbs)
|
||
|
if ((pkey_ctx = EVP_PKEY_CTX_new(pk, NULL)) == NULL)
|
||
|
goto err;
|
||
|
if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0)
|
||
|
- goto gerr;
|
||
|
+ goto err;
|
||
|
|
||
|
- /*
|
||
|
- * If client certificate is present and is of the same type,
|
||
|
- * maybe use it for key exchange.
|
||
|
- * Don't mind errors from EVP_PKEY_derive_set_peer, because
|
||
|
- * it is completely valid to use a client certificate for
|
||
|
- * authorization only.
|
||
|
- */
|
||
|
- if ((client_pub_pkey = X509_get_pubkey(s->session->peer)) != NULL) {
|
||
|
- if (EVP_PKEY_derive_set_peer(pkey_ctx,
|
||
|
- client_pub_pkey) <= 0)
|
||
|
- ERR_clear_error();
|
||
|
+ if (!psexp) {
|
||
|
+ EVP_PKEY *client_pub_pkey = X509_get_pubkey(s->session->peer);
|
||
|
+ /*
|
||
|
+ * If client certificate is present and is of the same type,
|
||
|
+ * maybe use it for key exchange.
|
||
|
+ * Don't mind errors from EVP_PKEY_derive_set_peer, because
|
||
|
+ * it is completely valid to use a client certificate for
|
||
|
+ * authorization only.
|
||
|
+ */
|
||
|
+ if (client_pub_pkey != NULL) {
|
||
|
+ if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
|
||
|
+ ERR_clear_error();
|
||
|
+ EVP_PKEY_free(client_pub_pkey);
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Compute shared IV and store it in algorithm-specific context data.
|
||
|
+ */
|
||
|
+ if (!tls1_set_gost_ukm(s, pkey_ctx, psexp))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Decrypt session key */
|
||
|
+ if (!CBS_get_asn1(cbs, &gostblob, CBS_ASN1_SEQUENCE))
|
||
|
+ goto truncated;
|
||
|
+ } else {
|
||
|
+ int format;
|
||
|
+
|
||
|
+ if (S3I(s)->hs.new_cipher->algorithm_enc == SSL_MAGMA_CTR_ACPKM)
|
||
|
+ format = GOST_ENC_FORMAT_PSKEY_MAGMA;
|
||
|
+ else
|
||
|
+ format = GOST_ENC_FORMAT_PSKEY_KUZNYECHIK;
|
||
|
+
|
||
|
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_DECRYPT,
|
||
|
+ EVP_PKEY_CTRL_GOST_ENC_FORMAT,
|
||
|
+ format, NULL) <= 0) {
|
||
|
+ SSLerror(s, ERR_R_EVP_LIB);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Compute shared IV and store it in algorithm-specific context data.
|
||
|
+ */
|
||
|
+ if (!tls1_set_gost_ukm(s, pkey_ctx, psexp))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Decrypt session key */
|
||
|
+ if (!CBS_get_asn1_element(cbs, &gostblob, CBS_ASN1_SEQUENCE))
|
||
|
+ goto truncated;
|
||
|
}
|
||
|
|
||
|
- /* Decrypt session key */
|
||
|
- if (!CBS_get_asn1(cbs, &gostblob, CBS_ASN1_SEQUENCE))
|
||
|
- goto truncated;
|
||
|
if (CBS_len(cbs) != 0)
|
||
|
goto truncated;
|
||
|
if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen,
|
||
|
- CBS_data(&gostblob), CBS_len(&gostblob)) <= 0) {
|
||
|
+ CBS_data(&gostblob), CBS_len(&gostblob)) <= 0 ||
|
||
|
+ outlen != 32) {
|
||
|
SSLerror(s, SSL_R_DECRYPTION_FAILED);
|
||
|
- goto gerr;
|
||
|
+ goto err;
|
||
|
}
|
||
|
|
||
|
/* Generate master secret */
|
||
|
s->session->master_key_length =
|
||
|
tls1_generate_master_secret(
|
||
|
- s, s->session->master_key, premaster_secret, 32);
|
||
|
+ s, s->session->master_key, premaster_secret, outlen);
|
||
|
|
||
|
- /* Check if pubkey from client certificate was used */
|
||
|
- if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1,
|
||
|
- EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
|
||
|
- ret = 2;
|
||
|
- else
|
||
|
- ret = 1;
|
||
|
- gerr:
|
||
|
- EVP_PKEY_free(client_pub_pkey);
|
||
|
+ ret = 1;
|
||
|
+
|
||
|
+err:
|
||
|
EVP_PKEY_CTX_free(pkey_ctx);
|
||
|
- if (ret)
|
||
|
- return (ret);
|
||
|
- else
|
||
|
- goto err;
|
||
|
+
|
||
|
+ return ret;
|
||
|
|
||
|
truncated:
|
||
|
al = SSL_AD_DECODE_ERROR;
|
||
|
SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
|
||
|
ssl3_send_alert(s, SSL3_AL_FATAL, al);
|
||
|
- err:
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
@@ -2038,7 +2065,10 @@ ssl3_get_client_key_exchange(SSL *s)
|
||
|
if (ssl3_get_client_kex_ecdhe(s, &cbs) != 1)
|
||
|
goto err;
|
||
|
} else if (alg_k & SSL_kGOST) {
|
||
|
- if (ssl3_get_client_kex_gost(s, &cbs) != 1)
|
||
|
+ if (ssl3_get_client_kex_gost(s, &cbs, 0) != 1)
|
||
|
+ goto err;
|
||
|
+ } else if (alg_k & SSL_kGOST_KDF) {
|
||
|
+ if (ssl3_get_client_kex_gost(s, &cbs, 1) != 1)
|
||
|
goto err;
|
||
|
} else {
|
||
|
al = SSL_AD_HANDSHAKE_FAILURE;
|
||
|
diff --git a/src/lib/libssl/t1_lib.c b/src/lib/libssl/t1_lib.c
|
||
|
index 580ae4b19..3da2ebb8c 100644
|
||
|
--- a/src/lib/libssl/t1_lib.c
|
||
|
+++ b/src/lib/libssl/t1_lib.c
|
||
|
@@ -1029,3 +1029,45 @@ tls_decrypt_ticket(SSL *s, CBS *session_id, CBS *ticket, SSL_SESSION **psess)
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Compute shared IV and store it in algorithm-specific context data.
|
||
|
+ */
|
||
|
+int
|
||
|
+tls1_set_gost_ukm(SSL *s, EVP_PKEY_CTX *pkey_ctx, unsigned int psexp)
|
||
|
+{
|
||
|
+ unsigned char shared_ukm[32];
|
||
|
+ unsigned int md_len;
|
||
|
+ EVP_MD_CTX *ukm_hash;
|
||
|
+ int nid;
|
||
|
+
|
||
|
+ ukm_hash = EVP_MD_CTX_new();
|
||
|
+ if (ukm_hash == NULL) {
|
||
|
+ SSLerror(s, ERR_R_MALLOC_FAILURE);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94)
|
||
|
+ nid = NID_id_GostR3411_94;
|
||
|
+ else
|
||
|
+ nid = NID_id_tc26_gost3411_2012_256;
|
||
|
+ if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid)) ||
|
||
|
+ !EVP_DigestUpdate(ukm_hash, s->s3->client_random, SSL3_RANDOM_SIZE) ||
|
||
|
+ !EVP_DigestUpdate(ukm_hash, s->s3->server_random, SSL3_RANDOM_SIZE) ||
|
||
|
+ !EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len)) {
|
||
|
+ SSLerror(s, ERR_R_EVP_LIB);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1,
|
||
|
+ EVP_PKEY_CTRL_SET_IV, psexp ? md_len : 8, shared_ukm) < 0) {
|
||
|
+ SSLerror(s, SSL_R_LIBRARY_BUG);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+ EVP_MD_CTX_free(ukm_hash);
|
||
|
+ return 1;
|
||
|
+
|
||
|
+err:
|
||
|
+ EVP_MD_CTX_free(ukm_hash);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
--
|
||
|
2.17.1
|
||
|
|