[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Mon Jul 18 22:07:28 UTC 2016


The branch master has been updated
       via  05ec6a25f80ac8edfb7d7cb764d2dd68156a6965 (commit)
       via  a7a752285a4fdb716fa5e184b84fe1474de6dbcf (commit)
       via  840a2bf8eccc5efa77f84e8470b33ac0c64bb020 (commit)
       via  e00e0b3d84719e80ed5a8fd48c1162537c2fa12c (commit)
       via  67ad5aabe6b6d60ac27f6a4b10e7b1ba65113829 (commit)
       via  a8c1c7040aabdb78f9bec21ba16be8f262de1444 (commit)
       via  13c0ec4ad441cee62c5671caa9fe1168cb7f951b (commit)
       via  0bce0b02d8a24890e5ceee54c95504e66eb19856 (commit)
       via  d4450e4bb95de561de54c6319596bf5637062337 (commit)
      from  c76a4aead2660f417608eead5cdff81f04021220 (commit)


- Log -----------------------------------------------------------------
commit 05ec6a25f80ac8edfb7d7cb764d2dd68156a6965
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 12:27:30 2016 +0100

    Fix up error codes after splitting up tls_construct_key_exchange()
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit a7a752285a4fdb716fa5e184b84fe1474de6dbcf
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 11:09:02 2016 +0100

    Some tidy ups after the CKE construction refactor
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 840a2bf8eccc5efa77f84e8470b33ac0c64bb020
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 10:43:59 2016 +0100

    Split out SRP CKE construction into a separate function
    
    Continuing previous commit to break up the
    tls_construct_client_key_exchange() function. This splits out the SRP
    code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e00e0b3d84719e80ed5a8fd48c1162537c2fa12c
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 10:07:55 2016 +0100

    Split out GOST CKE construction into a separate function
    
    Continuing previous commit to break up the
    tls_construct_client_key_exchange() function. This splits out the GOST
    code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 67ad5aabe6b6d60ac27f6a4b10e7b1ba65113829
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 09:51:02 2016 +0100

    Split out DHE CKE construction into a separate function
    
    Continuing previous commit to break up the
    tls_construct_client_key_exchange() function. This splits out the ECDHE
    code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit a8c1c7040aabdb78f9bec21ba16be8f262de1444
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 09:42:07 2016 +0100

    Split out DHE CKE construction into a separate function
    
    Continuing previous commit to break up the
    tls_construct_client_key_exchange() function. This splits out the DHE
    code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 13c0ec4ad441cee62c5671caa9fe1168cb7f951b
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 7 14:42:27 2016 +0100

    Split out CKE construction PSK pre-amble and RSA into a separate function
    
    The tls_construct_client_key_exchange() function is too long. This splits
    out the construction of the PSK pre-amble into a separate function as well
    as the RSA construction.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 0bce0b02d8a24890e5ceee54c95504e66eb19856
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 7 12:47:07 2016 +0100

    Narrow the scope of local variables in tls_construct_client_key_exchange()
    
    This is in preparation for splitting up this over long function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d4450e4bb95de561de54c6319596bf5637062337
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 7 15:51:17 2016 +0100

    Fix bug with s2n et al macros
    
    The parameters should have parens around them when used.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h    |   6 +
 ssl/ssl_err.c            |   7 +
 ssl/ssl_locl.h           |  24 +-
 ssl/statem/statem_clnt.c | 767 +++++++++++++++++++++++++----------------------
 4 files changed, 437 insertions(+), 367 deletions(-)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1e50e7e..8dcd525 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2203,6 +2203,12 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_TLS1_SET_SERVER_SIGALGS                    335
 # define SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK          354
 # define SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST          372
+# define SSL_F_TLS_CONSTRUCT_CKE_DHE                      404
+# define SSL_F_TLS_CONSTRUCT_CKE_ECDHE                    405
+# define SSL_F_TLS_CONSTRUCT_CKE_GOST                     406
+# define SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE             407
+# define SSL_F_TLS_CONSTRUCT_CKE_RSA                      409
+# define SSL_F_TLS_CONSTRUCT_CKE_SRP                      410
 # define SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE           355
 # define SSL_F_TLS_CONSTRUCT_CLIENT_HELLO                 356
 # define SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE          357
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index b69e91c..5192168 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -231,6 +231,13 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_client_key_exchange_post_work"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST),
      "tls_construct_certificate_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_DHE), "tls_construct_cke_dhe"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_ECDHE), "tls_construct_cke_ecdhe"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_GOST), "tls_construct_cke_gost"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE),
+     "tls_construct_cke_psk_preamble"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_RSA), "tls_construct_cke_rsa"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CKE_SRP), "tls_construct_cke_srp"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE),
      "tls_construct_client_certificate"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 8287077..1cc63aa 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -141,18 +141,18 @@
                                 } \
                         }
 
