[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Tue Feb 3 14:54:11 UTC 2015


The branch master has been updated
       via  156a872233b56558c72561789b8f33ff71a88fa7 (commit)
       via  6668b6b8b0c1bcb6c6168ab22159a12cac41ae79 (commit)
       via  c536461499a3e93166921181847b3ed9b2d85c7d (commit)
       via  0cfb0e75b9dbf1a605c47e1b79c76d43a1f8344d (commit)
       via  ddc06b35565d9f2888e8d946ee7ae292bc902afd (commit)
       via  c660ec63a83090051f3e110b00bd5753f21bce51 (commit)
       via  48fbcbacd2b22ab8d1bd9203a8fdc316eaab62f1 (commit)
       via  6f152a15d433c249b4b73d0a7968d4ea63925a24 (commit)
      from  52e028b9de371da62c1e51b46592517b1068d770 (commit)


- Log -----------------------------------------------------------------
commit 156a872233b56558c72561789b8f33ff71a88fa7
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Jan 24 17:09:55 2015 +0000

    Add SSL_get_extms_support documentation.
    
    Document SSL_get_extms_support().
    
    Modify behaviour of SSL_get_extms_support() so it returns -1 if the
    master secret support of the peer is not known (e.g. handshake in progress).
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit 6668b6b8b0c1bcb6c6168ab22159a12cac41ae79
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 14:03:48 2015 +0000

    Add CHANGES entry.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit c536461499a3e93166921181847b3ed9b2d85c7d
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:52:20 2015 +0000

    Ctrl to retrieve extms support.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit 0cfb0e75b9dbf1a605c47e1b79c76d43a1f8344d
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:49:16 2015 +0000

    Add extms support to master key generation.
    
    Update master secret calculation to support extended master secret.
    TLS 1.2 client authentication adds a complication because we need to
    cache the handshake messages. This is simpllified however because
    the point at which the handshake hashes are calculated for extended
    master secret is identical to that required for TLS 1.2 client
    authentication (immediately after client key exchange which is also
    immediately before certificate verify).
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit ddc06b35565d9f2888e8d946ee7ae292bc902afd
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:45:13 2015 +0000

    Extended master secret extension support.
    
    Add and retrieve extended master secret extension, setting the flag
    SSL_SESS_FLAG_EXTMS appropriately.
    
    Note: this just sets the flag and doesn't include the changes to
    master secret generation.
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit c660ec63a83090051f3e110b00bd5753f21bce51
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:41:09 2015 +0000

    Rewrite ssl3_send_client_key_exchange to support extms.
    
    Rewrite ssl3_send_client_key_exchange to retain the premaster secret
    instead of using it immediately.
    
    This is needed because the premaster secret is used after the client key
    exchange message has been sent to compute the extended master secret.
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit 48fbcbacd2b22ab8d1bd9203a8fdc316eaab62f1
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:37:27 2015 +0000

    Utility function to retrieve handshake hashes.
    
    Retrieve handshake hashes in a separate function. This tidies the existing
    code and will be used for extended master secret generation.
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit 6f152a15d433c249b4b73d0a7968d4ea63925a24
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jan 23 02:29:50 2015 +0000

    Add flags field to SSL_SESSION.
    
    Add a "flags" field to SSL_SESSION. This will contain various flags
    such as encrypt-then-mac and extended master secret support.
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

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

Summary of changes:
 CHANGES                           |    6 ++
 doc/ssl/SSL_get_extms_support.pod |   33 ++++++
 ssl/d1_srvr.c                     |   16 +--
 ssl/s3_clnt.c                     |  200 +++++++++++++++++++++----------------
 ssl/s3_srvr.c                     |   16 +--
 ssl/ssl.h                         |    4 +
 ssl/ssl_asn1.c                    |   23 +++++
 ssl/ssl_cert.c                    |    5 +
 ssl/ssl_lib.c                     |   36 +++++++
 ssl/ssl_locl.h                    |   10 ++
 ssl/ssl_txt.c                     |    4 +
 ssl/t1_enc.c                      |   94 ++++++++---------
 ssl/t1_lib.c                      |   14 +++
 ssl/t1_trce.c                     |    3 +-
 ssl/tls1.h                        |   15 ++-
 15 files changed, 330 insertions(+), 149 deletions(-)
 create mode 100644 doc/ssl/SSL_get_extms_support.pod

diff --git a/CHANGES b/CHANGES
index 11176ce..8fcfcce 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,12 @@
  _______________
 
  Changes between 1.0.2 and 1.1.0  [xx XXX xxxx]
+
+  *) Added support for TLS extended master secret from
+     draft-ietf-tls-session-hash-03.txt. Thanks for Alfredo Pironti for an
+     initial patch which was a great help during development.
+     [Steve Henson]
+
   *) All libssl internal structures have been removed from the public header
      files, and the OPENSSL_NO_SSL_INTERN option has been removed (since it is
      now redundant). Users should not attempt to access internal structures
