Updates to GOST2012
[openssl.git] / ssl / statem / statem_clnt.c
index d0c6b1292ede75cc3ca383185aae392e73a0280b..527101b1266e6b3edfc3304f65398a5d440e2411 100644 (file)
@@ -182,8 +182,9 @@ static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
 static inline int cert_req_allowed(SSL *s)
 {
     /* TLS does not like anon-DH with client cert */
-    if (s->version > SSL3_VERSION
-            && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+    if ((s->version > SSL3_VERSION
+                && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+            || (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aSRP | SSL_aPSK)))
         return 0;
 
     return 1;
@@ -238,16 +239,16 @@ static int key_exchange_expected(SSL *s)
 }
 
 /*
- * client_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the client is reading messages from the server. The
- * message type that the server has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
  *
  *  Return values are:
  *  1: Success (transition allowed)
  *  0: Error (transition not allowed)
  */
-int client_read_transition(SSL *s, int mt)
+int ossl_statem_client_read_transition(SSL *s, int mt)
 {
     OSSL_STATEM *st = &s->statem;
     int ske_expected;
@@ -391,7 +392,7 @@ int client_read_transition(SSL *s, int mt)
  * client_write_transition() works out what handshake state to move to next
  * when the client is writing messages to be sent to the server.
  */
-enum WRITE_TRAN client_write_transition(SSL *s)
+WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -495,7 +496,7 @@ enum WRITE_TRAN client_write_transition(SSL *s)
  * Perform any pre work that needs to be done prior to sending a message from
  * the client to the server.
  */
-enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
+WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -542,7 +543,7 @@ enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
  * Perform any work that needs to be done after sending a message from the
  * client to the server.
  */
-enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
+WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -621,9 +622,6 @@ enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
 #endif
         if (statem_flush(s) != 1)
             return WORK_MORE_B;
-
-        if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
-                return WORK_ERROR;
         break;
 
     default:
@@ -641,7 +639,7 @@ enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
  *   1: Success
  *   0: Error
  */
-int client_construct_message(SSL *s)
+int ossl_statem_client_construct_message(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -687,7 +685,7 @@ int client_construct_message(SSL *s)
  * Returns the maximum allowed length for the current message that we are
  * reading. Excludes the message header.
  */
-unsigned long client_max_message_size(SSL *s)
+unsigned long ossl_statem_client_max_message_size(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -733,7 +731,7 @@ unsigned long client_max_message_size(SSL *s)
 /*
  * Process a message that the client has been received from the server.
  */
-enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -780,7 +778,7 @@ enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt)
  * Perform any further processing required following the receipt of a message
  * from the server
  */
-enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
+WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
 {
     OSSL_STATEM *st = &s->statem;
 
@@ -800,11 +798,6 @@ enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
         return WORK_FINISHED_STOP;
 #endif
 
-    case TLS_ST_CR_FINISHED:
-        if (!s->hit)
-            return tls_finish_handshake(s, wst);
-        else
-            return WORK_FINISHED_STOP;
     default:
         break;
     }
@@ -1093,7 +1086,7 @@ int tls_construct_client_hello(SSL *s)
     return 0;
 }
 
-enum MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
 {
     int al;
     unsigned int cookie_len;
@@ -1127,7 +1120,7 @@ enum MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
 {
     STACK_OF(SSL_CIPHER) *sk;
     const SSL_CIPHER *c;
@@ -1332,6 +1325,9 @@ enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         s->s3->tmp.mask_ssl = SSL_TLSV1_2;
     else
         s->s3->tmp.mask_ssl = 0;
+    /* Skip TLS v1.0 ciphersuites if SSLv3 */
+    if ((c->algorithm_ssl & SSL_TLSV1) && s->version == SSL3_VERSION)
+        s->s3->tmp.mask_ssl |= SSL_TLSV1;
     /*
      * If it is a disabled cipher we didn't send it in client hello, so
      * return an error.
@@ -1365,12 +1361,6 @@ enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
     s->s3->tmp.new_cipher = c;
-    /*
-     * 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))
-        goto f_err;
     /* lets get the compression algorithm */
     /* COMPRESSION */
     if (!PACKET_get_1(pkt, &compression)) {
@@ -1442,9 +1432,8 @@ enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
          * Add new shared key for SCTP-Auth, will be ignored if
          * no SCTP used.
          */
-        snprintf((char *)labelbuffer,
-                 sizeof(DTLS1_SCTP_AUTH_LABEL),
-                 DTLS1_SCTP_AUTH_LABEL);
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
 
         if (SSL_export_keying_material(s, sctpauthkey,
                                    sizeof(sctpauthkey),
@@ -1467,7 +1456,7 @@ enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-enum MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
 {
     int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
     unsigned long cert_list_len, cert_len;
@@ -1561,7 +1550,10 @@ enum 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,
@@ -1590,13 +1582,10 @@ enum MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
     return ret;
 }
 
-enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 {
-#ifndef OPENSSL_NO_RSA
-    unsigned char *q, md_buf[EVP_MAX_MD_SIZE * 2];
-#endif
     EVP_MD_CTX md_ctx;
-    int al, j, verify_ret;
+    int al, j;
     long alg_k, alg_a;
     EVP_PKEY *pkey = NULL;
     const EVP_MD *md = NULL;
@@ -1658,7 +1647,10 @@ enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             goto f_err;
         }
 
-        if (!PACKET_strndup(&psk_identity_hint,
+        if (PACKET_remaining(&psk_identity_hint) == 0) {
+            OPENSSL_free(s->session->psk_identity_hint);
+            s->session->psk_identity_hint = NULL;
+        } else if (!PACKET_strndup(&psk_identity_hint,
                             &s->session->psk_identity_hint)) {
             al = SSL_AD_INTERNAL_ERROR;
             goto f_err;
@@ -1931,6 +1923,8 @@ enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
+        } else if (pkey->type == EVP_PKEY_RSA) {
+            md = EVP_md5_sha1();
         } else {
             md = EVP_sha1();
         }
@@ -1954,58 +1948,23 @@ enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
             goto f_err;
         }
-#ifndef OPENSSL_NO_RSA
-        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
-            int num;
-            unsigned int size;
-
-            j = 0;
-            q = md_buf;
-            for (num = 2; num > 0; num--) {
-                EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, PACKET_data(&params),
-                                 PACKET_remaining(&params));
-                EVP_DigestFinal_ex(&md_ctx, q, &size);
-                q += size;
-                j += size;
-            }
-            verify_ret =
-                RSA_verify(NID_md5_sha1, md_buf, j, PACKET_data(&signature),
-                           PACKET_remaining(&signature), pkey->pkey.rsa);
-            if (verify_ret < 0) {
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_RSA_DECRYPT);
-                goto f_err;
-            }
-            if (verify_ret == 0) {
-                /* bad signature */
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
-                goto f_err;
-            }
-        } else
-#endif
-        {
-            EVP_VerifyInit_ex(&md_ctx, md, NULL);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, PACKET_data(&params),
-                             PACKET_remaining(&params));
-            if (EVP_VerifyFinal(&md_ctx, PACKET_data(&signature),
-                                PACKET_remaining(&signature), pkey) <= 0) {
-                /* bad signature */
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
-                goto f_err;
-            }
+        if (EVP_VerifyInit_ex(&md_ctx, md, NULL) <= 0
+                || EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                    SSL3_RANDOM_SIZE) <= 0
+                || EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                    SSL3_RANDOM_SIZE) <= 0
+                || EVP_VerifyUpdate(&md_ctx, PACKET_data(&params),
+                                    PACKET_remaining(&params)) <= 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+            goto f_err;
+        }
+        if (EVP_VerifyFinal(&md_ctx, PACKET_data(&signature),
+                            PACKET_remaining(&signature), pkey) <= 0) {
+            /* bad signature */
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
+            goto f_err;
         }
     } else {
         /* aNULL, aSRP or PSK do not need public keys */
@@ -2045,7 +2004,7 @@ enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-enum MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
 {
     int ret = MSG_PROCESS_ERROR;
     unsigned int list_len, ctype_num, i, name_len;
@@ -2107,6 +2066,8 @@ enum MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
             SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
             goto err;
         }
+    } else {
+        ssl_set_default_md(s);
     }
 
     /* get the CA RDNs */
@@ -2168,7 +2129,7 @@ static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
     return (X509_NAME_cmp(*a, *b));
 }
 
-enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
 {
     int al;
     unsigned int ticklen;
@@ -2221,7 +2182,7 @@ enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
     s->session->tlsext_ticklen = 0;
 
     s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-    if (!s->session->tlsext_tick) {
+    if (s->session->tlsext_tick == NULL) {
         SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
         goto err;
     }
@@ -2255,7 +2216,7 @@ enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
 {
     int al;
     unsigned long resplen;
@@ -2275,7 +2236,7 @@ enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
     }
     OPENSSL_free(s->tlsext_ocsp_resp);
     s->tlsext_ocsp_resp = OPENSSL_malloc(resplen);
-    if (!s->tlsext_ocsp_resp) {
+    if (s->tlsext_ocsp_resp == NULL) {
         al = SSL_AD_INTERNAL_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
         goto f_err;
@@ -2307,7 +2268,7 @@ enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-enum MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
+MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
 {
     if (PACKET_remaining(pkt) > 0) {
         /* should contain no data */
@@ -2459,7 +2420,7 @@ psk_err:
         RSA *rsa;
         pmslen = SSL_MAX_MASTER_KEY_LENGTH;
         pms = OPENSSL_malloc(pmslen);
-        if (!pms)
+        if (pms == NULL)
             goto memerr;
 
         if (s->session->peer == NULL) {
@@ -2561,7 +2522,7 @@ psk_err:
 
         pmslen = DH_size(dh_clnt);
         pms = OPENSSL_malloc(pmslen);
-        if (!pms)
+        if (pms == NULL)
             goto memerr;
 
         /*
@@ -2701,7 +2662,7 @@ psk_err:
         }
         pmslen = (field_size + 7) / 8;
         pms = OPENSSL_malloc(pmslen);
-        if (!pms)
+        if (pms == NULL)
             goto memerr;
         n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
         if (n <= 0 || pmslen != (size_t)n) {
@@ -2754,6 +2715,7 @@ psk_err:
         EVP_PKEY_free(srvr_pub_pkey);
     }
 #endif                          /* !OPENSSL_NO_EC */
+#ifndef OPENSSL_NO_GOST
     else if (alg_k & SSL_kGOST) {
         /* GOST key exchange message creation */
         EVP_PKEY_CTX *pkey_ctx;
@@ -2763,10 +2725,14 @@ 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);
-        if (!pms)
+        if (pms == NULL)
             goto memerr;
 
         /*
@@ -2781,18 +2747,23 @@ psk_err:
 
         pkey_ctx = EVP_PKEY_CTX_new(pub_key =
                                     X509_get_pubkey(peer_cert), NULL);
+        if (pkey_ctx == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
         /*
          * If we have send a certificate, and certificate key
-         *
-         * * parameters match those of server certificate, use
+         * parameters match those of server certificate, use
          * certificate key for key exchange
          */
 
         /* Otherwise, generate ephemeral key pair */
 
-        EVP_PKEY_encrypt_init(pkey_ctx);
-        /* Generate session key */
-        if (RAND_bytes(pms, pmslen) <= 0) {
+        if (pkey_ctx == NULL
+                || EVP_PKEY_encrypt_init(pkey_ctx) <= 0
+                /* Generate session key */
+                || RAND_bytes(pms, pmslen) <= 0) {
             EVP_PKEY_CTX_free(pkey_ctx);
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                    ERR_R_INTERNAL_ERROR);
@@ -2816,13 +2787,18 @@ psk_err:
          * data
          */
         ukm_hash = EVP_MD_CTX_create();
-        EVP_DigestInit(ukm_hash,
-                       EVP_get_digestbynid(NID_id_GostR3411_94));
-        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);
+        if (EVP_DigestInit(ukm_hash,
+                           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,
+                                    SSL3_RANDOM_SIZE) <= 0
+                || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) {
+            EVP_MD_CTX_destroy(ukm_hash);
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
         EVP_MD_CTX_destroy(ukm_hash);
         if (EVP_PKEY_CTX_ctrl
             (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
@@ -2837,7 +2813,7 @@ psk_err:
          */
         *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
         msglen = 255;
-        if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
+        if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                    SSL_R_LIBRARY_BUG);
             goto err;
@@ -2861,6 +2837,7 @@ psk_err:
         EVP_PKEY_free(pub_key);
 
     }
+#endif
 #ifndef OPENSSL_NO_SRP
     else if (alg_k & SSL_kSRP) {
         if (s->srp_ctx.A != NULL) {
@@ -2962,8 +2939,8 @@ int tls_client_key_exchange_post_work(SSL *s)
          * Add new shared key for SCTP-Auth, will be ignored if no SCTP
          * used.
          */
-        snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                 DTLS1_SCTP_AUTH_LABEL);
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
 
         if (SSL_export_keying_material(s, sctpauthkey,
                                    sizeof(sctpauthkey), labelbuffer,
@@ -2985,129 +2962,67 @@ 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];
     EVP_PKEY *pkey;
-    EVP_PKEY_CTX *pctx = NULL;
+    const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
     EVP_MD_CTX mctx;
     unsigned u = 0;
-    unsigned long n;
-    int j;
+    unsigned long n = 0;
+    long hdatalen = 0;
+    void *hdata;
 
     EVP_MD_CTX_init(&mctx);
 
     p = ssl_handshake_start(s);
     pkey = s->cert->key->privatekey;
-/* Create context from key and test if sha1 is allowed as digest */
-    pctx = EVP_PKEY_CTX_new(pkey, NULL);
-    EVP_PKEY_sign_init(pctx);
-    if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
-        if (!SSL_USE_SIGALGS(s))
-            s->method->ssl3_enc->cert_verify_mac(s,
-                                                 NID_sha1,
-                                                 &(data
-                                                   [MD5_DIGEST_LENGTH]));
-    } else {
-        ERR_clear_error();
+
+    hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+    if (hdatalen <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        goto err;
     }
-    /*
-     * For TLS v1.2 send signature algorithm and signature using agreed
-     * digest and cached handshake records.
-     */
     if (SSL_USE_SIGALGS(s)) {
-        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 (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
+        if (!tls12_get_sigandhash(p, pkey, md)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
             goto err;
         }
         p += 2;
+        n = 2;
+    }
 #ifdef SSL_DEBUG
-        fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
-                EVP_MD_name(md));
-#endif
-        if (!EVP_SignInit_ex(&mctx, md, NULL)
-            || !EVP_SignUpdate(&mctx, hdata, hdatalen)
-            || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
-            goto err;
-        }
-        s2n(u, p);
-        n = u + 4;
-        /* Digest cached records and discard handshake buffer */
-        if (!ssl3_digest_cached_records(s, 0))
-            goto err;
-    } else
-#ifndef OPENSSL_NO_RSA
-    if (pkey->type == EVP_PKEY_RSA) {
-        s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(data[0]));
-        if (RSA_sign(NID_md5_sha1, data,
-                     MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
-                     &(p[2]), &u, pkey->pkey.rsa) <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_RSA_LIB);
-            goto err;
-        }
-        s2n(u, p);
-        n = u + 2;
-    } else
-#endif
-#ifndef OPENSSL_NO_DSA
-    if (pkey->type == EVP_PKEY_DSA) {
-        if (!DSA_sign(pkey->save_type,
-                      &(data[MD5_DIGEST_LENGTH]),
-                      SHA_DIGEST_LENGTH, &(p[2]),
-                      (unsigned int *)&j, pkey->pkey.dsa)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_DSA_LIB);
-            goto err;
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else
-#endif
-#ifndef OPENSSL_NO_EC
-    if (pkey->type == EVP_PKEY_EC) {
-        if (!ECDSA_sign(pkey->save_type,
-                        &(data[MD5_DIGEST_LENGTH]),
-                        SHA_DIGEST_LENGTH, &(p[2]),
-                        (unsigned int *)&j, pkey->pkey.ec)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_ECDSA_LIB);
-            goto err;
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else
-#endif
-    if (pkey->type == NID_id_GostR3410_2001) {
-        unsigned char signbuf[64];
-        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) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        for (i = 63, j = 0; i >= 0; j++, i--) {
-            p[2 + j] = signbuf[i];
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+    fprintf(stderr, "Using client alg %s\n", EVP_MD_name(md));
+#endif
+    if (!EVP_SignInit_ex(&mctx, md, NULL)
+        || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+        || (s->version == SSL3_VERSION
+            && !EVP_MD_CTX_ctrl(&mctx, EVP_CTRL_SSL3_MASTER_SECRET,
+                                s->session->master_key_length,
+                                s->session->master_key))
+        || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
         goto err;
     }
+#ifndef OPENSSL_NO_GOST
+    if (pkey->type == NID_id_GostR3410_2001
+            || pkey->type == NID_id_GostR3410_2012_256
+            || pkey->type == NID_id_GostR3410_2012_512) {
+        BUF_reverse(p + 2, NULL, u);
+    }
+#endif
+
+    s2n(u, p);
+    n += u + 2;
+    /* Digest cached records and discard handshake buffer */
+    if (!ssl3_digest_cached_records(s, 0))
+        goto err;
     if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
     EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_CTX_free(pctx);
     return 1;
  err:
     EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_CTX_free(pctx);
     return 0;
 }
 
@@ -3154,7 +3069,7 @@ static int ssl3_check_client_certificate(SSL *s)
     return 1;
 }
 
-enum WORK_STATE tls_prepare_client_certificate(SSL *s, enum WORK_STATE wst)
+WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
 {
     X509 *x509 = NULL;
     EVP_PKEY *pkey = NULL;