-# define n2s(c,s)        ((s=(((unsigned int)(c[0]))<< 8)| \
-                            (((unsigned int)(c[1]))    )),c+=2)
-# define s2n(s,c)        ((c[0]=(unsigned char)(((s)>> 8)&0xff), \
-                          c[1]=(unsigned char)(((s)    )&0xff)),c+=2)
-
-# define n2l3(c,l)       ((l =(((unsigned long)(c[0]))<<16)| \
-                             (((unsigned long)(c[1]))<< 8)| \
-                             (((unsigned long)(c[2]))    )),c+=3)
-
-# define l2n3(l,c)       ((c[0]=(unsigned char)(((l)>>16)&0xff), \
-                          c[1]=(unsigned char)(((l)>> 8)&0xff), \
-                          c[2]=(unsigned char)(((l)    )&0xff)),c+=3)
+# define n2s(c,s)        ((s=(((unsigned int)((c)[0]))<< 8)| \
+                             (((unsigned int)((c)[1]))    )),(c)+=2)
+# define s2n(s,c)        (((c)[0]=(unsigned char)(((s)>> 8)&0xff), \
+                           (c)[1]=(unsigned char)(((s)    )&0xff)),(c)+=2)
+
+# define n2l3(c,l)       ((l =(((unsigned long)((c)[0]))<<16)| \
+                              (((unsigned long)((c)[1]))<< 8)| \
+                              (((unsigned long)((c)[2]))    )),(c)+=3)
+
+# define l2n3(l,c)       (((c)[0]=(unsigned char)(((l)>>16)&0xff), \
+                           (c)[1]=(unsigned char)(((l)>> 8)&0xff), \
+                           (c)[2]=(unsigned char)(((l)    )&0xff)),(c)+=3)
 
 #define DTLS_VERSION_GT(v1, v2) ((v1) < (v2))
 #define DTLS_VERSION_GE(v1, v2) ((v1) <= (v2))
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index bcbb0fd..60aecdb 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2012,426 +2012,483 @@ MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
         return MSG_PROCESS_FINISHED_READING;
 }
 