diff --git a/doc/ssl/SSL_get_extms_support.pod b/doc/ssl/SSL_get_extms_support.pod
new file mode 100644
index 0000000..427819a
--- /dev/null
+++ b/doc/ssl/SSL_get_extms_support.pod
@@ -0,0 +1,33 @@
+=pod
+
+=head1 NAME
+
+SSL_get_extms_support - extended master secret support
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_get_extms_support(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_get_extms_support() indicates whether the current session used extended
+master secret.
+
+This function is implemented as a macro.
+
+=head1 RETURN VALUES
+
+SSL_get_extms_support() returns 1 if the current session used extended
+master secret, 0 if it did not and -1 if a handshake is currently in
+progress i.e. it is not possible to determine if extended master secret
+was used.
+
+=back
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>
+
+=cut
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 1ccdc35..55d37e7 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -655,17 +655,19 @@ int dtls1_accept(SSL *s)
                 s->init_num = 0;
                 if (!s->session->peer)
                     break;
-                /*
-                 * For sigalgs freeze the handshake buffer at this point and
-                 * digest cached records.
-                 */
                 if (!s->s3->handshake_buffer) {
                     SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
                     return -1;
                 }
-                s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-                if (!ssl3_digest_cached_records(s))
-                    return -1;
+                /*
+                 * For sigalgs freeze the handshake buffer. If we support
+                 * extms we've done this already.
+                 */
+                if (!(s->s3->flags & SSL_SESS_FLAG_EXTMS)) {
+                    s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+                    if (!ssl3_digest_cached_records(s))
+                        return -1;
+                }
             } else {
                 s->state = SSL3_ST_SR_CERT_VRFY_A;
                 s->init_num = 0;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index a383eee..5e2b543 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -2338,6 +2338,8 @@ int ssl3_send_client_key_exchange(SSL *s)
     int encoded_pt_len = 0;
     BN_CTX *bn_ctx = NULL;
 #endif
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
 
     if (s->state == SSL3_ST_CW_KEY_EXCH_A) {
         p = ssl_handshake_start(s);
@@ -2350,7 +2352,10 @@ int ssl3_send_client_key_exchange(SSL *s)
 #ifndef OPENSSL_NO_RSA
         else if (alg_k & SSL_kRSA) {
             RSA *rsa;
-            unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+            pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
 
             if (s->session->sess_cert == NULL) {
                 /*
@@ -2378,19 +2383,16 @@ int ssl3_send_client_key_exchange(SSL *s)
                 EVP_PKEY_free(pkey);
             }
 
-            tmp_buf[0] = s->client_version >> 8;
-            tmp_buf[1] = s->client_version & 0xff;
-            if (RAND_bytes(&(tmp_buf[2]), sizeof tmp_buf - 2) <= 0)
+            pms[0] = s->client_version >> 8;
+            pms[1] = s->client_version & 0xff;
+            if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
                 goto err;
 
-            s->session->master_key_length = sizeof tmp_buf;
-
             q = p;
             /* Fix buf for TLS and beyond */
             if (s->version > SSL3_VERSION)
                 p += 2;
-            n = RSA_public_encrypt(sizeof tmp_buf,
-                                   tmp_buf, p, rsa, RSA_PKCS1_PADDING);
+            n = RSA_public_encrypt(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
 # ifdef PKCS1_CHECK
             if (s->options & SSL_OP_PKCS1_CHECK_1)
                 p[1]++;
@@ -2408,14 +2410,6 @@ int ssl3_send_client_key_exchange(SSL *s)
                 s2n(n, q);
                 n += 2;
             }
-
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            tmp_buf,
-                                                            sizeof tmp_buf);
-            OPENSSL_cleanse(tmp_buf, sizeof tmp_buf);
         }
 #endif
 #ifndef OPENSSL_NO_KRB5
@@ -2505,9 +2499,14 @@ int ssl3_send_client_key_exchange(SSL *s)
                 n += 2;
             }
 
-            tmp_buf[0] = s->client_version >> 8;
-            tmp_buf[1] = s->client_version & 0xff;
-            if (RAND_bytes(&(tmp_buf[2]), sizeof tmp_buf - 2) <= 0)
+            pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
+
+            pms[0] = s->client_version >> 8;
+            pms[1] = s->client_version & 0xff;
+            if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
                 goto err;
 
             /*-
@@ -2520,8 +2519,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 
             memset(iv, 0, sizeof iv); /* per RFC 1510 */
             EVP_EncryptInit_ex(&ciph_ctx, enc, NULL, kssl_ctx->key, iv);
-            EVP_EncryptUpdate(&ciph_ctx, epms, &outl, tmp_buf,
-                              sizeof tmp_buf);
+            EVP_EncryptUpdate(&ciph_ctx, epms, &outl, pms, pmslen);
             EVP_EncryptFinal_ex(&ciph_ctx, &(epms[outl]), &padl);
             outl += padl;
             if (outl > (int)sizeof epms) {
@@ -2536,15 +2534,6 @@ int ssl3_send_client_key_exchange(SSL *s)
             memcpy(p, epms, outl);
             p += outl;
             n += outl + 2;
-
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            tmp_buf,
-                                                            sizeof tmp_buf);
-
-            OPENSSL_cleanse(tmp_buf, sizeof tmp_buf);
             OPENSSL_cleanse(epms, outl);
         }
 #endif
