Don't downgrade keys in libssl
[openssl.git] / ssl / statem / statem_clnt.c
index eb4d416b6b4c63f62e82d813ab57b48598840b8b..7189940a62c49d5b2e18534268cb1657d7b6e436 100644 (file)
 #include <openssl/trace.h>
 #include <internal/cryptlib.h>
 
+DEFINE_STACK_OF(X509)
+DEFINE_STACK_OF(SSL_COMP)
+DEFINE_STACK_OF_CONST(SSL_CIPHER)
+
 static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, PACKET *pkt);
 static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
 
@@ -2227,21 +2231,6 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
         return 0;
     }
 
-    /*
-     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
-     * knows how to get a key from an encoded point with the help of
-     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
-     * downgrades an EVP_PKEY to contain a legacy key.
-     *
-     * THIS IS TEMPORARY
-     */
-    EVP_PKEY_get0(s->s3.peer_tmp);
-    if (EVP_PKEY_id(s->s3.peer_tmp) == EVP_PKEY_NONE) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
-                 ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
     if (!EVP_PKEY_set1_tls_encodedpoint(s->s3.peer_tmp,
                                         PACKET_data(&encoded_pt),
                                         PACKET_remaining(&encoded_pt))) {
@@ -3144,21 +3133,6 @@ static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt)
         goto err;
     }
 
-    /*
-     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
-     * knows how to get a key from an encoded point with the help of
-     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
-     * downgrades an EVP_PKEY to contain a legacy key.
-     *
-     * THIS IS TEMPORARY
-     */
-    EVP_PKEY_get0(ckey);
-    if (EVP_PKEY_id(skey) == EVP_PKEY_NONE) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
-                 ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
     if (ssl_derive(s, ckey, skey, 0) == 0) {
         /* SSLfatal() already called */
         goto err;
@@ -3310,6 +3284,146 @@ static int tls_construct_cke_gost(SSL *s, WPACKET *pkt)
 #endif
 }
 
+#ifndef OPENSSL_NO_GOST
+int gost18_cke_cipher_nid(const SSL *s)
+{
+    if ((s->s3.tmp.new_cipher->algorithm_enc & SSL_MAGMA) != 0)
+        return NID_magma_ctr;
+    else if ((s->s3.tmp.new_cipher->algorithm_enc & SSL_KUZNYECHIK) != 0)
+        return NID_kuznyechik_ctr;
+
+    return NID_undef;
+}
+
+int gost_ukm(const SSL *s, unsigned char *dgst_buf)
+{
+    EVP_MD_CTX * hash = NULL;
+    unsigned int md_len;
+    const EVP_MD *md = ssl_evp_md_fetch(s->ctx->libctx, NID_id_GostR3411_2012_256, s->ctx->propq);
+
+    if (md == NULL)
+        return 0;
+
+    if ((hash = EVP_MD_CTX_new()) == NULL
+        || EVP_DigestInit(hash, md) <= 0
+        || EVP_DigestUpdate(hash, s->s3.client_random, SSL3_RANDOM_SIZE) <= 0
+        || EVP_DigestUpdate(hash, s->s3.server_random, SSL3_RANDOM_SIZE) <= 0
+        || EVP_DigestFinal_ex(hash, dgst_buf, &md_len) <= 0) {
+        EVP_MD_CTX_free(hash);
+        ssl_evp_md_free(md);
+        return 0;
+    }
+
+    EVP_MD_CTX_free(hash);
+    ssl_evp_md_free(md);
+    return 1;
+}
+#endif
+
+static int tls_construct_cke_gost18(SSL *s, WPACKET *pkt)
+{
+#ifndef OPENSSL_NO_GOST
+    /* GOST 2018 key exchange message creation */
+    unsigned char rnd_dgst[32], tmp[255];
+    EVP_PKEY_CTX *pkey_ctx = NULL;
+    X509 *peer_cert;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+    size_t msglen;
+    int cipher_nid = gost18_cke_cipher_nid(s);
+
+    if (cipher_nid == NID_undef) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (gost_ukm(s, rnd_dgst) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                      ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Pre-master secret - random bytes */
+    pmslen = 32;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (RAND_bytes_ex(s->ctx->libctx, pms, (int)pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+     /* Get server certificate PKEY and create ctx from it */
+    peer_cert = s->session->peer;
+    if (peer_cert == NULL) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+               SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+        return 0;
+    }
+
+    pkey_ctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, X509_get0_pubkey(peer_cert), s->ctx->propq);
+    if (pkey_ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0 ) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    };
+
+    /* Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code */
+    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
+                          EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+
+    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
+                          EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+
+    msglen = 255;
+    if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+
+    if (!WPACKET_memcpy(pkt, tmp, msglen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    EVP_PKEY_CTX_free(pkey_ctx);
+    s->s3.tmp.pms = pms;
+    s->s3.tmp.pmslen = pmslen;
+
+    return 1;
+ err:
+    EVP_PKEY_CTX_free(pkey_ctx);
+    OPENSSL_clear_free(pms, pmslen);
+    return 0;
+#else
+    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
+             ERR_R_INTERNAL_ERROR);
+    return 0;
+#endif
+}
+
 static int tls_construct_cke_srp(SSL *s, WPACKET *pkt)
 {
 #ifndef OPENSSL_NO_SRP
@@ -3366,6 +3480,9 @@ int tls_construct_client_key_exchange(SSL *s, WPACKET *pkt)
     } else if (alg_k & SSL_kGOST) {
         if (!tls_construct_cke_gost(s, pkt))
             goto err;
+    } else if (alg_k & SSL_kGOST18) {
+        if (!tls_construct_cke_gost18(s, pkt))
+            goto err;
     } else if (alg_k & SSL_kSRP) {
         if (!tls_construct_cke_srp(s, pkt))
             goto err;