-int tls_construct_client_key_exchange(SSL *s)
+static int tls_construct_cke_psk_preamble(SSL *s, unsigned char **p,
+                                          size_t *pskhdrlen, int *al)
 {
-    unsigned char *p;
-    int n;
 #ifndef OPENSSL_NO_PSK
-    size_t pskhdrlen = 0;
+    int ret = 0;
+    /*
+     * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
+     * \0-terminated identity. The last byte is for us for simulating
+     * strnlen.
+     */
+    char identity[PSK_MAX_IDENTITY_LEN + 1];
+    size_t identitylen = 0;
+    unsigned char psk[PSK_MAX_PSK_LEN];
+    unsigned char *tmppsk = NULL;
+    char *tmpidentity = NULL;
+    size_t psklen = 0;
+
+    if (s->psk_client_callback == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, SSL_R_PSK_NO_CLIENT_CB);
+        *al = SSL_AD_INTERNAL_ERROR;
+        goto err;
+    }
+
+    memset(identity, 0, sizeof(identity));
+
+    psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
+                                    identity, sizeof(identity) - 1,
+                                    psk, sizeof(psk));
+
+    if (psklen > PSK_MAX_PSK_LEN) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        goto err;
+    } else if (psklen == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE,
+               SSL_R_PSK_IDENTITY_NOT_FOUND);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        goto err;
+    }
+
+    identitylen = strlen(identity);
+    if (identitylen > PSK_MAX_IDENTITY_LEN) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        goto err;
+    }
+
+    tmppsk = OPENSSL_memdup(psk, psklen);
+    tmpidentity = OPENSSL_strdup(identity);
+    if (tmppsk == NULL || tmpidentity == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_MALLOC_FAILURE);
+        *al = SSL_AD_INTERNAL_ERROR;
+        goto err;
+    }
+
+    OPENSSL_free(s->s3->tmp.psk);
+    s->s3->tmp.psk = tmppsk;
+    s->s3->tmp.psklen = psklen;
+    tmppsk = NULL;
+    OPENSSL_free(s->session->psk_identity);
+    s->session->psk_identity = tmpidentity;
+    tmpidentity = NULL;
+    s2n(identitylen, *p);
+    memcpy(*p, identity, identitylen);
+    *pskhdrlen = 2 + identitylen;
+    *p += identitylen;
+
+    ret = 1;
+
+ err:
+    OPENSSL_cleanse(psk, psklen);
+    OPENSSL_cleanse(identity, sizeof(identity));
+    OPENSSL_clear_free(tmppsk, psklen);
+    OPENSSL_clear_free(tmpidentity, identitylen);
+
+    return ret;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
-    unsigned long alg_k;
+}
+
+static int tls_construct_cke_rsa(SSL *s, unsigned char **p, int *len, int *al)
+{
 #ifndef OPENSSL_NO_RSA
     unsigned char *q;
     EVP_PKEY *pkey = NULL;
     EVP_PKEY_CTX *pctx = NULL;
-#endif
-#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
-    EVP_PKEY *ckey = NULL, *skey = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    unsigned char *encodedPoint = NULL;
-    int encoded_pt_len = 0;
-#endif
+    size_t enclen;
     unsigned char *pms = NULL;
     size_t pmslen = 0;
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
-    p = ssl_handshake_start(s);
-
-
-#ifndef OPENSSL_NO_PSK
-    if (alg_k & SSL_PSK) {
-        int psk_err = 1;
+    if (s->session->peer == NULL) {
         /*
-         * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
-         * \0-terminated identity. The last byte is for us for simulating
-         * strnlen.
+         * We should always have a server certificate with SSL_kRSA.
          */
-        char identity[PSK_MAX_IDENTITY_LEN + 1];
-        size_t identitylen;
-        unsigned char psk[PSK_MAX_PSK_LEN];
-        size_t psklen;
-
-        if (s->psk_client_callback == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_NO_CLIENT_CB);
-            goto err;
-        }
-
-        memset(identity, 0, sizeof(identity));
-
-        psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
-                                        identity, sizeof(identity) - 1,
-                                        psk, sizeof(psk));
-
-        if (psklen > PSK_MAX_PSK_LEN) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        } else if (psklen == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_IDENTITY_NOT_FOUND);
-            goto psk_err;
-        }
-        OPENSSL_free(s->s3->tmp.psk);
-        s->s3->tmp.psk = OPENSSL_memdup(psk, psklen);
-        OPENSSL_cleanse(psk, psklen);
-
-        if (s->s3->tmp.psk == NULL) {
-            OPENSSL_cleanse(identity, sizeof(identity));
-            goto memerr;
-        }
-
-        s->s3->tmp.psklen = psklen;
-        identitylen = strlen(identity);
-        if (identitylen > PSK_MAX_IDENTITY_LEN) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        }
-        OPENSSL_free(s->session->psk_identity);
-        s->session->psk_identity = OPENSSL_strdup(identity);
-        if (s->session->psk_identity == NULL) {
-            OPENSSL_cleanse(identity, sizeof(identity));
-            goto memerr;
-        }
-
-        s2n(identitylen, p);
-        memcpy(p, identity, identitylen);
-        pskhdrlen = 2 + identitylen;
-        p += identitylen;
-        psk_err = 0;
-psk_err:
-        OPENSSL_cleanse(identity, sizeof(identity));
-        if (psk_err != 0) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-            goto err;
-        }
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
-    if (alg_k & SSL_kPSK) {
-        n = 0;
-    } else
-#endif
 