@@ -2603,12 +2592,17 @@ int ssl3_send_client_key_exchange(SSL *s)
                 }
             }
 
+            pmslen = DH_size(dh_clnt);
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
+
             /*
              * use the 'p' output buffer for the DH key, but make sure to
              * clear it out afterwards
              */
 
-            n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt);
+            n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
             if (scert->peer_dh_tmp == NULL)
                 DH_free(dh_srvr);
 
@@ -2618,15 +2612,6 @@ int ssl3_send_client_key_exchange(SSL *s)
                 goto err;
             }
 
-            /* generate master key from the result */
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            p, n);
-            /* clean up */
-            memset(p, 0, n);
-
             if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
                 n = 0;
             else {
@@ -2758,22 +2743,16 @@ int ssl3_send_client_key_exchange(SSL *s)
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
                 goto err;
             }
-            n = ECDH_compute_key(p, (field_size + 7) / 8, srvr_ecpoint,
-                                 clnt_ecdh, NULL);
-            if (n <= 0) {
+            pmslen = (field_size + 7) / 8;
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
+            n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
+            if (n <= 0 || pmslen != (size_t)n) {
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
                 goto err;
             }
 
-            /* generate master key from the result */
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            p, n);
-
-            memset(p, 0, n);    /* clean up */
-
             if (ecdh_clnt_cert) {
                 /* Send empty client key exch message */
                 n = 0;
@@ -2828,10 +2807,15 @@ int ssl3_send_client_key_exchange(SSL *s)
             size_t msglen;
             unsigned int md_len;
             int keytype;
-            unsigned char premaster_secret[32], shared_ukm[32], tmp[256];
+            unsigned char shared_ukm[32], tmp[256];
             EVP_MD_CTX *ukm_hash;
             EVP_PKEY *pub_key;
 
+            pmslen = 32;
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
+
             /*
              * Get server sertificate PKEY and create ctx from it
              */
@@ -2861,7 +2845,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 
             EVP_PKEY_encrypt_init(pkey_ctx);
             /* Generate session key */
-            RAND_bytes(premaster_secret, 32);
+            RAND_bytes(pms, pmslen);
             /*
              * If we have client certificate, use its secret as peer key
              */
@@ -2901,8 +2885,7 @@ int ssl3_send_client_key_exchange(SSL *s)
              */
             *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
             msglen = 255;
-            if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret, 32)
-                < 0) {
+            if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
                        SSL_R_LIBRARY_BUG);
                 goto err;
@@ -2923,12 +2906,6 @@ int ssl3_send_client_key_exchange(SSL *s)
                 s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
             }
             EVP_PKEY_CTX_free(pkey_ctx);
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            premaster_secret,
-                                                            32);
             EVP_PKEY_free(pub_key);
 
         }
@@ -2953,15 +2930,6 @@ int ssl3_send_client_key_exchange(SSL *s)
                        ERR_R_MALLOC_FAILURE);
                 goto err;
             }
-
-            if ((s->session->master_key_length =
-                 SRP_generate_client_master_secret(s,
-                                                   s->session->master_key)) <
-                0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
         }
 #endif
 #ifndef OPENSSL_NO_PSK
