[openssl-commits] [openssl] OpenSSL_1_1_0-stable update

Matt Caswell matt at openssl.org
Thu Sep 22 10:37:17 UTC 2016


The branch OpenSSL_1_1_0-stable has been updated
       via  5fe5914d3068128cdc6b08fe72746bb516a30b8a (commit)
       via  ac2c44c6289f9716de4c4beeb284a818eacde517 (commit)
       via  f3e189613fdbe7404bfbbca2caccf5cbd19e2ffc (commit)
       via  d3c9d6e99f075e6fbdab94db00b220cfa08b5c4b (commit)
       via  63658103d4441924f8dbfc517b99bb54758a98b9 (commit)
       via  6d32c2ae28952b5c1d7a24968e488532fcadc51a (commit)
       via  f6a7505e64d06f9d41e01b763b684e4e2df34922 (commit)
       via  7409b0aae569b5ba4476076fbea3226d606c50ba (commit)
       via  1645f3f4b9f717133ffcaf3398508ed2ddc81374 (commit)
       via  a59ab1c4dd27a4c7c6e88f3c33747532fd144412 (commit)
      from  d8e94b0d8fe412c19bc230593a960b7db73a8e7b (commit)


- Log -----------------------------------------------------------------
commit 5fe5914d3068128cdc6b08fe72746bb516a30b8a
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 22 11:15:54 2016 +0100

    Prepare for 1.1.0b-dev
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ac2c44c6289f9716de4c4beeb284a818eacde517
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 22 11:14:50 2016 +0100

    Prepare for 1.1.0a release
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f3e189613fdbe7404bfbbca2caccf5cbd19e2ffc
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Sep 21 21:59:49 2016 +0100

    Updates CHANGES and NEWS for new release
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d3c9d6e99f075e6fbdab94db00b220cfa08b5c4b
Author: Dmitry Belyavsky <beldmit at gmail.com>
Date:   Mon Sep 19 15:53:35 2016 +0100

    Avoid KCI attack for GOST
    
    Russian GOST ciphersuites are vulnerable to the KCI attack because they use
    long-term keys to establish the connection when ssl client authorization is
    on. This change brings the GOST implementation into line with the latest
    specs in order to avoid the attack. It should not break backwards
    compatibility.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>

commit 63658103d4441924f8dbfc517b99bb54758a98b9
Author: Matt Caswell <matt at openssl.org>
Date:   Sat Sep 10 21:24:40 2016 +0100

    Fix a hang with SSL_peek()
    
    If while calling SSL_peek() we read an empty record then we go into an
    infinite loop, continually trying to read data from the empty record and
    never making any progress. This could be exploited by a malicious peer in
    a Denial Of Service attack.
    
    CVE-2016-6305
    
    GitHub Issue #1563
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 6d32c2ae28952b5c1d7a24968e488532fcadc51a
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 9 10:53:39 2016 +0100

    Fix a mem leak in NPN handling
    
    If a server sent multiple NPN extensions in a single ClientHello then a
    mem leak can occur. This will only happen where the client has requested
    NPN in the first place. It does not occur during renegotiation. Therefore
    the maximum that could be leaked in a single connection with a malicious
    server is 64k (the maximum size of the ServerHello extensions section). As
    this is client side, only occurs if NPN has been requested and does not
    occur during renegotiation this is unlikely to be exploitable.
    
    Issue reported by Shi Lei.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit f6a7505e64d06f9d41e01b763b684e4e2df34922
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 13 17:02:03 2016 +0100

    Add some more OCSP testing
    
    Test that the OCSP callbacks work as expected.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 7409b0aae569b5ba4476076fbea3226d606c50ba
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 13 23:26:53 2016 +0100

    Add OCSP_RESPID_match()
    
    Add a function for testing whether a given OCSP_RESPID matches with a
    certificate.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 1645f3f4b9f717133ffcaf3398508ed2ddc81374
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 12 17:39:55 2016 +0100

    Add the ability to set OCSP_RESPID fields
    
    OCSP_RESPID was made opaque in 1.1.0, but no accessors were provided for
    setting the name/key value for the OCSP_RESPID.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit a59ab1c4dd27a4c7c6e88f3c33747532fd144412
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 9 10:08:45 2016 +0100

    Fix OCSP Status Request extension unbounded memory growth
    
    A malicious client can send an excessively large OCSP Status Request
    extension. If that client continually requests renegotiation,
    sending a large OCSP Status Request extension each time, then there will
    be unbounded memory growth on the server. This will eventually lead to a
    Denial Of Service attack through memory exhaustion. Servers with a
    default configuration are vulnerable even if they do not support OCSP.
    Builds using the "no-ocsp" build time option are not affected.
    
    I have also checked other extensions to see if they suffer from a similar
    problem but I could not find any other issues.
    
    CVE-2016-6304
    
    Issue reported by Shi Lei.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 CHANGES                             |  70 +++++++++++-
 NEWS                                |  11 +-
 README                              |   2 +-
 crypto/ocsp/ocsp_srv.c              |  73 ++++++++++--
 doc/crypto/OCSP_response_status.pod |  34 +++++-
 include/openssl/ocsp.h              |   3 +
 include/openssl/opensslv.h          |   6 +-
 ssl/record/rec_layer_s3.c           |   6 +-
 ssl/statem/statem_clnt.c            |  19 +---
 ssl/t1_lib.c                        |  28 +++--
 test/sslapitest.c                   | 217 +++++++++++++++++++++++++++++++++---
 util/libcrypto.num                  |   3 +
 12 files changed, 412 insertions(+), 60 deletions(-)