-    /* Fool emacs indentation */
-    if (0) {
+    pkey = X509_get0_pubkey(s->session->peer);
+    if (EVP_PKEY_get0_RSA(pkey) == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
-#ifndef OPENSSL_NO_RSA
-    else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-        size_t enclen;
-        pmslen = SSL_MAX_MASTER_KEY_LENGTH;
-        pms = OPENSSL_malloc(pmslen);
-        if (pms == NULL)
-            goto memerr;
-
-        if (s->session->peer == NULL) {
-            /*
-             * We should always have a server certificate with SSL_kRSA.
-             */
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
 
-        pkey = X509_get0_pubkey(s->session->peer);
-        if (EVP_PKEY_get0_RSA(pkey) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
+    pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_MALLOC_FAILURE);
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
 
-        pms[0] = s->client_version >> 8;
-        pms[1] = s->client_version & 0xff;
-        if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
-            goto err;
+    pms[0] = s->client_version >> 8;
+    pms[1] = s->client_version & 0xff;
+    if (RAND_bytes(pms + 2, pmslen - 2) <= 0) {
+        goto err;
+    }
 
-        q = p;
-        /* Fix buf for TLS and beyond */
-        if (s->version > SSL3_VERSION)
-            p += 2;
-        pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0
-            || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_EVP_LIB);
-            goto err;
-        }
-        if (EVP_PKEY_encrypt(pctx, p, &enclen, pms, pmslen) <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_BAD_RSA_ENCRYPT);
-            goto err;
-        }
-        n = enclen;
-        EVP_PKEY_CTX_free(pctx);
-        pctx = NULL;
+    q = *p;
+    /* Fix buf for TLS and beyond */
+    if (s->version > SSL3_VERSION)
+        *p += 2;
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0
+        || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (EVP_PKEY_encrypt(pctx, *p, &enclen, pms, pmslen) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, SSL_R_BAD_RSA_ENCRYPT);
+        goto err;
+    }
+    *len = enclen;
+    EVP_PKEY_CTX_free(pctx);
+    pctx = NULL;
 # ifdef PKCS1_CHECK
-        if (s->options & SSL_OP_PKCS1_CHECK_1)
-            p[1]++;
-        if (s->options & SSL_OP_PKCS1_CHECK_2)
-            tmp_buf[0] = 0x70;
+    if (s->options & SSL_OP_PKCS1_CHECK_1)
+        (*p)[1]++;
+    if (s->options & SSL_OP_PKCS1_CHECK_2)
+        tmp_buf[0] = 0x70;
 # endif
 
-        /* Fix buf for TLS and beyond */
-        if (s->version > SSL3_VERSION) {
-            s2n(n, q);
-            n += 2;
-        }
+    /* Fix buf for TLS and beyond */
+    if (s->version > SSL3_VERSION) {
+        s2n(*len, q);
+        *len += 2;
     }
+
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_PKEY_CTX_free(pctx);
+
+    return 0;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
-#ifndef OPENSSL_NO_DH
-    else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
-        DH *dh_clnt = NULL;
-        const BIGNUM *pub_key;
-        skey = s->s3->peer_tmp;
-        if (skey == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        ckey = ssl_generate_pkey(skey, NID_undef);
-        dh_clnt = EVP_PKEY_get0_DH(ckey);
+}
 