@@ -2974,8 +2942,7 @@ int ssl3_send_client_key_exchange(SSL *s)
             char identity[PSK_MAX_IDENTITY_LEN + 2];
             size_t identity_len;
             unsigned char *t = NULL;
-            unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4];
-            unsigned int pre_ms_len = 0, psk_len = 0;
+            unsigned int psk_len = 0;
             int psk_err = 1;
 
             n = 0;
@@ -2986,10 +2953,15 @@ int ssl3_send_client_key_exchange(SSL *s)
             }
 
             memset(identity, 0, sizeof(identity));
+            /* Allocate maximum size buffer */
+            pmslen = PSK_MAX_PSK_LEN * 2 + 4;
+            pms = OPENSSL_malloc(pmslen);
+            if (!pms)
+                goto memerr;
+
             psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
                                              identity, sizeof(identity) - 1,
-                                             psk_or_pre_ms,
-                                             sizeof(psk_or_pre_ms));
+                                             pms, pmslen);
             if (psk_len > PSK_MAX_PSK_LEN) {
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
                        ERR_R_INTERNAL_ERROR);
@@ -2999,6 +2971,8 @@ int ssl3_send_client_key_exchange(SSL *s)
                        SSL_R_PSK_IDENTITY_NOT_FOUND);
                 goto psk_err;
             }
+            /* Change pmslen to real length */
+            pmslen = 2 + psk_len + 2 + psk_len;
             identity[PSK_MAX_IDENTITY_LEN + 1] = '\0';
             identity_len = strlen(identity);
             if (identity_len > PSK_MAX_IDENTITY_LEN) {
@@ -3007,9 +2981,8 @@ int ssl3_send_client_key_exchange(SSL *s)
                 goto psk_err;
             }
             /* create PSK pre_master_secret */
-            pre_ms_len = 2 + psk_len + 2 + psk_len;
-            t = psk_or_pre_ms;
-            memmove(psk_or_pre_ms + psk_len + 4, psk_or_pre_ms, psk_len);
+            t = pms;
+            memmove(pms + psk_len + 4, pms, psk_len);
             s2n(psk_len, t);
             memset(t, 0, psk_len);
             t += psk_len;
@@ -3035,19 +3008,12 @@ int ssl3_send_client_key_exchange(SSL *s)
                 goto psk_err;
             }
 
-            s->session->master_key_length =
-                s->method->ssl3_enc->generate_master_secret(s,
-                                                            s->
-                                                            session->master_key,
-                                                            psk_or_pre_ms,
-                                                            pre_ms_len);
             s2n(identity_len, p);
             memcpy(p, identity, identity_len);
             n = 2 + identity_len;
             psk_err = 0;
  psk_err:
             OPENSSL_cleanse(identity, sizeof(identity));
-            OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
             if (psk_err != 0) {
                 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
                 goto err;
@@ -3065,8 +3031,60 @@ int ssl3_send_client_key_exchange(SSL *s)
     }
 
     /* SSL3_ST_CW_KEY_EXCH_B */
-    return ssl_do_write(s);
+    n = ssl_do_write(s);
+#ifndef OPENSSL_NO_SRP
+    /* Check for SRP */
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        /*
+         * If everything written generate master key: no need to save PMS as
+         * SRP_generate_client_master_secret generates it internally.
+         */
+        if (n > 0) {
+            if ((s->session->master_key_length =
+                 SRP_generate_client_master_secret(s,
+                                                   s->session->master_key)) <
+                0) {
+                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+    } else
+#endif
+        /* If we haven't written everything save PMS */
+    if (n <= 0) {
+        s->cert->pms = pms;
+        s->cert->pmslen = pmslen;
+    } else {
+        /* If we don't have a PMS restore */
+        if (pms == NULL) {
+            pms = s->cert->pms;
+            pmslen = s->cert->pmslen;
+        }
+        if (pms == NULL) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        s->session->master_key_length =
+            s->method->ssl3_enc->generate_master_secret(s,
+                                                        s->
+                                                        session->master_key,
+                                                        pms, pmslen);
+        OPENSSL_cleanse(pms, pmslen);
+        OPENSSL_free(pms);
+        s->cert->pms = NULL;
+    }
+    return n;
+ memerr:
+    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
  err:
+    if (pms) {
+        OPENSSL_cleanse(pms, pmslen);
+        OPENSSL_free(pms);
+        s->cert->pms = NULL;
+    }
 #ifndef OPENSSL_NO_ECDH
     BN_CTX_free(bn_ctx);
     if (encodedPoint != NULL)
@@ -3132,7 +3150,15 @@ int ssl3_send_client_verify(SSL *s)
             }
             s2n(u, p);
             n = u + 4;