diff --git a/CHANGES b/CHANGES
index 9fc7bfb..76b4974 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,7 +2,75 @@
  OpenSSL CHANGES
  _______________
 
- Changes between 1.1.0 and 1.1.0a [xx XXX xxxx]
+ Changes between 1.1.0a and 1.1.0b [xx XXX xxxx]
+
+  *)
+
+ Changes between 1.1.0 and 1.1.0a [22 Sep 2016]
+
+  *) OCSP Status Request extension unbounded memory growth
+
+     A malicious client can send an excessively large OCSP Status Request
+     extension. If that client continually requests renegotiation, sending a
+     large OCSP Status Request extension each time, then there will be unbounded
+     memory growth on the server. This will eventually lead to a Denial Of
+     Service attack through memory exhaustion. Servers with a default
+     configuration are vulnerable even if they do not support OCSP. Builds using
+     the "no-ocsp" build time option are not affected.
+
+     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
+     (CVE-2016-6304)
+     [Matt Caswell]
+
+  *) SSL_peek() hang on empty record
+
+     OpenSSL 1.1.0 SSL/TLS will hang during a call to SSL_peek() if the peer
+     sends an empty record. This could be exploited by a malicious peer in a
+     Denial Of Service attack.
+
+     This issue was reported to OpenSSL by Alex Gaynor.
+     (CVE-2016-6305)
+     [Matt Caswell]
+
+  *) Excessive allocation of memory in tls_get_message_header() and
+     dtls1_preprocess_fragment()
+
+     A (D)TLS message includes 3 bytes for its length in the header for the
+     message. This would allow for messages up to 16Mb in length. Messages of
+     this length are excessive and OpenSSL includes a check to ensure that a
+     peer is sending reasonably sized messages in order to avoid too much memory
+     being consumed to service a connection. A flaw in the logic of version
+     1.1.0 means that memory for the message is allocated too early, prior to
+     the excessive message length check. Due to way memory is allocated in
+     OpenSSL this could mean an attacker could force up to 21Mb to be allocated
+     to service a connection. This could lead to a Denial of Service through
+     memory exhaustion. However, the excessive message length check still takes
+     place, and this would cause the connection to immediately fail. Assuming
+     that the application calls SSL_free() on the failed conneciton in a timely
+     manner then the 21Mb of allocated memory will then be immediately freed
+     again. Therefore the excessive memory allocation will be transitory in
+     nature. This then means that there is only a security impact if:
+
+     1) The application does not call SSL_free() in a timely manner in the event
+     that the connection fails
+     or
+     2) The application is working in a constrained environment where there is
+     very little free memory
+     or
+     3) The attacker initiates multiple connection attempts such that there are
+     multiple connections in a state where memory has been allocated for the
+     connection; SSL_free() has not yet been called; and there is insufficient
+     memory to service the multiple requests.
+
+     Except in the instance of (1) above any Denial Of Service is likely to be
+     transitory because as soon as the connection fails the memory is
+     subsequently freed again in the SSL_free() call. However there is an
+     increased risk during this period of application crashes due to the lack of
+     memory - which would then mean a more serious Denial of Service.
+
+     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
+     (CVE-2016-6307 and CVE-2016-6308)
+     [Matt Caswell]
 
   *) solaris-x86-cc, i.e. 32-bit configuration with vendor compiler,
      had to be removed. Primary reason is that vendor assembler can't