-        if (dh_clnt == NULL || ssl_derive(s, ckey, skey) == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
+static int tls_construct_cke_dhe(SSL *s, unsigned char **p, int *len, int *al)
+{
+#ifndef OPENSSL_NO_DH
+    DH *dh_clnt = NULL;
+    const BIGNUM *pub_key;
+    EVP_PKEY *ckey = NULL, *skey = NULL;
 
+    skey = s->s3->peer_tmp;
+    if (skey == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    ckey = ssl_generate_pkey(skey, NID_undef);
+    dh_clnt = EVP_PKEY_get0_DH(ckey);
 
-        /* send off the data */
-        DH_get0_key(dh_clnt, &pub_key, NULL);
-        n = BN_num_bytes(pub_key);
-        s2n(n, p);
-        BN_bn2bin(pub_key, p);
-        n += 2;
+    if (dh_clnt == NULL || ssl_derive(s, ckey, skey) == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR);
         EVP_PKEY_free(ckey);
-        ckey = NULL;
+        return 0;
     }
+
+    /* send off the data */
+    DH_get0_key(dh_clnt, &pub_key, NULL);
+    *len = BN_num_bytes(pub_key);
+    s2n(*len, *p);
+    BN_bn2bin(pub_key, *p);
+    *len += 2;
+    EVP_PKEY_free(ckey);
+
+    return 1;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
+}
 
+static int tls_construct_cke_ecdhe(SSL *s, unsigned char **p, int *len, int *al)
+{
 #ifndef OPENSSL_NO_EC
-    else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+    unsigned char *encodedPoint = NULL;
+    int encoded_pt_len = 0;
+    EVP_PKEY *ckey = NULL, *skey = NULL;
 
-        skey = s->s3->peer_tmp;
-        if ((skey == NULL) || EVP_PKEY_get0_EC_KEY(skey) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-            goto err;
-            }
+    skey = s->s3->peer_tmp;
+    if ((skey == NULL) || EVP_PKEY_get0_EC_KEY(skey) == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
 
-        ckey = ssl_generate_pkey(skey, NID_undef);
+    ckey = ssl_generate_pkey(skey, NID_undef);
 
-        if (ssl_derive(s, ckey, skey) == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EVP_LIB);
-            goto err;
-        }
+    if (ssl_derive(s, ckey, skey) == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EVP_LIB);
+        goto err;
+    }
 
-        /* Generate encoding of client key */
-        encoded_pt_len = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(ckey),
-                                        POINT_CONVERSION_UNCOMPRESSED,
-                                        &encodedPoint, NULL);
+    /* Generate encoding of client key */
+    encoded_pt_len = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(ckey),
+                                    POINT_CONVERSION_UNCOMPRESSED,
+                                    &encodedPoint, NULL);
 
-        if (encoded_pt_len == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
+    if (encoded_pt_len == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EC_LIB);
+        goto err;
+    }
 
-        EVP_PKEY_free(ckey);
-        ckey = NULL;
+    EVP_PKEY_free(ckey);
+    ckey = NULL;
 
-        n = encoded_pt_len;
+    *len = encoded_pt_len;
 
-        *p = n;         /* length of encoded point */
-        /* Encoded point will be copied here */
-        p += 1;
-        /* copy the point */
-        memcpy(p, encodedPoint, n);
-        /* increment n to account for length field */
-        n += 1;
+    /* length of encoded point */
+    **p = *len;
+    *p += 1;
+    /* copy the point */
+    memcpy(*p, encodedPoint, *len);
+    /* increment len to account for length field */
+    *len += 1;
 