-            if (!ssl3_digest_cached_records(s))
+            /*
+             * For extended master secret we've already digested cached
+             * records.
+             */
+            if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+                BIO_free(s->s3->handshake_buffer);
+                s->s3->handshake_buffer = NULL;
+                s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+            } else if (!ssl3_digest_cached_records(s))
                 goto err;
         } else
 #ifndef OPENSSL_NO_RSA
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index e929658..f31b76a 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -620,17 +620,19 @@ int ssl3_accept(SSL *s)
                 s->init_num = 0;
                 if (!s->session->peer)
                     break;
-                /*
-                 * For sigalgs freeze the handshake buffer at this point and
-                 * digest cached records.
-                 */
                 if (!s->s3->handshake_buffer) {
                     SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
                     return -1;
                 }
-                s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-                if (!ssl3_digest_cached_records(s))
-                    return -1;
+                /*
+                 * For sigalgs freeze the handshake buffer. If we support
+                 * extms we've done this already.
+                 */
+                if (!(s->s3->flags & SSL_SESS_FLAG_EXTMS)) {
+                    s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+                    if (!ssl3_digest_cached_records(s))
+                        return -1;
+                }
             } else {
                 int offset = 0;
                 int dgst_num;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index df91c18..a3b8a81 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -656,6 +656,9 @@ void SSL_set_msg_callback(SSL *ssl,
 # define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
 # define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
 
+# define SSL_get_extms_support(s) \
+        SSL_ctrl((s),SSL_CTRL_GET_EXTMS_SUPPORT,0,NULL)
+
 # ifndef OPENSSL_NO_SRP
 
 /* see tls_srp.c */
@@ -1212,6 +1215,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 # define SSL_CTRL_CHECK_PROTO_VERSION            119
 # define DTLS_CTRL_SET_LINK_MTU                  120
 # define DTLS_CTRL_GET_LINK_MIN_MTU              121
+# define SSL_CTRL_GET_EXTMS_SUPPORT              122
 # define SSL_CERT_SET_FIRST                      1
 # define SSL_CERT_SET_NEXT                       2
 # define SSL_CERT_SET_SERVER                     3
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 3eaee1d..b27e058 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -115,6 +115,7 @@ typedef struct ssl_session_asn1_st {
 #ifndef OPENSSL_NO_SRP
     ASN1_OCTET_STRING srp_username;
 #endif                          /* OPENSSL_NO_SRP */
+    ASN1_INTEGER flags;
 } SSL_SESSION_ASN1;
 
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
@@ -134,6 +135,8 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 #ifndef OPENSSL_NO_SRP
     int v12 = 0;
 #endif
+    unsigned char fbuf[LSIZE2];
+    int v13 = 0;
     long l;
     SSL_SESSION_ASN1 a;
     M_ASN1_I2D_vars(in);
@@ -256,6 +259,13 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
     }
 #endif                          /* OPENSSL_NO_SRP */
 
+    if (in->flags) {
+        a.flags.length = LSIZE2;
+        a.flags.type = V_ASN1_INTEGER;
+        a.flags.data = fbuf;
+        ASN1_INTEGER_set(&a.flags, in->flags);
+    }
+
     M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER);
     M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER);
     M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING);
@@ -304,6 +314,8 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
         M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12,
                                v12);
 #endif                          /* OPENSSL_NO_SRP */
+    if (in->flags)
+        M_ASN1_I2D_len_EXP_opt(&(a.flags), i2d_ASN1_INTEGER, 13, v13);
 
     M_ASN1_I2D_seq_total();
 
@@ -356,6 +368,8 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
         M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12,
                                v12);
 #endif                          /* OPENSSL_NO_SRP */
+    if (in->flags)
+        M_ASN1_I2D_put_EXP_opt(&a.flags, i2d_ASN1_INTEGER, 13, v13);
     M_ASN1_I2D_finish();
 }
 
@@ -593,6 +607,15 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
     } else
         ret->srp_username = NULL;
 #endif                          /* OPENSSL_NO_SRP */