diff --git a/NEWS b/NEWS
index 0792f31..66bade1 100644
--- a/NEWS
+++ b/NEWS
@@ -5,10 +5,19 @@
   This file gives a brief overview of the major changes between each OpenSSL
   release. For more details please read the CHANGES file.
 
-  Major changes between OpenSSL 1.1.0 and OpenSSL 1.1.0a [under development]
+  Major changes between OpenSSL 1.1.0a and OpenSSL 1.1.0b [under development]
 
       o
 
+  Major changes between OpenSSL 1.1.0 and OpenSSL 1.1.0a [22 Sep 2016]
+
+      o OCSP Status Request extension unbounded memory growth (CVE-2016-6304)
+      o SSL_peek() hang on empty record (CVE-2016-6305)
+      o Excessive allocation of memory in tls_get_message_header()
+       (CVE-2016-6307)
+      o Excessive allocation of memory in dtls1_preprocess_fragment()
+       (CVE-2016-6308)
+
   Major changes between OpenSSL 1.0.2h and OpenSSL 1.1.0 [25 Aug 2016]
 
       o Copyright text was shrunk to a boilerplate that points to the license
diff --git a/README b/README
index cac5fc6..fdf0f8f 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 
- OpenSSL 1.1.0a-dev
+ OpenSSL 1.1.0b-dev
 
  Copyright (c) 1998-2016 The OpenSSL Project
  Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
diff --git a/crypto/ocsp/ocsp_srv.c b/crypto/ocsp/ocsp_srv.c
index 443161c..46a4bf7 100644
--- a/crypto/ocsp/ocsp_srv.c
+++ b/crypto/ocsp/ocsp_srv.c
@@ -193,17 +193,10 @@ int OCSP_basic_sign(OCSP_BASICRESP *brsp,
 
     rid = &brsp->tbsResponseData.responderId;
     if (flags & OCSP_RESPID_KEY) {
-        unsigned char md[SHA_DIGEST_LENGTH];
-        X509_pubkey_digest(signer, EVP_sha1(), md, NULL);
-        if ((rid->value.byKey = ASN1_OCTET_STRING_new()) == NULL)
-            goto err;
-        if (!(ASN1_OCTET_STRING_set(rid->value.byKey, md, SHA_DIGEST_LENGTH)))
-            goto err;
-        rid->type = V_OCSP_RESPID_KEY;
-    } else {
-        if (!X509_NAME_set(&rid->value.byName, X509_get_subject_name(signer)))
+        if (!OCSP_RESPID_set_by_key(rid, signer))
             goto err;
-        rid->type = V_OCSP_RESPID_NAME;
+    } else if (!OCSP_RESPID_set_by_name(rid, signer)) {
+        goto err;
     }
 
     if (!(flags & OCSP_NOTIME) &&
@@ -222,3 +215,63 @@ int OCSP_basic_sign(OCSP_BASICRESP *brsp,
  err:
     return 0;
 }
+
+int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert)
+{
+    if (!X509_NAME_set(&respid->value.byName, X509_get_subject_name(cert)))
+        return 0;
+
+    respid->type = V_OCSP_RESPID_NAME;
+
+    return 1;
+}
+
+int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert)
+{
+    ASN1_OCTET_STRING *byKey = NULL;
+    unsigned char md[SHA_DIGEST_LENGTH];
+
+    /* RFC2560 requires SHA1 */
+    if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL))
+        return 0;
+
+    byKey = ASN1_OCTET_STRING_new();
+    if (byKey == NULL)
+        return 0;
+
+    if (!(ASN1_OCTET_STRING_set(byKey, md, SHA_DIGEST_LENGTH))) {
+        ASN1_OCTET_STRING_free(byKey);
+        return 0;
+    }
+
+    respid->type = V_OCSP_RESPID_KEY;
+    respid->value.byKey = byKey;
+
+    return 1;
+}
+
+int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert)
+{
+    if (respid->type == V_OCSP_RESPID_KEY) {
+        unsigned char md[SHA_DIGEST_LENGTH];
+
+        if (respid->value.byKey == NULL)
+            return 0;
+
+        /* RFC2560 requires SHA1 */
+        if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL))
+            return 0;
+
+        return (ASN1_STRING_length(respid->value.byKey) == SHA_DIGEST_LENGTH)
+            && (memcmp(ASN1_STRING_get0_data(respid->value.byKey), md,
+                       SHA_DIGEST_LENGTH) == 0);
+    } else if(respid->type == V_OCSP_RESPID_NAME) {
+        if (respid->value.byName == NULL)
+            return 0;
+
+        return X509_NAME_cmp(respid->value.byName,
+                             X509_get_subject_name(cert)) == 0;
+    }
+
+    return 0;
+}
diff --git a/doc/crypto/OCSP_response_status.pod b/doc/crypto/OCSP_response_status.pod
index 08738d2..81946a6 100644
--- a/doc/crypto/OCSP_response_status.pod
+++ b/doc/crypto/OCSP_response_status.pod
@@ -3,7 +3,8 @@
 =head1 NAME
 
 OCSP_response_status, OCSP_response_get1_basic, OCSP_response_create,