-        /* Free allocated memory */
-        OPENSSL_free(encodedPoint);
-    }
-#endif                          /* !OPENSSL_NO_EC */
+    OPENSSL_free(encodedPoint);
+
+    return 1;
+ err:
+    EVP_PKEY_free(ckey);
+    return 0;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
+#endif
+}
+
+static int tls_construct_cke_gost(SSL *s, unsigned char **p, int *len, int *al)
+{
 #ifndef OPENSSL_NO_GOST
-    else if (alg_k & SSL_kGOST) {
-        /* GOST key exchange message creation */
-        EVP_PKEY_CTX *pkey_ctx;
-        X509 *peer_cert;
-        size_t msglen;
-        unsigned int md_len;
-        unsigned char shared_ukm[32], tmp[256];
-        EVP_MD_CTX *ukm_hash;
-        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 == NULL)
-            goto memerr;
+    /* GOST key exchange message creation */
+    EVP_PKEY_CTX *pkey_ctx = NULL;
+    X509 *peer_cert;
+    size_t msglen;
+    unsigned int md_len;
+    unsigned char shared_ukm[32], tmp[256];
+    EVP_MD_CTX *ukm_hash = NULL;
+    int dgst_nid = NID_id_GostR3411_94;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
 
-        /*
-         * Get server sertificate PKEY and create ctx from it
-         */
-        peer_cert = s->session->peer;
-        if (!peer_cert) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
-            goto err;
-        }
+    if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0)
+        dgst_nid = NID_id_GostR3411_2012_256;
 
-        pkey_ctx = EVP_PKEY_CTX_new(X509_get0_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
-         * certificate key for key exchange
-         */
+    /*
+     * Get server sertificate PKEY and create ctx from it
+     */
+    peer_cert = s->session->peer;
+    if (!peer_cert) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST,
+               SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+        return 0;
+    }
 
-        /* Otherwise, generate ephemeral key pair */
+    pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL);
+    if (pkey_ctx == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    /*
+     * If we have send a certificate, and certificate key
+     * parameters match those of server certificate, use
+     * certificate key for key exchange
+     */
 
-        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);
-            goto err;
-        };
-        /*
-         * If we have client certificate, use its secret as peer key
-         */
-        if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
-            if (EVP_PKEY_derive_set_peer
-                (pkey_ctx, s->cert->key->privatekey) <= 0) {
-                /*
-                 * If there was an error - just ignore it. Ephemeral key
-                 * * would be used
-                 */
-                ERR_clear_error();
-            }
-        }
-        /*
-         * Compute shared IV and store it in algorithm-specific context
-         * data
-         */
-        ukm_hash = EVP_MD_CTX_new();
-        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_free(ukm_hash);
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        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) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_LIBRARY_BUG);
-            goto err;
-        }
-        /* Make GOST keytransport blob message */
-        /*
-         * Encapsulate it into sequence
-         */
-        *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
-        msglen = 255;
-        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;
-        }
-        if (msglen >= 0x80) {
-            *(p++) = 0x81;
-            *(p++) = msglen & 0xff;
-            n = msglen + 3;
-        } else {
-            *(p++) = msglen & 0xff;
-            n = msglen + 2;
-        }
-        memcpy(p, tmp, msglen);
-        /* 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) {
-            /* Set flag "skip certificate verify" */
-            s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+    /* Otherwise, generate ephemeral key pair */
+    pmslen = 32;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0
+            /* Generate session key */
+            || RAND_bytes(pms, pmslen) <= 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    };
+    /*
+     * If we have client certificate, use its secret as peer key
+     */
+    if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+        if (EVP_PKEY_derive_set_peer
+            (pkey_ctx, s->cert->key->privatekey) <= 0) {
+            /*
+             * If there was an error - just ignore it. Ephemeral key
+             * * would be used
+             */
+            ERR_clear_error();
         }