+    ai.length = 0;
+    M_ASN1_D2I_get_EXP_opt(aip, d2i_ASN1_INTEGER, 13);
+    if (ai.data != NULL) {
+        ret->flags = ASN1_INTEGER_get(aip);
+        OPENSSL_free(ai.data);
+        ai.data = NULL;
+        ai.length = 0;
+    } else
+        ret->flags = 0;
 
     M_ASN1_D2I_Finish(a, SSL_SESSION_free, SSL_F_D2I_SSL_SESSION);
 }
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index f2de54b..1178d43 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -476,6 +476,11 @@ void ssl_cert_free(CERT *c)
     custom_exts_free(&c->cli_ext);
     custom_exts_free(&c->srv_ext);
 #endif
+    if (c->pms) {
+        OPENSSL_cleanse(c->pms, c->pmslen);
+        OPENSSL_free(c->pms);
+        c->pms = NULL;
+    }
     OPENSSL_free(c);
 }
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 2a84ff2..bcb6be1 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1134,6 +1134,13 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
             return (int)s->cert->ciphers_rawlen;
         } else
             return ssl_put_cipher_by_char(s, NULL, NULL);
+    case SSL_CTRL_GET_EXTMS_SUPPORT:
+        if (!s->session || SSL_in_init(s) || s->in_handshake)
+		return -1;
+	if (s->session->flags & SSL_SESS_FLAG_EXTMS)
+            return 1;
+        else
+            return 0;
     default:
         return (s->method->ssl_ctrl(s, cmd, larg, parg));
     }
@@ -3479,6 +3486,35 @@ void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
     *hash = NULL;
 }
 
+/* Retrieve handshake hashes */
+int ssl_handshake_hash(SSL *s, unsigned char *out, int outlen)
+{
+    unsigned char *p = out;
+    int idx, ret = 0;
+    long mask;
+    EVP_MD_CTX ctx;
+    const EVP_MD *md;
+    EVP_MD_CTX_init(&ctx);
+    for (idx = 0; ssl_get_handshake_digest(idx, &mask, &md); idx++) {
+        if (mask & ssl_get_algorithm2(s)) {
+            int hashsize = EVP_MD_size(md);
+            EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
+            if (!hdgst || hashsize < 0 || hashsize > outlen)
+                goto err;
+            if (!EVP_MD_CTX_copy_ex(&ctx, hdgst))
+                goto err;
+            if (!EVP_DigestFinal_ex(&ctx, p, NULL))
+                goto err;
+            p += hashsize;
+            outlen -= hashsize;
+        }
+    }
+    ret = p - out;
+ err:
+    EVP_MD_CTX_cleanup(&ctx);
+    return ret;
+}
+
 void SSL_set_debug(SSL *s, int debug)
 {
     s->debug = debug;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 56d6108..49425d8 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -597,6 +597,7 @@ struct ssl_method_st {
  *      Ticket [10]             EXPLICIT OCTET STRING, -- session ticket (clients only)
  *      Compression_meth [11]   EXPLICIT OCTET STRING, -- optional compression method
  *      SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
+ *      flags [ 13 ] EXPLICIT INTEGER -- optional flags
  *      }
  * Look in ssl/ssl_asn1.c for more details
  * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
@@ -674,8 +675,12 @@ struct ssl_session_st {
 # ifndef OPENSSL_NO_SRP
     char *srp_username;
 # endif
+    long flags;
 };
 
+/* Extended master secret support */
+#  define SSL_SESS_FLAG_EXTMS             0x1
+
 
 # ifndef OPENSSL_NO_SRP
 
@@ -1674,6 +1679,9 @@ typedef struct cert_st {
      */
     unsigned char *ctypes;
     size_t ctype_num;
+    /* Temporary storage for premaster secret */
+    unsigned char *pms;
+    size_t pmslen;
     /*
      * signature algorithms peer reports: e.g. supported signature algorithms
      * extension for server or as part of a certificate request for client.
@@ -2406,6 +2414,8 @@ int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
 int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len,
                                        int *al);
 
+int ssl_handshake_hash(SSL *s, unsigned char *out, int outlen);
+
 /* s3_cbc.c */
 void ssl3_cbc_copy_mac(unsigned char *out,
                        const SSL3_RECORD *rec, unsigned md_size);
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c
index 76a7cce..e5774d2 100644
--- a/ssl/ssl_txt.c
+++ b/ssl/ssl_txt.c
@@ -244,6 +244,10 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
                    X509_verify_cert_error_string(x->verify_result)) <= 0)
         goto err;
 