-OCSP_RESPONSE_free - OCSP response functions
+OCSP_RESPONSE_free, OCSP_RESPID_set_by_name,
+OCSP_RESPID_set_by_key, OCSP_RESPID_match - OCSP response functions
 
 =head1 SYNOPSIS
 
@@ -14,6 +15,10 @@ OCSP_RESPONSE_free - OCSP response functions
  OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs);
  void OCSP_RESPONSE_free(OCSP_RESPONSE *resp);
 
+ int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert);
+ int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert);
+ int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert);
+
 =head1 DESCRIPTION
 
 OCSP_response_status() returns the OCSP response status of B<resp>. It returns
@@ -30,6 +35,20 @@ B<status> and optionally including basic response B<bs>.
 
 OCSP_RESPONSE_free() frees up OCSP response B<resp>.
 
+OCSP_RESPID_set_by_name() sets the name of the OCSP_RESPID to be the same as the
+subject name in the supplied X509 certificate B<cert> for the OCSP responder.
+
+OCSP_RESPID_set_by_key() sets the key of the OCSP_RESPID to be the same as the
+key in the supplied X509 certificate B<cert> for the OCSP responder. The key is
+stored as a SHA1 hash.
+
+Note that an OCSP_RESPID can only have one of the name, or the key set. Calling
+OCSP_RESPID_set_by_name() or OCSP_RESPID_set_by_key() will clear any existing
+setting.
+
+OCSP_RESPID_match() tests whether the OCSP_RESPID given in B<respid> matches
+with the X509 certificate B<cert>.
+
 =head1 RETURN VALUES
 
 OCSP_RESPONSE_status() returns a status value.
@@ -42,6 +61,12 @@ if an error occurred.
 
 OCSP_RESPONSE_free() does not return a value.
 
+OCSP_RESPID_set_by_name() and OCSP_RESPID_set_by_key() return 1 on success or 0
+on failure.
+
+OCSP_RESPID_match() returns 1 if the OCSP_RESPID and the X509 certificate match
+or 0 otherwise.
+
 =head1 NOTES
 
 OCSP_response_get1_basic() is only called if the status of a response is
@@ -55,6 +80,13 @@ L<OCSP_request_add1_nonce(3)>
 L<OCSP_REQUEST_new(3)>
 L<OCSP_response_find_status(3)>
 L<OCSP_sendreq_new(3)>
+L<OCSP_RESPID_new(3)>
+L<OCSP_RESPID_free(3)>
+
+=head1 HISTORY
+
+The OCSP_RESPID_set_by_name(), OCSP_RESPID_set_by_key() and OCSP_RESPID_match()
+functions were added in OpenSSL version 1.1.0a.
 
 =head1 COPYRIGHT
 
diff --git a/include/openssl/ocsp.h b/include/openssl/ocsp.h
index 119e591..08debc5 100644
--- a/include/openssl/ocsp.h
+++ b/include/openssl/ocsp.h
@@ -259,6 +259,9 @@ int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert);
 int OCSP_basic_sign(OCSP_BASICRESP *brsp,
                     X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
                     STACK_OF(X509) *certs, unsigned long flags);
+int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert);
+int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert);
+int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert);
 
 X509_EXTENSION *OCSP_crlID_new(const char *url, long *n, char *tim);
 
