[openssl-commits] [openssl] master update

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


The branch master has been updated
       via  39c136cc53d7b6fafdd1a0b52c035fd24358e01c (commit)
       via  41b42807726e340538701021cdc196672330f4db (commit)
       via  b8d243956296458d1782af0d6e7ecfe6deae038a (commit)
       via  c31dbed70c0be1578276367a1ba420ac935d0c68 (commit)
       via  ba881d3b39829d22eede8f69412d187aaab487e9 (commit)
       via  a671b3e64abe782d37c705ae51e93f2013672f9d (commit)
       via  e12c0beb5a652ba0c3a71e633a77fafbb4f86aa4 (commit)
       via  e408c09bbf7c3057bda4b8d20bec1b3a7771c15b (commit)
      from  a449b47c7d8e20efc8cc524ed695a060b11ef889 (commit)


- Log -----------------------------------------------------------------
commit 39c136cc53d7b6fafdd1a0b52c035fd24358e01c
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 41b42807726e340538701021cdc196672330f4db
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 b8d243956296458d1782af0d6e7ecfe6deae038a
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 c31dbed70c0be1578276367a1ba420ac935d0c68
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 ba881d3b39829d22eede8f69412d187aaab487e9
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 a671b3e64abe782d37c705ae51e93f2013672f9d
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 e12c0beb5a652ba0c3a71e633a77fafbb4f86aa4
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 e408c09bbf7c3057bda4b8d20bec1b3a7771c15b
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                             |  77 ++++++++++++-
 NEWS                                |  11 +-
 crypto/ocsp/ocsp_srv.c              |  73 ++++++++++--
 doc/crypto/OCSP_response_status.pod |  34 +++++-
 include/openssl/ocsp.h              |   3 +
 ssl/record/rec_layer_s3.c           |   6 +-
 ssl/statem/statem_clnt.c            |  18 ---
 ssl/t1_lib.c                        |  28 +++--
 test/sslapitest.c                   | 217 +++++++++++++++++++++++++++++++++---
 util/libcrypto.num                  |   3 +
 10 files changed, 414 insertions(+), 56 deletions(-)

diff --git a/CHANGES b/CHANGES
index 38b025a..97e70ac 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,7 +2,7 @@
  OpenSSL CHANGES
  _______________
 
- Changes between 1.1.0 and 1.1.1 [xx XXX xxxx]
+ Changes between 1.1.0a and 1.1.1 [xx XXX xxxx]
 
   *)
 
@@ -11,6 +11,81 @@
      https://www.akkadia.org/drepper/SHA-crypt.txt
      [Richard Levitte]
 
+ 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
+     assemble our modules with -KPIC flag. As result it, assembly
+     support, was not even available as option. But its lack means
+     lack of side-channel resistant code, which is incompatible with
+     security by todays standards. Fortunately gcc is readily available
+     prepackaged option, which we firmly point at...
+     [Andy Polyakov]
+
  Changes between 1.0.2h and 1.1.0  [25 Aug 2016]
 
   *) Windows command-line tool supports UTF-8 opt-in option for arguments
diff --git a/NEWS b/NEWS
index ab9ea17..bdb7a4f 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.1 [under development]
+  Major changes between OpenSSL 1.1.0a and OpenSSL 1.1.1 [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/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/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 1774f7a..e3e593b 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2378,18 +2378,6 @@ static int tls_construct_cke_gost(SSL *s, WPACKET *pkt, 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
      */
@@ -2432,12 +2420,6 @@ static int tls_construct_cke_gost(SSL *s, WPACKET *pkt, int *al)
         goto err;
     }
 
-    /* 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 035353c..4733bff 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2019,6 +2019,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;
@@ -2030,13 +2046,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));
@@ -2385,6 +2394,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