+    if (BIO_printf(bp, "    Extended master secret: %s\n",
+                   x->flags & SSL_SESS_FLAG_EXTMS ? "yes" : "no") <= 0)
+        goto err;
+
     return (1);
  err:
     return (0);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 3f4973e..ff6273f 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -919,57 +919,28 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
     return ((int)ret);
 }
 
-int tls1_final_finish_mac(SSL *s,
-                          const char *str, int slen, unsigned char *out)
+int tls1_final_finish_mac(SSL *s, const char *str, int slen,
+                          unsigned char *out)
 {
-    unsigned int i;
-    EVP_MD_CTX ctx;
-    unsigned char buf[2 * EVP_MAX_MD_SIZE];
-    unsigned char *q, buf2[12];
-    int idx;
-    long mask;
-    int err = 0;
-    const EVP_MD *md;
-
-    q = buf;
+    int hashlen;
+    unsigned char hash[2 * EVP_MAX_MD_SIZE];
+    unsigned char buf2[12];
 
     if (s->s3->handshake_buffer)
         if (!ssl3_digest_cached_records(s))
             return 0;
 
-    EVP_MD_CTX_init(&ctx);
+    hashlen = ssl_handshake_hash(s, hash, sizeof(hash));
 
-    for (idx = 0; ssl_get_handshake_digest(idx, &mask, &md); idx++) {
-        if (mask & ssl_get_algorithm2(s)) {
-            int hashsize = EVP_MD_size(md);
-            EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
-            if (!hdgst || hashsize < 0
-                || hashsize > (int)(sizeof buf - (size_t)(q - buf))) {
-                /*
-                 * internal error: 'buf' is too small for this cipersuite!
-                 */
-                err = 1;
-            } else {
-                if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) ||
-                    !EVP_DigestFinal_ex(&ctx, q, &i) ||
-                    (i != (unsigned int)hashsize))
-                    err = 1;
-                q += hashsize;
-            }
-        }
-    }
+    if (hashlen == 0)
+        return 0;
 
     if (!tls1_PRF(ssl_get_algorithm2(s),
-                  str, slen, buf, (int)(q - buf), NULL, 0, NULL, 0, NULL, 0,
+                  str, slen, hash, hashlen, NULL, 0, NULL, 0, NULL, 0,
                   s->session->master_key, s->session->master_key_length,
                   out, buf2, sizeof buf2))
-        err = 1;
-    EVP_MD_CTX_cleanup(&ctx);
-
-    if (err)
         return 0;
-    else
-        return sizeof buf2;
+    return sizeof buf2;
 }
 
 int tls1_mac(SSL *ssl, unsigned char *md, int send)
@@ -1099,13 +1070,41 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
             len);
 #endif                          /* KSSL_DEBUG */
 
-
-    tls1_PRF(ssl_get_algorithm2(s),
-             TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
-             s->s3->client_random, SSL3_RANDOM_SIZE,
-             co, col,
-             s->s3->server_random, SSL3_RANDOM_SIZE,
-             so, sol, p, len, s->session->master_key, buff, sizeof buff);
+    if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+        unsigned char hash[EVP_MAX_MD_SIZE * 2];
+        int hashlen;
+        /* If we don't have any digests cache records */
+        if (s->s3->handshake_buffer) {
+            /*
+             * keep record buffer: this wont affect client auth because we're
+             * freezing the buffer at the same point (after client key
+             * exchange and before certificate verify)
+             */
+            s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+            ssl3_digest_cached_records(s);
+        }
+        hashlen = ssl_handshake_hash(s, hash, sizeof(hash));
+#ifdef SSL_DEBUG
+        fprintf(stderr, "Handshake hashes:\n");
+        BIO_dump_fp(stderr, (char *)hash, hashlen);
+#endif
+        tls1_PRF(ssl_get_algorithm2(s),
+                 TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+                 TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
+                 hash, hashlen,
+                 co, col,
+                 NULL, 0,
+                 so, sol, p, len, s->session->master_key, buff, sizeof buff);
+        OPENSSL_cleanse(hash, hashlen);
+    } else {
+        tls1_PRF(ssl_get_algorithm2(s),
+                 TLS_MD_MASTER_SECRET_CONST,
+                 TLS_MD_MASTER_SECRET_CONST_SIZE,
+                 s->s3->client_random, SSL3_RANDOM_SIZE,
+                 co, col,
+                 s->s3->server_random, SSL3_RANDOM_SIZE,
+                 so, sol, p, len, s->session->master_key, buff, sizeof buff);
+    }
 #ifdef SSL_DEBUG
     fprintf(stderr, "Premaster Secret:\n");
     BIO_dump_fp(stderr, (char *)p, len);