diff --git a/include/openssl/opensslv.h b/include/openssl/opensslv.h
index 0d9a89d..5cc6881 100644
--- a/include/openssl/opensslv.h
+++ b/include/openssl/opensslv.h
@@ -39,11 +39,11 @@ extern "C" {
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  *  major minor fix final patch/beta)
  */
-# define OPENSSL_VERSION_NUMBER  0x10100010L
+# define OPENSSL_VERSION_NUMBER  0x10100020L
 # ifdef OPENSSL_FIPS
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.0a-fips-dev  xx XXX xxxx"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.0b-fips-dev  xx XXX xxxx"
 # else
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.0a-dev  xx XXX xxxx"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.0b-dev  xx XXX xxxx"
 # endif
 
 /*-
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index abde9d4..0775095 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1133,7 +1133,11 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
 
             memcpy(buf, &(rr->data[rr->off]), n);
             buf += n;
-            if (!peek) {
+            if (peek) {
+                /* Mark any zero length record as consumed CVE-2016-6305 */
+                if (SSL3_RECORD_get_length(rr) == 0)
+                    SSL3_RECORD_set_read(rr);
+            } else {
                 SSL3_RECORD_sub_length(rr, n);
                 SSL3_RECORD_add_off(rr, n);
                 if (SSL3_RECORD_get_length(rr) == 0) {
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index ff42858..692544b 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2379,18 +2379,6 @@ static int tls_construct_cke_gost(SSL *s, unsigned char **p, int *len, int *al)
         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
      */
@@ -2434,12 +2422,7 @@ static int tls_construct_cke_gost(SSL *s, unsigned char **p, int *len, int *al)
         *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;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b8f8fd2..86833d8 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2030,6 +2030,22 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
                     (&extension, &responder_id_list))
                     return 0;
 
+                /*
+                 * We remove any OCSP_RESPIDs from a previous handshake
+                 * to prevent unbounded memory growth - CVE-2016-6304
+                 */
+                sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids,
+                                        OCSP_RESPID_free);
+                if (PACKET_remaining(&responder_id_list) > 0) {
+                    s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
+                    if (s->tlsext_ocsp_ids == NULL) {
+                        *al = SSL_AD_INTERNAL_ERROR;
+                        return 0;
+                    }
+                } else {
+                    s->tlsext_ocsp_ids = NULL;
+                }
+
                 while (PACKET_remaining(&responder_id_list) > 0) {
                     OCSP_RESPID *id;
                     PACKET responder_id;
@@ -2041,13 +2057,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
                         return 0;
                     }
 
-                    if (s->tlsext_ocsp_ids == NULL
-                        && (s->tlsext_ocsp_ids =
-                            sk_OCSP_RESPID_new_null()) == NULL) {
-                        *al = SSL_AD_INTERNAL_ERROR;
-                        return 0;
-                    }
-
                     id_data = PACKET_data(&responder_id);
                     id = d2i_OCSP_RESPID(NULL, &id_data,
                                          PACKET_remaining(&responder_id));
@@ -2396,6 +2405,11 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
                 *al = TLS1_AD_INTERNAL_ERROR;
                 return 0;
             }