-        EVP_PKEY_CTX_free(pkey_ctx);
+    }
+    /*
+     * Compute shared IV and store it in algorithm-specific context
+     * data
+     */
+    ukm_hash = EVP_MD_CTX_new();
+    if (ukm_hash == NULL
+            || 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) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    EVP_MD_CTX_free(ukm_hash);
+    ukm_hash = NULL;
+    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
+                          EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+    /* Make GOST keytransport blob message */
+    /*
+     * Encapsulate it into sequence
+     */
+    *((*p)++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+    msglen = 255;
+    if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, SSL_R_LIBRARY_BUG);
+        goto err;
+    }
+    if (msglen >= 0x80) {
+        *((*p)++) = 0x81;
+        *((*p)++) = msglen & 0xff;
+        *len = msglen + 3;
+    } else {
+        *((*p)++) = msglen & 0xff;
+        *len = msglen + 2;
+    }
+    memcpy(*p, tmp, msglen);
+    /* 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) {
+        /* Set flag "skip certificate verify" */
+        s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+    }
+    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);
+    EVP_MD_CTX_free(ukm_hash);
+    return 0;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
+#endif
+}
 
+static int tls_construct_cke_srp(SSL *s, unsigned char **p, int *len, int *al)
+{
+#ifndef OPENSSL_NO_SRT
+    if (s->srp_ctx.A != NULL) {
+        /* send off the data */
+        *len = BN_num_bytes(s->srp_ctx.A);
+        s2n(*len, *p);
+        BN_bn2bin(s->srp_ctx.A, *p);
+        *len += 2;
+    } else {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
+    OPENSSL_free(s->session->srp_username);
+    s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login);
+    if (s->session->srp_username == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    return 1;
+#else
+    SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
-#ifndef OPENSSL_NO_SRP
-    else if (alg_k & SSL_kSRP) {
-        if (s->srp_ctx.A != NULL) {
-            /* send off the data */
-            n = BN_num_bytes(s->srp_ctx.A);
-            s2n(n, p);
-            BN_bn2bin(s->srp_ctx.A, p);
-            n += 2;
-        } else {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
+}
+
+int tls_construct_client_key_exchange(SSL *s)
+{
+    unsigned char *p;
+    int len;
+    size_t pskhdrlen = 0;
+    unsigned long alg_k;
+    int al = -1;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    p = ssl_handshake_start(s);
+
+    if ((alg_k & SSL_PSK)
+            && !tls_construct_cke_psk_preamble(s, &p, &pskhdrlen, &al))
+        goto err;
+
+    if (alg_k & SSL_kPSK) {
+        len = 0;
+    } else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        if (!tls_construct_cke_rsa(s, &p, &len, &al))
             goto err;
-        }
-        OPENSSL_free(s->session->srp_username);
-        s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login);
-        if (s->session->srp_username == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
+    } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (!tls_construct_cke_dhe(s, &p, &len, &al))
             goto err;
-        }
-    }
-#endif
-    else {
+    } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        if (!tls_construct_cke_ecdhe(s, &p, &len, &al))
+            goto err;
+    } else if (alg_k & SSL_kGOST) {
+        if (!tls_construct_cke_gost(s, &p, &len, &al))
+            goto err;
+    } else if (alg_k & SSL_kSRP) {
+        if (!tls_construct_cke_srp(s, &p, &len, &al))
+            goto err;
+    } else {
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
-#ifndef OPENSSL_NO_PSK
-    n += pskhdrlen;
-#endif
+    len += pskhdrlen;
 
-    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
+    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, len)) {
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
-    if (pms != NULL) {
-        s->s3->tmp.pms = pms;
-        s->s3->tmp.pmslen = pmslen;
-    }
-
     return 1;
- memerr:
-    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-    SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
  err:
-    OPENSSL_clear_free(pms, pmslen);
+    if (al != -1)
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    OPENSSL_clear_free(s->s3->tmp.pms, s->s3->tmp.pmslen);
     s->s3->tmp.pms = NULL;
-#ifndef OPENSSL_NO_RSA
-    EVP_PKEY_CTX_free(pctx);
-#endif
-#ifndef OPENSSL_NO_EC
-    OPENSSL_free(encodedPoint);
-#endif
-#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
-    EVP_PKEY_free(ckey);
-#endif
 #ifndef OPENSSL_NO_PSK
     OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
     s->s3->tmp.psk = NULL;


More information about the openssl-commits mailing list