@@ -1204,6 +1203,9 @@ int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
     if (memcmp(val, TLS_MD_MASTER_SECRET_CONST,
                TLS_MD_MASTER_SECRET_CONST_SIZE) == 0)
         goto err1;
+    if (memcmp(val, TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+               TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE) == 0)
+        goto err1;
     if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST,
                TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0)
         goto err1;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 9be7347..22f7047 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1445,6 +1445,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
     s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
     s2n(0, ret);
 # endif
+    s2n(TLSEXT_TYPE_extended_master_secret, ret);
+    s2n(0, ret);
 
     /*
      * Add padding to workaround bugs in F5 terminators. See
@@ -1682,6 +1684,10 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
         }
     }
 # endif
+    if (!s->hit && s->session->flags & SSL_SESS_FLAG_EXTMS) {
+        s2n(TLSEXT_TYPE_extended_master_secret, ret);
+        s2n(0, ret);
+    }
 
     if (s->s3->alpn_selected) {
         const unsigned char *selected = s->s3->alpn_selected;
@@ -2300,6 +2306,10 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p,
         else if (type == TLSEXT_TYPE_encrypt_then_mac)
             s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
 # endif
+        else if (type == TLSEXT_TYPE_extended_master_secret) {
+            if (!s->hit)
+                s->session->flags |= SSL_SESS_FLAG_EXTMS;
+        }
         /*
          * If this ClientHello extension was unhandled and this is a
          * nonresumed connection, check whether the extension is a custom
@@ -2594,6 +2604,10 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p,
                 s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
         }
 # endif
+        else if (type == TLSEXT_TYPE_extended_master_secret) {
+            if (!s->hit)
+                s->session->flags |= SSL_SESS_FLAG_EXTMS;
+        }
         /*
          * If this extension type was not otherwise handled, but matches a
          * custom_cli_ext_record, then send it to the c callback
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 26160ed..4161750 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -363,7 +363,8 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_session_ticket, "session_ticket"},
     {TLSEXT_TYPE_renegotiate, "renegotiate"},
     {TLSEXT_TYPE_next_proto_neg, "next_proto_neg"},
-    {TLSEXT_TYPE_padding, "padding"}
+    {TLSEXT_TYPE_padding, "padding"},
+    {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"}
 };
 
 static ssl_trace_tbl ssl_curve_tbl[] = {
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 1f756a4..af03f13 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -250,6 +250,12 @@ extern "C" {
  * http://www.ietf.org/id/draft-ietf-tls-encrypt-then-mac-02.txt
  */
 # define TLSEXT_TYPE_encrypt_then_mac    22
+/*
+ * Extended master secret extension.
+ * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+ * https://tools.ietf.org/id/draft-ietf-tls-session-hash-03.txt
+ */
+# define TLSEXT_TYPE_extended_master_secret      23
 
 /* ExtensionType value from RFC4507 */
 # define TLSEXT_TYPE_session_ticket              35
@@ -776,7 +782,7 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
 
 # define TLS1_FINISH_MAC_LENGTH          12
 
-# define TLS_MD_MAX_CONST_SIZE                   20
+# define TLS_MD_MAX_CONST_SIZE                   22
 # define TLS_MD_CLIENT_FINISH_CONST              "client finished"
 # define TLS_MD_CLIENT_FINISH_CONST_SIZE         15
 # define TLS_MD_SERVER_FINISH_CONST              "server finished"
@@ -791,6 +797,8 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
 # define TLS_MD_IV_BLOCK_CONST_SIZE              8
 # define TLS_MD_MASTER_SECRET_CONST              "master secret"
 # define TLS_MD_MASTER_SECRET_CONST_SIZE         13
+# define TLS_MD_EXTENDED_MASTER_SECRET_CONST     "extended master secret"
+# define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE        22
 
 # ifdef CHARSET_EBCDIC
 #  undef TLS_MD_CLIENT_FINISH_CONST
@@ -840,6 +848,11 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
  * master secret
  */
 #  define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
+#  undef TLS_MD_EXTENDED_MASTER_SECRET_CONST
+/*
+ * extended master secret
+ */
+#  define TLS_MD_EXTENDED_MASTER_SECRET_CONST    "\x65\x78\x74\x65\x63\x64\x65\x64\x20\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
 # endif
 
 /* TLS Session Ticket extension struct */


More information about the openssl-commits mailing list