+            /*
+             * Could be non-NULL if server has sent multiple NPN extensions in
+             * a single Serverhello
+             */
+            OPENSSL_free(s->next_proto_negotiated);
             s->next_proto_negotiated = OPENSSL_malloc(selected_len);
             if (s->next_proto_negotiated == NULL) {
                 *al = TLS1_AD_INTERNAL_ERROR;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index b190145..a2b18df 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -7,10 +7,13 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h>
+
 #include <openssl/opensslconf.h>
 #include <openssl/bio.h>
 #include <openssl/crypto.h>
 #include <openssl/ssl.h>
+#include <openssl/ocsp.h>
 
 #include "ssltestlib.h"
 #include "testutil.h"
@@ -18,63 +21,243 @@
 static char *cert = NULL;
 static char *privkey = NULL;
 
+static const unsigned char orespder[] = "Dummy OCSP Response";
+static int ocsp_server_called = 0;
+static int ocsp_client_called = 0;
+
+static int cdummyarg = 1;
+static X509 *ocspcert = NULL;
+
+static int ocsp_server_cb(SSL *s, void *arg)
+{
+    int *argi = (int *)arg;
+    unsigned char *orespdercopy = NULL;
+    STACK_OF(OCSP_RESPID) *ids = NULL;
+    OCSP_RESPID *id = NULL;
+
+    if (*argi == 2) {
+        /* In this test we are expecting exactly 1 OCSP_RESPID */
+        SSL_get_tlsext_status_ids(s, &ids);
+        if (ids == NULL || sk_OCSP_RESPID_num(ids) != 1)
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+        id = sk_OCSP_RESPID_value(ids, 0);
+        if (id == NULL || !OCSP_RESPID_match(id, ocspcert))
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+    } else if (*argi != 1) {
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+
+
+    orespdercopy = OPENSSL_memdup(orespder, sizeof(orespder));
+    if (orespdercopy == NULL)
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+    SSL_set_tlsext_status_ocsp_resp(s, orespdercopy, sizeof(orespder));
+
+    ocsp_server_called = 1;
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+static int ocsp_client_cb(SSL *s, void *arg)
+{
+    int *argi = (int *)arg;
+    const unsigned char *respderin;
+    size_t len;
+
+    if (*argi != 1 && *argi != 2)
+        return 0;
+
+    len = SSL_get_tlsext_status_ocsp_resp(s, &respderin);
+
+    if (memcmp(orespder, respderin, len) != 0)
+        return 0;
+
+    ocsp_client_called = 1;
+
+    return 1;
+}
+
 static int test_tlsext_status_type(void)
 {
-    SSL_CTX *ctx = NULL;
-    SSL *con = NULL;
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
     int testresult = 0;
+    STACK_OF(OCSP_RESPID) *ids = NULL;
+    OCSP_RESPID *id = NULL;
+    BIO *certbio = NULL;
 
-    /* Test tlsext_status_type */
-    ctx = SSL_CTX_new(TLS_method());
+    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
+                             &cctx, cert, privkey)) {
+        printf("Unable to create SSL_CTX pair\n");
+        return 0;
+    }
 
-    if (SSL_CTX_get_tlsext_status_type(ctx) != -1) {
+    if (SSL_CTX_get_tlsext_status_type(cctx) != -1) {
         printf("Unexpected initial value for "
                "SSL_CTX_get_tlsext_status_type()\n");
         goto end;
     }
 
-    con = SSL_new(ctx);
+    /* First just do various checks getting and setting tlsext_status_type */
 
-    if (SSL_get_tlsext_status_type(con) != -1) {
+    clientssl = SSL_new(cctx);
+    if (SSL_get_tlsext_status_type(clientssl) != -1) {
         printf("Unexpected initial value for SSL_get_tlsext_status_type()\n");
         goto end;
     }
 
-    if (!SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp)) {
+    if (!SSL_set_tlsext_status_type(clientssl, TLSEXT_STATUSTYPE_ocsp)) {
         printf("Unexpected fail for SSL_set_tlsext_status_type()\n");
         goto end;
     }
 
-    if (SSL_get_tlsext_status_type(con) != TLSEXT_STATUSTYPE_ocsp) {
+    if (SSL_get_tlsext_status_type(clientssl) != TLSEXT_STATUSTYPE_ocsp) {
         printf("Unexpected result for SSL_get_tlsext_status_type()\n");
         goto end;
     }
 
-    SSL_free(con);
-    con = NULL;
+    SSL_free(clientssl);
+    clientssl = NULL;
 
-    if (!SSL_CTX_set_tlsext_status_type(ctx, TLSEXT_STATUSTYPE_ocsp)) {
+    if (!SSL_CTX_set_tlsext_status_type(cctx, TLSEXT_STATUSTYPE_ocsp)) {
         printf("Unexpected fail for SSL_CTX_set_tlsext_status_type()\n");
         goto end;
     }
 
-    if (SSL_CTX_get_tlsext_status_type(ctx) != TLSEXT_STATUSTYPE_ocsp) {
+    if (SSL_CTX_get_tlsext_status_type(cctx) != TLSEXT_STATUSTYPE_ocsp) {
         printf("Unexpected result for SSL_CTX_get_tlsext_status_type()\n");
         goto end;
     }
 
-    con = SSL_new(ctx);
+    clientssl = SSL_new(cctx);
 
-    if (SSL_get_tlsext_status_type(con) != TLSEXT_STATUSTYPE_ocsp) {
+    if (SSL_get_tlsext_status_type(clientssl) != TLSEXT_STATUSTYPE_ocsp) {
         printf("Unexpected result for SSL_get_tlsext_status_type() (test 2)\n");
         goto end;
     }
 
+    SSL_free(clientssl);
+    clientssl = NULL;
+
+    /*
+     * Now actually do a handshake and check OCSP information is exchanged and
+     * the callbacks get called
+     */
+
+    SSL_CTX_set_tlsext_status_cb(cctx, ocsp_client_cb);
+    SSL_CTX_set_tlsext_status_arg(cctx, &cdummyarg);
+    SSL_CTX_set_tlsext_status_cb(sctx, ocsp_server_cb);
+    SSL_CTX_set_tlsext_status_arg(sctx, &cdummyarg);
+
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl, clientssl)) {
+        printf("Unable to create SSL connection\n");
+        goto end;
+    }
+
+    if (!ocsp_client_called || !ocsp_server_called) {
+        printf("OCSP callbacks not called\n");
+        goto end;
+    }
+
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = NULL;
+    clientssl = NULL;
+
+    /* Try again but this time force the server side callback to fail */
+    ocsp_client_called = 0;
+    ocsp_server_called = 0;
+    cdummyarg = 0;
+
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    /* This should fail because the callback will fail */
+    if (create_ssl_connection(serverssl, clientssl)) {
+        printf("Unexpected success creating the connection\n");
+        goto end;
+    }
+
+    if (ocsp_client_called || ocsp_server_called) {
+        printf("OCSP callbacks successfully called unexpectedly\n");
+        goto end;
+    }
+
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = NULL;
+    clientssl = NULL;
+
+    /*
+     * This time we'll get the client to send an OCSP_RESPID that it will
+     * accept.
+     */
+    ocsp_client_called = 0;
+    ocsp_server_called = 0;
+    cdummyarg = 2;
+
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    /*
+     * We'll just use any old cert for this test - it doesn't have to be an OCSP
+     * specifc one. We'll use the server cert.
+     */
+    certbio = BIO_new_file(cert, "r");
+    if (certbio == NULL) {
+        printf("Can't load the certficate file\n");
+        goto end;
+    }
+    id = OCSP_RESPID_new();
+    ids = sk_OCSP_RESPID_new_null();
+    ocspcert = PEM_read_bio_X509(certbio, NULL, NULL, NULL);
+    if (id == NULL || ids == NULL || ocspcert == NULL
+            || !OCSP_RESPID_set_by_key(id, ocspcert)
+            || !sk_OCSP_RESPID_push(ids, id)) {
+        printf("Unable to set OCSP_RESPIDs\n");
+        goto end;
+    }
+    id = NULL;
+    SSL_set_tlsext_status_ids(clientssl, ids);
+    /* Control has been transferred */
+    ids = NULL;
+
+    BIO_free(certbio);
+    certbio = NULL;
+
+    if (!create_ssl_connection(serverssl, clientssl)) {
+        printf("Unable to create SSL connection\n");
+        goto end;
+    }
+
+    if (!ocsp_client_called || !ocsp_server_called) {
+        printf("OCSP callbacks not called\n");
+        goto end;
+    }
+
     testresult = 1;
 
  end:
-    SSL_free(con);
-    SSL_CTX_free(ctx);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    sk_OCSP_RESPID_pop_free(ids, OCSP_RESPID_free);
+    OCSP_RESPID_free(id);
+    BIO_free(certbio);
+    X509_free(ocspcert);
+    ocspcert = NULL;
 
     return testresult;
 }
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 8f19a3a..db6732e 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4203,3 +4203,6 @@ ECPKPARAMETERS_free                     4153	1_1_0	EXIST::FUNCTION:EC
 ECPARAMETERS_free                       4154	1_1_0	EXIST::FUNCTION:EC
 ECPKPARAMETERS_new                      4155	1_1_0	EXIST::FUNCTION:EC
 ECPARAMETERS_new                        4156	1_1_0	EXIST::FUNCTION:EC
+OCSP_RESPID_set_by_name                 4157	1_1_0a	EXIST::FUNCTION:OCSP
+OCSP_RESPID_set_by_key                  4158	1_1_0a	EXIST::FUNCTION:OCSP
+OCSP_RESPID_match                       4159	1_1_0a	EXIST::FUNCTION:OCSP


More information about the openssl-commits mailing list