Backport certificate status request TLS extension support to 0.9.8.
authorDr. Stephen Henson <steve@openssl.org>
Fri, 12 Oct 2007 00:00:36 +0000 (00:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 12 Oct 2007 00:00:36 +0000 (00:00 +0000)
27 files changed:
CHANGES
apps/apps.h
apps/ocsp.c
apps/s_client.c
apps/s_server.c
apps/x509.c
crypto/asn1/x_exten.c
crypto/ocsp/ocsp.h
crypto/ocsp/ocsp_err.c
crypto/ocsp/ocsp_ht.c
crypto/ossl_typ.h
crypto/stack/safestack.h
crypto/x509/x509.h
crypto/x509v3/v3_utl.c
crypto/x509v3/x509v3.h
ssl/s23_clnt.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_lib.c
ssl/tls1.h
util/libeay.num

diff --git a/CHANGES b/CHANGES
index 141cce877637586e6fb1507f827635011e742d2a..a3a713a7ac3f19b7cc458d255e79ed067bc36f23 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,12 @@
 
  Changes between 0.9.8f and 0.9.8g  [xx XXX xxxx]
 
-  *)
+  *) Implement certificate status request TLS extension defined in RFC3546.
+     A client can set the appropriate parameters and receive the encoded
+     OCSP response via a callback. A server can query the supplied parameters
+     and set the encoded OCSP response in the callback. Add simplified examples
+     to s_client and s_server.
+     [Steve Henson]
 
  Changes between 0.9.8e and 0.9.8f  [11 Oct 2007]
 
index 26dcbc5771d5ca1888830468e6d8c66fbcf8fd18..0df170813ae15215272e9562fc52143f0eff524c 100644 (file)
 #ifndef OPENSSL_NO_ENGINE
 #include <openssl/engine.h>
 #endif
+#ifndef OPENSSL_NO_OCSP
+#include <openssl/ocsp.h>
+#endif
 #include <openssl/ossl_typ.h>
 
 int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
@@ -228,6 +231,12 @@ extern BIO *bio_err;
 #  endif
 #endif
 
+#ifdef OPENSSL_SYSNAME_WIN32
+#  define openssl_fdset(a,b) FD_SET((unsigned int)a, b)
+#else
+#  define openssl_fdset(a,b) FD_SET(a, b)
+#endif
+
 typedef struct args_st
        {
        char **data;
@@ -275,6 +284,12 @@ X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
 ENGINE *setup_engine(BIO *err, const char *engine, int debug);
 #endif
 
+#ifndef OPENSSL_NO_OCSP
+OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
+                       char *host, char *path, char *port, int use_ssl,
+                       int req_timeout);
+#endif
+
 int load_config(BIO *err, CONF *cnf);
 char *make_config_name(void);
 
index 3dc36c4bdc4a4ab67b5a6f68f1e780fd487123af..df0339b74315380561a7e191fe4349c71483123d 100644 (file)
 #ifndef OPENSSL_NO_OCSP
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include "apps.h"
-#include <openssl/pem.h>
+#include <openssl/e_os2.h>
+#include <openssl/bio.h>
 #include <openssl/ocsp.h>
-#include <openssl/err.h>
+#include <openssl/txt_db.h>
 #include <openssl/ssl.h>
-#include <openssl/bn.h>
+#include "apps.h"
 
 /* Maximum leeway in validity period: default 5 minutes */
 #define MAX_VALIDITY_PERIOD    (5 * 60)
@@ -86,6 +87,8 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
 static BIO *init_responder(char *port);
 static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port);
 static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
+static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
+                               OCSP_REQUEST *req, int req_timeout);
 
 #undef PROG
 #define PROG ocsp_main
@@ -112,11 +115,11 @@ int MAIN(int argc, char **argv)
        BIO *acbio = NULL, *cbio = NULL;
        BIO *derbio = NULL;
        BIO *out = NULL;
+       int req_timeout = -1;
        int req_text = 0, resp_text = 0;
        long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
        char *CAfile = NULL, *CApath = NULL;
        X509_STORE *store = NULL;
-       SSL_CTX *ctx = NULL;
        STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
        char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
        unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
@@ -154,6 +157,22 @@ int MAIN(int argc, char **argv)
                                }
                        else badarg = 1;
                        }
+               else if (!strcmp(*args, "-timeout"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               req_timeout = atol(*args);
+                               if (req_timeout < 0)
+                                       {
+                                       BIO_printf(bio_err,
+                                               "Illegal timeout value %s\n",
+                                               *args);
+                                       badarg = 1;
+                                       }
+                               }
+                       else badarg = 1;
+                       }
                else if (!strcmp(*args, "-url"))
                        {
                        if (args[1])
@@ -703,52 +722,14 @@ int MAIN(int argc, char **argv)
        else if (host)
                {
 #ifndef OPENSSL_NO_SOCK
-               cbio = BIO_new_connect(host);
+               resp = process_responder(bio_err, req, host, path,
+                                               port, use_ssl, req_timeout);
+               if (!resp)
+                       goto end;
 #else
                BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
                goto end;
 #endif
-               if (!cbio)
-                       {
-                       BIO_printf(bio_err, "Error creating connect BIO\n");
-                       goto end;
-                       }
-               if (port) BIO_set_conn_port(cbio, port);
-               if (use_ssl == 1)
-                       {
-                       BIO *sbio;
-#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
-                       ctx = SSL_CTX_new(SSLv23_client_method());
-#elif !defined(OPENSSL_NO_SSL3)
-                       ctx = SSL_CTX_new(SSLv3_client_method());
-#elif !defined(OPENSSL_NO_SSL2)
-                       ctx = SSL_CTX_new(SSLv2_client_method());
-#else
-                       BIO_printf(bio_err, "SSL is disabled\n");
-                       goto end;
-#endif
-                       if (ctx == NULL)
-                               {
-                               BIO_printf(bio_err, "Error creating SSL context.\n");
-                               goto end;
-                               }
-                       SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
-                       sbio = BIO_new_ssl(ctx, 1);
-                       cbio = BIO_push(sbio, cbio);
-                       }
-               if (BIO_do_connect(cbio) <= 0)
-                       {
-                       BIO_printf(bio_err, "Error connecting BIO\n");
-                       goto end;
-                       }
-               resp = OCSP_sendreq_bio(cbio, path, req);
-               BIO_free_all(cbio);
-               cbio = NULL;
-               if (!resp)
-                       {
-                       BIO_printf(bio_err, "Error querying OCSP responsder\n");
-                       goto end;
-                       }
                }
        else if (respin)
                {
@@ -897,7 +878,6 @@ end:
                OPENSSL_free(host);
                OPENSSL_free(port);
                OPENSSL_free(path);
-               SSL_CTX_free(ctx);
                }
 
        OPENSSL_EXIT(ret);
@@ -1121,6 +1101,7 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
        char *itmp, *row[DB_NUMBER],**rrow;
        for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
        bn = ASN1_INTEGER_to_BN(ser,NULL);
+       OPENSSL_assert(bn); /* FIXME: should report an error at this point and abort */
        if (BN_is_zero(bn))
                itmp = BUF_strdup("00");
        else
@@ -1231,4 +1212,137 @@ static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
        return 1;
        }
 
+static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
+                               OCSP_REQUEST *req, int req_timeout)
+       {
+       int fd;
+       int rv;
+       OCSP_REQ_CTX *ctx = NULL;
+       OCSP_RESPONSE *rsp = NULL;
+       fd_set confds;
+       struct timeval tv;
+
+       if (req_timeout != -1)
+               BIO_set_nbio(cbio, 1);
+
+       rv = BIO_do_connect(cbio);
+
+       if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio)))
+               {
+               BIO_puts(err, "Error connecting BIO\n");
+               return NULL;
+               }
+
+       if (req_timeout == -1)
+               return OCSP_sendreq_bio(cbio, path, req);
+
+       if (BIO_get_fd(cbio, &fd) <= 0)
+               {
+               BIO_puts(err, "Can't get connection fd\n");
+               goto err;
+               }
+
+       if (rv <= 0)
+               {
+               FD_ZERO(&confds);
+               openssl_fdset(fd, &confds);
+               tv.tv_usec = 0;
+               tv.tv_sec = req_timeout;
+               rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
+               if (rv == 0)
+                       {
+                       BIO_puts(err, "Timeout on connect\n");
+                       return NULL;
+                       }
+               }
+
+
+       ctx = OCSP_sendreq_new(cbio, path, req, -1);
+       if (!ctx)
+               return NULL;
+       
+       for (;;)
+               {
+               rv = OCSP_sendreq_nbio(&rsp, ctx);
+               if (rv != -1)
+                       break;
+               FD_ZERO(&confds);
+               openssl_fdset(fd, &confds);
+               tv.tv_usec = 0;
+               tv.tv_sec = req_timeout;
+               if (BIO_should_read(cbio))
+                       rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
+               else if (BIO_should_write(cbio))
+                       rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
+               else
+                       {
+                       BIO_puts(err, "Unexpected retry condition\n");
+                       goto err;
+                       }
+               if (rv == 0)
+                       {
+                       BIO_puts(err, "Timeout on request\n");
+                       break;
+                       }
+               if (rv == -1)
+                       {
+                       BIO_puts(err, "Select error\n");
+                       break;
+                       }
+                       
+               }
+       err:
+       if (ctx)
+               OCSP_REQ_CTX_free(ctx);
+
+       return rsp;
+       }
+
+OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
+                       char *host, char *path, char *port, int use_ssl,
+                       int req_timeout)
+       {
+       BIO *cbio = NULL;
+       SSL_CTX *ctx = NULL;
+       OCSP_RESPONSE *resp = NULL;
+       cbio = BIO_new_connect(host);
+       if (!cbio)
+               {
+               BIO_printf(err, "Error creating connect BIO\n");
+               goto end;
+               }
+       if (port) BIO_set_conn_port(cbio, port);
+       if (use_ssl == 1)
+               {
+               BIO *sbio;
+#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
+               ctx = SSL_CTX_new(SSLv23_client_method());
+#elif !defined(OPENSSL_NO_SSL3)
+               ctx = SSL_CTX_new(SSLv3_client_method());
+#elif !defined(OPENSSL_NO_SSL2)
+               ctx = SSL_CTX_new(SSLv2_client_method());
+#else
+               BIO_printf(err, "SSL is disabled\n");
+                       goto end;
+#endif
+               if (ctx == NULL)
+                       {
+                       BIO_printf(err, "Error creating SSL context.\n");
+                       goto end;
+                       }
+               SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+               sbio = BIO_new_ssl(ctx, 1);
+               cbio = BIO_push(sbio, cbio);
+               }
+       resp = query_responder(err, cbio, path, req, req_timeout);
+       if (!resp)
+               BIO_printf(bio_err, "Error querying OCSP responsder\n");
+       end:
+       if (ctx)
+               SSL_CTX_free(ctx);
+       if (cbio)
+               BIO_free_all(cbio);
+       return resp;
+       }
+
 #endif
index d240fe2a98851e73bbfd40d4bda779e2e6a568f3..f444d27a9f99d6b36958b0315644a379c192a04c 100644 (file)
@@ -134,6 +134,7 @@ typedef unsigned int u_int;
 #include <openssl/err.h>
 #include <openssl/pem.h>
 #include <openssl/rand.h>
+#include <openssl/ocsp.h>
 #include "s_apps.h"
 #include "timeouts.h"
 
@@ -173,12 +174,14 @@ static int c_Pause=0;
 static int c_debug=0;
 #ifndef OPENSSL_NO_TLSEXT
 static int c_tlsextdebug=0;
+static int c_status_req=0;
 #endif
 static int c_msg=0;
 static int c_showcerts=0;
 
 static void sc_usage(void);
 static void print_stuff(BIO *berr,SSL *con,int full);
+static int ocsp_resp_cb(SSL *s, void *arg);
 static BIO *bio_c_out=NULL;
 static int c_quiet=0;
 static int c_ign_eof=0;
@@ -239,6 +242,7 @@ static void sc_usage(void)
 #ifndef OPENSSL_NO_TLSEXT
        BIO_printf(bio_err," -servername host  - Set TLS extension servername in ClientHello\n");
        BIO_printf(bio_err," -tlsextdebug      - hex dump of all TLS extensions received\n");
+       BIO_printf(bio_err," -status           - request certificate status from server\n");
        BIO_printf(bio_err," -no_ticket        - disable use of RFC4507bis session tickets\n");
 #endif
        }
@@ -435,6 +439,8 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_TLSEXT
                else if (strcmp(*argv,"-tlsextdebug") == 0)
                        c_tlsextdebug=1;
+               else if (strcmp(*argv,"-status") == 0)
+                       c_status_req=1;
 #endif
 #ifdef WATT32
                else if (strcmp(*argv,"-wdebug") == 0)
@@ -826,6 +832,23 @@ re_start:
                SSL_set_tlsext_debug_callback(con, tlsext_cb);
                SSL_set_tlsext_debug_arg(con, bio_c_out);
                }
+       if (c_status_req)
+               {
+               SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp);
+               SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb);
+               SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
+#if 0
+{
+STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null();
+OCSP_RESPID *id = OCSP_RESPID_new();
+id->value.byKey = ASN1_OCTET_STRING_new();
+id->type = V_OCSP_RESPID_KEY;
+ASN1_STRING_set(id->value.byKey, "Hello World", -1);
+sk_OCSP_RESPID_push(ids, id);
+SSL_set_tlsext_status_ids(con, ids);
+}
+#endif
+               }
 #endif
 
        SSL_set_bio(con,sbio,sbio);
@@ -1430,3 +1453,28 @@ static void print_stuff(BIO *bio, SSL *s, int full)
        (void)BIO_flush(bio);
        }
 
+static int ocsp_resp_cb(SSL *s, void *arg)
+       {
+       const unsigned char *p;
+       int len;
+       OCSP_RESPONSE *rsp;
+       len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+       BIO_puts(arg, "OCSP response: ");
+       if (!p)
+               {
+               BIO_puts(arg, "no response sent\n");
+               return 1;
+               }
+       rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+       if (!rsp)
+               {
+               BIO_puts(arg, "response parse error\n");
+               BIO_dump_indent(arg, (char *)p, len, 4);
+               return 0;
+               }
+       BIO_puts(arg, "\n======================================\n");
+       OCSP_RESPONSE_print(arg, rsp, 0);
+       BIO_puts(arg, "======================================\n");
+       OCSP_RESPONSE_free(rsp);
+       return 1;
+       }
index 7c5775f81c15c3831dd27f083874952c06ab676c..2b4e256c1a46d890886e5ffb3e7c3d7f3f646894 100644 (file)
@@ -153,6 +153,7 @@ typedef unsigned int u_int;
 #include <openssl/x509.h>
 #include <openssl/ssl.h>
 #include <openssl/rand.h>
+#include <openssl/ocsp.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
@@ -269,6 +270,8 @@ static BIO *bio_s_out=NULL;
 static int s_debug=0;
 #ifndef OPENSSL_NO_TLSEXT
 static int s_tlsextdebug=0;
+static int s_tlsextstatus=0;
+static int cert_status_cb(SSL *s, void *arg);
 #endif
 static int s_msg=0;
 static int s_quiet=0;
@@ -585,6 +588,152 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg)
                }
        return SSL_TLSEXT_ERR_OK;
 }
+
+/* Structure passed to cert status callback */
+
+typedef struct tlsextstatusctx_st {
+   /* Default responder to use */
+   char *host, *path, *port;
+   int use_ssl;
+   int timeout;
+   BIO *err;
+   int verbose;
+} tlsextstatusctx;
+
+static tlsextstatusctx tlscstatp = {NULL, NULL, NULL, 0, -1, NULL, 0};
+
+/* Certificate Status callback. This is called when a client includes a
+ * certificate status request extension.
+ *
+ * This is a simplified version. It examines certificates each time and
+ * makes one OCSP responder query for each request.
+ *
+ * A full version would store details such as the OCSP certificate IDs and
+ * minimise the number of OCSP responses by caching them until they were
+ * considered "expired".
+ */
+
+static int cert_status_cb(SSL *s, void *arg)
+       {
+       tlsextstatusctx *srctx = arg;
+       BIO *err = srctx->err;
+       char *host, *port, *path;
+       int use_ssl;
+       unsigned char *rspder = NULL;
+       int rspderlen;
+       STACK *aia = NULL;
+       X509 *x = NULL;
+       X509_STORE_CTX inctx;
+       X509_OBJECT obj;
+       OCSP_REQUEST *req = NULL;
+       OCSP_RESPONSE *resp = NULL;
+       OCSP_CERTID *id = NULL;
+       STACK_OF(X509_EXTENSION) *exts;
+       int ret = SSL_TLSEXT_ERR_NOACK;
+       int i;
+#if 0
+STACK_OF(OCSP_RESPID) *ids;
+SSL_get_tlsext_status_ids(s, &ids);
+BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids));
+#endif
+       if (srctx->verbose)
+               BIO_puts(err, "cert_status: callback called\n");
+       /* Build up OCSP query from server certificate */
+       x = SSL_get_certificate(s);
+       aia = X509_get1_ocsp(x);
+       if (aia)
+               {
+               if (!OCSP_parse_url(sk_value(aia, 0),
+                       &host, &port, &path, &use_ssl))
+                       {
+                       BIO_puts(err, "cert_status: can't parse AIA URL\n");
+                       goto err;
+                       }
+               if (srctx->verbose)
+                       BIO_printf(err, "cert_status: AIA URL: %s\n",
+                                       sk_value(aia, 0));
+               }
+       else
+               {
+               if (!srctx->host)
+                       {
+                       BIO_puts(srctx->err, "cert_status: no AIA and no default responder URL\n");
+                       goto done;
+                       }
+               host = srctx->host;
+               path = srctx->path;
+               port = srctx->port;
+               use_ssl = srctx->use_ssl;
+               }
+               
+       if (!X509_STORE_CTX_init(&inctx,
+                               SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)),
+                               NULL, NULL))
+               goto err;
+       if (X509_STORE_get_by_subject(&inctx,X509_LU_X509,
+                               X509_get_issuer_name(x),&obj) <= 0)
+               {
+               BIO_puts(err, "cert_status: Can't retrieve issuer certificate.\n");
+               X509_STORE_CTX_cleanup(&inctx);
+               goto done;
+               }
+       req = OCSP_REQUEST_new();
+       if (!req)
+               goto err;
+       id = OCSP_cert_to_id(NULL, x, obj.data.x509);
+       X509_free(obj.data.x509);
+       X509_STORE_CTX_cleanup(&inctx);
+       if (!id)
+               goto err;
+       if (!OCSP_request_add0_id(req, id))
+               goto err;
+       id = NULL;
+       /* Add any extensions to the request */
+       SSL_get_tlsext_status_exts(s, &exts);
+       for (i = 0; i < sk_X509_EXTENSION_num(exts); i++)
+               {
+               X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+               if (!OCSP_REQUEST_add_ext(req, ext, -1))
+                       goto err;
+               }
+       resp = process_responder(err, req, host, path, port, use_ssl,
+                                       srctx->timeout);
+       if (!resp)
+               {
+               BIO_puts(err, "cert_status: error querying responder\n");
+               goto done;
+               }
+       rspderlen = i2d_OCSP_RESPONSE(resp, &rspder);
+       if (rspderlen <= 0)
+               goto err;
+       SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen);
+       if (srctx->verbose)
+               {
+               BIO_puts(err, "cert_status: ocsp response sent:\n");
+               OCSP_RESPONSE_print(err, resp, 2);
+               }
+       ret = SSL_TLSEXT_ERR_OK;
+       done:
+       if (ret != SSL_TLSEXT_ERR_OK)
+               ERR_print_errors(err);
+       if (aia)
+               {
+               OPENSSL_free(host);
+               OPENSSL_free(path);
+               OPENSSL_free(port);
+               X509_email_free(aia);
+               }
+       if (id)
+               OCSP_CERTID_free(id);
+       if (req)
+               OCSP_REQUEST_free(req);
+       if (resp)
+               OCSP_RESPONSE_free(resp);
+       return ret;
+       err:
+       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+       goto done;
+       }
 #endif
 int MAIN(int, char **);
 
@@ -792,6 +941,33 @@ int MAIN(int argc, char *argv[])
 #ifndef OPENSSL_NO_TLSEXT
                else if (strcmp(*argv,"-tlsextdebug") == 0)
                        s_tlsextdebug=1;
+               else if (strcmp(*argv,"-status") == 0)
+                       s_tlsextstatus=1;
+               else if (strcmp(*argv,"-status_verbose") == 0)
+                       {
+                       s_tlsextstatus=1;
+                       tlscstatp.verbose = 1;
+                       }
+               else if (!strcmp(*argv, "-status_timeout"))
+                       {
+                       s_tlsextstatus=1;
+                        if (--argc < 1) goto bad;
+                       tlscstatp.timeout = atoi(*(++argv));
+                       }
+               else if (!strcmp(*argv, "-status_url"))
+                       {
+                       s_tlsextstatus=1;
+                        if (--argc < 1) goto bad;
+                       if (!OCSP_parse_url(*(++argv),
+                                       &tlscstatp.host,
+                                       &tlscstatp.port,
+                                       &tlscstatp.path,
+                                       &tlscstatp.use_ssl))
+                               {
+                               BIO_printf(bio_err, "Error parsing URL\n");
+                               goto bad;
+                               }
+                       }
 #endif
                else if (strcmp(*argv,"-msg") == 0)
                        { s_msg=1; }
@@ -1430,6 +1606,12 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                SSL_set_tlsext_debug_callback(con, tlsext_cb);
                SSL_set_tlsext_debug_arg(con, bio_s_out);
                }
+       if (s_tlsextstatus)
+               {
+               SSL_CTX_set_tlsext_status_cb(ctx, cert_status_cb);
+               tlscstatp.err = bio_err;
+               SSL_CTX_set_tlsext_status_arg(ctx, &tlscstatp);
+               }
 #endif
 #ifndef OPENSSL_NO_KRB5
                if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
index 5f61eb5c467a54d125ba42a65ae0cd7d78bc0f4e..f6938356f8a7acd5f0b655ab24788588fb39e1e8 100644 (file)
@@ -114,6 +114,7 @@ static const char *x509_usage[]={
 " -alias          - output certificate alias\n",
 " -noout          - no certificate output\n",
 " -ocspid         - print OCSP hash values for the subject name and public key\n",
+" -ocspurl        - print OCSP Responder URL(s)\n",
 " -trustout       - output a \"trusted\" certificate\n",
 " -clrtrust       - clear all trusted purposes\n",
 " -clrreject      - clear all rejected purposes\n",
@@ -179,6 +180,7 @@ int MAIN(int argc, char **argv)
        int next_serial=0;
        int subject_hash=0,issuer_hash=0,ocspid=0;
        int noout=0,sign_flag=0,CA_flag=0,CA_createserial=0,email=0;
+       int ocsp_uri=0;
        int trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
        int C=0;
        int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
@@ -378,6 +380,8 @@ int MAIN(int argc, char **argv)
                        C= ++num;
                else if (strcmp(*argv,"-email") == 0)
                        email= ++num;
+               else if (strcmp(*argv,"-ocsp_uri") == 0)
+                       ocsp_uri= ++num;
                else if (strcmp(*argv,"-serial") == 0)
                        serial= ++num;
                else if (strcmp(*argv,"-next_serial") == 0)
@@ -731,11 +735,14 @@ bad:
                                ASN1_INTEGER_free(ser);
                                BIO_puts(out, "\n");
                                }
-                       else if (email == i) 
+                       else if ((email == i) || (ocsp_uri == i))
                                {
                                int j;
                                STACK *emlst;
-                               emlst = X509_get1_email(x);
+                               if (email == i)
+                                       emlst = X509_get1_email(x);
+                               else
+                                       emlst = X509_get1_ocsp(x);
                                for (j = 0; j < sk_num(emlst); j++)
                                        BIO_printf(STDout, "%s\n", sk_value(emlst, j));
                                X509_email_free(emlst);
index 702421b6c851d1ff2b108f15dc86a357b599882e..1732e667125c50ffa3f3a5ce1e677263cb2c4a87 100644 (file)
@@ -67,5 +67,10 @@ ASN1_SEQUENCE(X509_EXTENSION) = {
        ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
 } ASN1_SEQUENCE_END(X509_EXTENSION)
 
+ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) = 
+       ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION)
+ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS)
+
 IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION)
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
 IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION)
index 8163411c9223c230a865104aa78b4aa0ad5ac0f1..a0577a717ef49ca00e8743bfb2d6f118ed3da95a 100644 (file)
@@ -186,11 +186,11 @@ typedef struct ocsp_resp_bytes_st
  *      responseStatus         OCSPResponseStatus,
  *      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
  */
-typedef struct ocsp_response_st
+struct ocsp_response_st
        {
        ASN1_ENUMERATED *responseStatus;
        OCSP_RESPBYTES  *responseBytes;
-       } OCSP_RESPONSE;
+       };
 
 /*   ResponderID ::= CHOICE {
  *      byName   [1] Name,
@@ -198,14 +198,18 @@ typedef struct ocsp_response_st
  */
 #define V_OCSP_RESPID_NAME 0
 #define V_OCSP_RESPID_KEY  1
-typedef struct ocsp_responder_id_st
+struct ocsp_responder_id_st
        {
        int type;
        union   {
                X509_NAME* byName;
                ASN1_OCTET_STRING *byKey;
                } value;
-       } OCSP_RESPID;
+       };
+
+DECLARE_STACK_OF(OCSP_RESPID)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
+
 /*   KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
  *                            --(excluding the tag and length fields)
  */
@@ -397,6 +401,10 @@ typedef struct ocsp_service_locator_st
                (char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
 
 OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
+OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
+                                                               int maxline);
+int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx);
+void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx);
 
 OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
 
@@ -574,6 +582,7 @@ void ERR_load_OCSP_strings(void);
 #define OCSP_F_OCSP_REQUEST_VERIFY                      116
 #define OCSP_F_OCSP_RESPONSE_GET1_BASIC                         111
 #define OCSP_F_OCSP_SENDREQ_BIO                                 112
+#define OCSP_F_PARSE_HTTP_LINE1                                 117
 #define OCSP_F_REQUEST_VERIFY                           113
 
 /* Reason codes. */
index ad62364f298e4b3fc8d5e3f6967bb7a8b6ae8f6c..d2f2e79f444c394e057ffb213d43329e160df17c 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/ocsp/ocsp_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -86,6 +86,7 @@ static ERR_STRING_DATA OCSP_str_functs[]=
 {ERR_FUNC(OCSP_F_OCSP_REQUEST_VERIFY), "OCSP_request_verify"},
 {ERR_FUNC(OCSP_F_OCSP_RESPONSE_GET1_BASIC),    "OCSP_response_get1_basic"},
 {ERR_FUNC(OCSP_F_OCSP_SENDREQ_BIO),    "OCSP_sendreq_bio"},
+{ERR_FUNC(OCSP_F_PARSE_HTTP_LINE1),    "PARSE_HTTP_LINE1"},
 {ERR_FUNC(OCSP_F_REQUEST_VERIFY),      "REQUEST_VERIFY"},
 {0,NULL}
        };
index 9213e58ae49c126f01c587c46d0c105b041c0e54..a8e569b74a0c18fdc1791f975001b21d70800f9b 100644 (file)
@@ -1,9 +1,9 @@
 /* ocsp_ht.c */
 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
- * project 2000.
+ * project 2006.
  */
 /* ====================================================================
- * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #define strtoul (unsigned long)strtol
 #endif /* OPENSSL_SYS_SUNOS */
 
-/* Quick and dirty HTTP OCSP request handler.
- * Could make this a bit cleverer by adding
- * support for non blocking BIOs and a few
- * other refinements.
- */
+/* Stateful OCSP request code, supporting non-blocking I/O */
 
-OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
-{
-       BIO *mem = NULL;
-       char tmpbuf[1024];
-       OCSP_RESPONSE *resp = NULL;
-       char *p, *q, *r;
-       int len, retcode;
-       static char req_txt[] =
-"POST %s HTTP/1.0\r\n\
-Content-Type: application/ocsp-request\r\n\
-Content-Length: %d\r\n\r\n";
-
-       len = i2d_OCSP_REQUEST(req, NULL);
-       if(BIO_printf(b, req_txt, path, len) < 0) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
-               goto err;
-       }
-       if(i2d_OCSP_REQUEST_bio(b, req) <= 0) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
-               goto err;
+/* Opaque OCSP request status structure */
+
+struct ocsp_req_ctx_st {
+       int state;              /* Current I/O state */
+       unsigned char *iobuf;   /* Line buffer */
+       int iobuflen;           /* Line buffer length */
+       BIO *io;                /* BIO to perform I/O with */
+       BIO *mem;               /* Memory BIO response is built into */
+       unsigned long asn1_len; /* ASN1 length of response */
+       };
+
+#define OCSP_MAX_REQUEST_LENGTH        (100 * 1024)
+#define OCSP_MAX_LINE_LEN      4096;
+
+/* OCSP states */
+
+/* If set no reading should be performed */
+#define OHS_NOREAD             0x1000
+/* Error condition */
+#define OHS_ERROR              (0 | OHS_NOREAD)
+/* First line being read */
+#define OHS_FIRSTLINE          1
+/* MIME headers being read */
+#define OHS_HEADERS            2
+/* OCSP initial header (tag + length) being read */
+#define OHS_ASN1_HEADER                3
+/* OCSP content octets being read */
+#define OHS_ASN1_CONTENT       4
+/* Request being sent */
+#define OHS_ASN1_WRITE         (6 | OHS_NOREAD)
+/* Request being flushed */
+#define OHS_ASN1_FLUSH         (7 | OHS_NOREAD)
+/* Completed */
+#define OHS_DONE               (8 | OHS_NOREAD)
+
+
+static int parse_http_line1(char *line);
+
+void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
+       {
+       if (rctx->mem)
+               BIO_free(rctx->mem);
+       if (rctx->iobuf)
+               OPENSSL_free(rctx->iobuf);
+       OPENSSL_free(rctx);
        }
-       if(!(mem = BIO_new(BIO_s_mem()))) goto err;
-       /* Copy response to a memory BIO: socket bios can't do gets! */
-       while ((len = BIO_read(b, tmpbuf, sizeof tmpbuf))) {
-               if(len < 0) {
-                       OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_READ_ERROR);
-                       goto err;
+
+OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
+                                                               int maxline)
+       {
+       static char post_hdr[] = "POST %s HTTP/1.0\r\n"
+       "Content-Type: application/ocsp-request\r\n"
+       "Content-Length: %d\r\n\r\n";
+
+       OCSP_REQ_CTX *rctx;
+       rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX));
+       rctx->state = OHS_FIRSTLINE;
+       rctx->mem = BIO_new(BIO_s_mem());
+       rctx->io = io;
+       if (maxline > 0)
+               rctx->iobuflen = maxline;
+       else
+               rctx->iobuflen = OCSP_MAX_LINE_LEN;
+       rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
+       if (!path)
+               path = "/";
+
+        if (BIO_printf(rctx->mem, post_hdr, path,
+                               i2d_OCSP_REQUEST(req, NULL)) <= 0)
+               {
+               rctx->state = OHS_ERROR;
+               return 0;
                }
-               BIO_write(mem, tmpbuf, len);
-       }
-       if(BIO_gets(mem, tmpbuf, 512) <= 0) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
-               goto err;
+        if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0)
+               {
+               rctx->state = OHS_ERROR;
+               return 0;
+               }
+       rctx->state = OHS_ASN1_WRITE;
+       rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
+
+       return rctx;
        }
-       /* Parse the HTTP response. This will look like this:
-        * "HTTP/1.0 200 OK". We need to obtain the numeric code and
-         * (optional) informational message.
-        */
 
+/* Parse the HTTP response. This will look like this:
+ * "HTTP/1.0 200 OK". We need to obtain the numeric code and
+ * (optional) informational message.
+ */
+
+static int parse_http_line1(char *line)
+       {
+       int retcode;
+       char *p, *q, *r;
        /* Skip to first white space (passed protocol info) */
-       for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
-       if(!*p) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
-               goto err;
-       }
+
+       for(p = line; *p && !isspace((unsigned char)*p); p++)
+               continue;
+       if(!*p)
+               {
+               OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
+                                       OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+               return 0;
+               }
+
        /* Skip past white space to start of response code */
-       while(*p && isspace((unsigned char)*p)) p++;
-       if(!*p) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
-               goto err;
-       }
+       while(*p && isspace((unsigned char)*p))
+               p++;
+
+       if(!*p)
+               {
+               OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
+                                       OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+               return 0;
+               }
+
        /* Find end of response code: first whitespace after start of code */
-       for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
-       if(!*q) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
-               goto err;
-       }
+       for(q = p; *q && !isspace((unsigned char)*q); q++)
+               continue;
+
+       if(!*q)
+               {
+               OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
+                                       OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+               return 0;
+               }
+
        /* Set end of response code and start of message */ 
        *q++ = 0;
+
        /* Attempt to parse numeric code */
        retcode = strtoul(p, &r, 10);
-       if(*r) goto err;
+
+       if(*r)
+               return 0;
+
        /* Skip over any leading white space in message */
-       while(*q && isspace((unsigned char)*q))  q++;
-       if(*q) {
-       /* Finally zap any trailing white space in message (include CRLF) */
-       /* We know q has a non white space character so this is OK */
-               for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
-       }
-       if(retcode != 200) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_ERROR);
-               if(!*q) { 
-                       ERR_add_error_data(2, "Code=", p);
+       while(*q && isspace((unsigned char)*q))
+               q++;
+
+       if(*q)
+               {
+               /* Finally zap any trailing white space in message (include
+                * CRLF) */
+
+               /* We know q has a non white space character so this is OK */
+               for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
+                       *r = 0;
                }
-               else {
+       if(retcode != 200)
+               {
+               OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
+               if(!*q)
+                       ERR_add_error_data(2, "Code=", p);
+               else
                        ERR_add_error_data(4, "Code=", p, ",Reason=", q);
+               return 0;
                }
-               goto err;
+
+
+       return 1;
+
        }
-       /* Find blank line marking beginning of content */      
-       while(BIO_gets(mem, tmpbuf, 512) > 0)
+
+int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
        {
-               for(p = tmpbuf; *p && isspace((unsigned char)*p); p++) continue;
-               if(!*p) break;
-       }
-       if(*p) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_NO_CONTENT);
-               goto err;
+       int i, n;
+       const unsigned char *p;
+       next_io:
+       if (!(rctx->state & OHS_NOREAD))
+               {
+               n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
+
+               if (n <= 0)
+                       {
+                       if (BIO_should_retry(rctx->io))
+                               return -1;
+                       return 0;
+                       }
+
+               /* Write data to memory BIO */
+
+               if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
+                       return 0;
+               }
+
+       switch(rctx->state)
+               {
+
+               case OHS_ASN1_WRITE:
+               n = BIO_get_mem_data(rctx->mem, &p);
+
+               i = BIO_write(rctx->io,
+                       p + (n - rctx->asn1_len), rctx->asn1_len);
+
+               if (i <= 0)
+                       {
+                       if (BIO_should_retry(rctx->io))
+                               return -1;
+                       rctx->state = OHS_ERROR;
+                       return 0;
+                       }
+
+               rctx->asn1_len -= i;
+
+               if (rctx->asn1_len > 0)
+                       goto next_io;
+
+               rctx->state = OHS_ASN1_FLUSH;
+
+               (void)BIO_reset(rctx->mem);
+
+               case OHS_ASN1_FLUSH:
+
+               i = BIO_flush(rctx->io);
+
+               if (i > 0)
+                       {
+                       rctx->state = OHS_FIRSTLINE;
+                       goto next_io;
+                       }
+
+               if (BIO_should_retry(rctx->io))
+                       return -1;
+
+               rctx->state = OHS_ERROR;
+               return 0;
+
+               case OHS_ERROR:
+               return 0;
+
+               case OHS_FIRSTLINE:
+               case OHS_HEADERS:
+
+               /* Attempt to read a line in */
+
+               next_line:
+               /* Due to &%^*$" memory BIO behaviour with BIO_gets we
+                * have to check there's a complete line in there before
+                * calling BIO_gets or we'll just get a partial read.
+                */
+               n = BIO_get_mem_data(rctx->mem, &p);
+               if ((n <= 0) || !memchr(p, '\n', n))
+                       {
+                       if (n >= rctx->iobuflen)
+                               {
+                               rctx->state = OHS_ERROR;
+                               return 0;
+                               }
+                       goto next_io;
+                       }
+               n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
+
+               if (n <= 0)
+                       {
+                       if (BIO_should_retry(rctx->mem))
+                               goto next_io;
+                       rctx->state = OHS_ERROR;
+                       return 0;
+                       }
+
+               /* Don't allow excessive lines */
+               if (n == rctx->iobuflen)
+                       {
+                       rctx->state = OHS_ERROR;
+                       return 0;
+                       }
+
+               /* First line */
+               if (rctx->state == OHS_FIRSTLINE)
+                       {
+                       if (parse_http_line1((char *)rctx->iobuf))
+                               {
+                               rctx->state = OHS_HEADERS;
+                               goto next_line;
+                               }
+                       else
+                               {
+                               rctx->state = OHS_ERROR;
+                               return 0;
+                               }
+                       }
+               else
+                       {
+                       /* Look for blank line: end of headers */
+                       for (p = rctx->iobuf; *p; p++)
+                               {
+                               if ((*p != '\r') && (*p != '\n'))
+                                       break;
+                               }
+                       if (*p)
+                               goto next_line;
+
+                       rctx->state = OHS_ASN1_HEADER;
+
+                       }
+               /* Fall thru */
+
+
+               case OHS_ASN1_HEADER:
+               /* Now reading ASN1 header: can read at least 6 bytes which
+                * is more than enough for any valid ASN1 SEQUENCE header
+                */
+               n = BIO_get_mem_data(rctx->mem, &p);
+               if (n < 6)
+                       goto next_io;
+
+               /* Check it is an ASN1 SEQUENCE */
+               if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED))
+                       {
+                       rctx->state = OHS_ERROR;
+                       return 0;
+                       }
+
+               /* Check out length field */
+               if (*p & 0x80)
+                       {
+                       n = *p & 0x7F;
+                       /* Not NDEF or excessive length */
+                       if (!n || (n > 4))
+                               {
+                               rctx->state = OHS_ERROR;
+                               return 0;
+                               }
+                       p++;
+                       rctx->asn1_len = 0;
+                       for (i = 0; i < n; i++)
+                               {
+                               rctx->asn1_len <<= 8;
+                               rctx->asn1_len |= *p++;
+                               }
+
+                       if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH)
+                               {
+                               rctx->state = OHS_ERROR;
+                               return 0;
+                               }
+
+                       rctx->asn1_len += n + 2;
+                       }
+               else
+                       rctx->asn1_len = *p + 2;
+
+               rctx->state = OHS_ASN1_CONTENT;
+
+               /* Fall thru */
+               
+               case OHS_ASN1_CONTENT:
+               n = BIO_get_mem_data(rctx->mem, &p);
+               if (n < (int)rctx->asn1_len)
+                       goto next_io;
+
+
+               *presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
+               if (*presp)
+                       {
+                       rctx->state = OHS_DONE;
+                       return 1;
+                       }
+
+               rctx->state = OHS_ERROR;
+               return 0;
+
+               break;
+
+               case OHS_DONE:
+               return 1;
+
+               }
+
+
+
+       return 0;
+
+
        }
-       if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
-               OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,ERR_R_NESTED_ASN1_ERROR);
-               goto err;
+
+/* Blocking OCSP request handler: now a special case of non-blocking I/O */
+
+OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
+       {
+       OCSP_RESPONSE *resp = NULL;
+       OCSP_REQ_CTX *ctx;
+       int rv;
+
+       ctx = OCSP_sendreq_new(b, path, req, -1);
+
+       do
+               {
+               rv = OCSP_sendreq_nbio(&resp, ctx);
+               } while ((rv == -1) && BIO_should_retry(b));
+
+       OCSP_REQ_CTX_free(ctx);
+
+       if (rv)
+               return resp;
+
+       return NULL;
        }
-       err:
-       BIO_free(mem);
-       return resp;
-}
index 9c335a181909da585d16205bd7c0105318f0e123..08c2968f122d27373659258120ccc3edd6c0963d 100644 (file)
@@ -171,4 +171,8 @@ typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
 typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, 
                                        int idx, long argl, void *argp);
 
+typedef struct ocsp_req_ctx_st OCSP_REQ_CTX;
+typedef struct ocsp_response_st OCSP_RESPONSE;
+typedef struct ocsp_responder_id_st OCSP_RESPID;
+
 #endif /* def HEADER_OPENSSL_TYPES_H */
index 53df649ecf84884ba5aca39e8bb00bebb13d74bd..c3b7ed53db0840f86283c4514228d8d8fc7f9e4c 100644 (file)
@@ -964,6 +964,28 @@ STACK_OF(type) \
 #define sk_OCSP_ONEREQ_sort(st) SKM_sk_sort(OCSP_ONEREQ, (st))
 #define sk_OCSP_ONEREQ_is_sorted(st) SKM_sk_is_sorted(OCSP_ONEREQ, (st))
 
+#define sk_OCSP_RESPID_new(st) SKM_sk_new(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_new_null() SKM_sk_new_null(OCSP_RESPID)
+#define sk_OCSP_RESPID_free(st) SKM_sk_free(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_num(st) SKM_sk_num(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_value(st, i) SKM_sk_value(OCSP_RESPID, (st), (i))
+#define sk_OCSP_RESPID_set(st, i, val) SKM_sk_set(OCSP_RESPID, (st), (i), (val))
+#define sk_OCSP_RESPID_zero(st) SKM_sk_zero(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_push(st, val) SKM_sk_push(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_unshift(st, val) SKM_sk_unshift(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_find(st, val) SKM_sk_find(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_find_ex(st, val) SKM_sk_find_ex(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_delete(st, i) SKM_sk_delete(OCSP_RESPID, (st), (i))
+#define sk_OCSP_RESPID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_RESPID, (st), (ptr))
+#define sk_OCSP_RESPID_insert(st, val, i) SKM_sk_insert(OCSP_RESPID, (st), (val), (i))
+#define sk_OCSP_RESPID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_RESPID, (st), (cmp))
+#define sk_OCSP_RESPID_dup(st) SKM_sk_dup(OCSP_RESPID, st)
+#define sk_OCSP_RESPID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_RESPID, (st), (free_func))
+#define sk_OCSP_RESPID_shift(st) SKM_sk_shift(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_pop(st) SKM_sk_pop(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_sort(st) SKM_sk_sort(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_is_sorted(st) SKM_sk_is_sorted(OCSP_RESPID, (st))
+
 #define sk_OCSP_SINGLERESP_new(st) SKM_sk_new(OCSP_SINGLERESP, (st))
 #define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
 #define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st))
index 16a954f709941a57224a2b621c543831927cf60d..c431237ec7e94aaa3e6389b86667cefefbf0d62d 100644 (file)
@@ -203,6 +203,8 @@ typedef struct X509_extension_st
        ASN1_OCTET_STRING *value;
        } X509_EXTENSION;
 
+typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
+
 DECLARE_STACK_OF(X509_EXTENSION)
 DECLARE_ASN1_SET_OF(X509_EXTENSION)
 
@@ -918,6 +920,7 @@ DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
 X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
 
 DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
+DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
 
 DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
 
index 3dba0557b86d87bb77d274c7a381af7f9b5638ac..ac171ca940a3cb6d721797f79cafde5d3d587266 100644 (file)
@@ -473,6 +473,30 @@ STACK *X509_get1_email(X509 *x)
        return ret;
 }
 
+STACK *X509_get1_ocsp(X509 *x)
+{
+       AUTHORITY_INFO_ACCESS *info;
+       STACK *ret = NULL;
+       int i;
+       info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL);
+       if (!info)
+               return NULL;
+       for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++)
+               {
+               ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
+               if (OBJ_obj2nid(ad->method) == NID_ad_OCSP)
+                       {
+                       if (ad->location->type == GEN_URI)
+                               {
+                               if (!append_ia5(&ret, ad->location->d.uniformResourceIdentifier))
+                                       break;
+                               }
+                       }
+               }
+       AUTHORITY_INFO_ACCESS_free(info);
+       return ret;
+}
+
 STACK *X509_REQ_get1_email(X509_REQ *x)
 {
        GENERAL_NAMES *gens;
index 91d2fb5b8baf6c3469bee022b985ff0f8930d318..db2b0482c152e57fcc1749ca097ab053f82bdb1a 100644 (file)
@@ -617,6 +617,7 @@ int X509_PURPOSE_get_id(X509_PURPOSE *);
 STACK *X509_get1_email(X509 *x);
 STACK *X509_REQ_get1_email(X509_REQ *x);
 void X509_email_free(STACK *sk);
+STACK *X509_get1_ocsp(X509 *x);
 
 ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
 ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
index a596e7b2ec9843ed18eb8fc9a507d2e7452f0611..c45a8e0a04cfeb9c5b82d7373300f7f2045e5db1 100644 (file)
@@ -230,6 +230,8 @@ static int ssl23_client_hello(SSL *s)
 
                if (s->tlsext_hostname != NULL)
                        ssl2_compat = 0;
+               if (s->tlsext_status_type != -1)
+                       ssl2_compat = 0;
                }
 #endif
 
index 4d4d63a6f1b64971a706f2bfe6372b881c314cfe..4e7846bb4cceea2c5f06ac3895e7e03464785f1f 100644 (file)
@@ -283,10 +283,23 @@ int ssl3_connect(SSL *s)
                                {
                                ret=ssl3_get_server_certificate(s);
                                if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+                               if (s->tlsext_status_expected)
+                                       s->state=SSL3_ST_CR_CERT_STATUS_A;
+                               else
+                                       s->state=SSL3_ST_CR_KEY_EXCH_A;
                                }
+                       else
+                               {
+                               skip = 1;
+                               s->state=SSL3_ST_CR_KEY_EXCH_A;
+                               }
+#else
                        else
                                skip=1;
+
                        s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
                        s->init_num=0;
                        break;
 
@@ -450,6 +463,14 @@ int ssl3_connect(SSL *s)
                        s->state=SSL3_ST_CR_FINISHED_A;
                        s->init_num=0;
                break;
+
+               case SSL3_ST_CR_CERT_STATUS_A:
+               case SSL3_ST_CR_CERT_STATUS_B:
+                       ret=ssl3_get_cert_status(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_CR_KEY_EXCH_A;
+                       s->init_num=0;
+               break;
 #endif
 
                case SSL3_ST_CR_FINISHED_A:
@@ -1688,7 +1709,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        if (ticklen + 6 != n)
                {
                al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
        if (s->session->tlsext_tick)
@@ -1699,7 +1720,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        s->session->tlsext_tick = OPENSSL_malloc(ticklen);
        if (!s->session->tlsext_tick)
                {
-               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
                goto err;
                }
        memcpy(s->session->tlsext_tick, p, ticklen);
@@ -1712,6 +1733,75 @@ f_err:
 err:
        return(-1);
        }
+
+int ssl3_get_cert_status(SSL *s)
+       {
+       int ok, al;
+       unsigned long resplen;
+       long n;
+       const unsigned char *p;
+
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_CERT_STATUS_A,
+               SSL3_ST_CR_CERT_STATUS_B,
+               SSL3_MT_CERTIFICATE_STATUS,
+               16384,
+               &ok);
+
+       if (!ok) return((int)n);
+       if (n < 4)
+               {
+               /* need at least status type + length */
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       p = (unsigned char *)s->init_msg;
+       if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+               {
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
+               goto f_err;
+               }
+       n2l3(p, resplen);
+       if (resplen + 4 != n)
+               {
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       if (s->tlsext_ocsp_resp)
+               OPENSSL_free(s->tlsext_ocsp_resp);
+       s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+       if (!s->tlsext_ocsp_resp)
+               {
+               al = SSL_AD_INTERNAL_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+               goto f_err;
+               }
+       s->tlsext_ocsp_resplen = resplen;
+       if (s->ctx->tlsext_status_cb)
+               {
+               int ret;
+               ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+               if (ret == 0)
+                       {
+                       al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+                       SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
+                       goto f_err;
+                       }
+               if (ret < 0)
+                       {
+                       al = SSL_AD_INTERNAL_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+                       goto f_err;
+                       }
+               }
+       return 1;
+f_err:
+       ssl3_send_alert(s,SSL3_AL_FATAL,al);
+       return(-1);
+       }
 #endif
 
 int ssl3_get_server_done(SSL *s)
index 95e893737cc46e2a5bf361e520609e21aaeb068a..06e454c96b1ece580bcc9f1872f2405ef6f98a80 100644 (file)
@@ -1936,6 +1936,44 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                s->tlsext_debug_arg=parg;
                ret = 1;
                break;
+  
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
+               s->tlsext_status_type=larg;
+               ret = 1;
+               break;
+
+       case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS:
+               *(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts;
+               ret = 1;
+               break;
+
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS:
+               s->tlsext_ocsp_exts = parg;
+               ret = 1;
+               break;
+
+       case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS:
+               *(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids;
+               ret = 1;
+               break;
+
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS:
+               s->tlsext_ocsp_ids = parg;
+               ret = 1;
+               break;
+
+       case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP:
+               *(unsigned char **)parg = s->tlsext_ocsp_resp;
+               return s->tlsext_ocsp_resplen;
+               
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP:
+               if (s->tlsext_ocsp_resp)
+                       OPENSSL_free(s->tlsext_ocsp_resp);
+               s->tlsext_ocsp_resp = parg;
+               s->tlsext_ocsp_resplen = larg;
+               ret = 1;
+               break;
+
 #endif /* !OPENSSL_NO_TLSEXT */
        default:
                break;
@@ -2156,6 +2194,12 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                        }
                return 1;
                }
+  
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
+               ctx->tlsext_status_arg=parg;
+               return 1;
+               break;
+
 #endif /* !OPENSSL_NO_TLSEXT */
        /* A Thawte special :-) */
        case SSL_CTRL_EXTRA_CHAIN_CERT:
@@ -2206,6 +2250,11 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
        case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
                ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
                break;
+  
+       case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
+               ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp;
+               break;
+
 #endif
        default:
                return(0);
index 6dba5c1977147ab9004667dd67ca935c65bd9dcf..fadb83ae611f9edb316c6785b3fc2dae6587477a 100644 (file)
@@ -306,10 +306,23 @@ int ssl3_accept(SSL *s)
                                {
                                ret=ssl3_send_server_certificate(s);
                                if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+                               if (s->tlsext_status_expected)
+                                       s->state=SSL3_ST_SW_CERT_STATUS_A;
+                               else
+                                       s->state=SSL3_ST_SW_KEY_EXCH_A;
                                }
+                       else
+                               {
+                               skip = 1;
+                               s->state=SSL3_ST_SW_KEY_EXCH_A;
+                               }
+#else
                        else
                                skip=1;
+
                        s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
                        s->init_num=0;
                        break;
 
@@ -512,6 +525,14 @@ int ssl3_accept(SSL *s)
                        s->init_num=0;
                        break;
 
+               case SSL3_ST_SW_CERT_STATUS_A:
+               case SSL3_ST_SW_CERT_STATUS_B:
+                       ret=ssl3_send_cert_status(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_SW_KEY_EXCH_A;
+                       s->init_num=0;
+                       break;
+
 #endif
 
                case SSL3_ST_SW_CHANGE_A:
@@ -2740,4 +2761,39 @@ int ssl3_send_newsession_ticket(SSL *s)
        /* SSL3_ST_SW_SESSION_TICKET_B */
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
+
+int ssl3_send_cert_status(SSL *s)
+       {
+       if (s->state == SSL3_ST_SW_CERT_STATUS_A)
+               {
+               unsigned char *p;
+               /* Grow buffer if need be: the length calculation is as
+                * follows 1 (message type) + 3 (message length) +
+                * 1 (ocsp response type) + 3 (ocsp response length)
+                * + (ocsp response)
+                */
+               if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen))
+                       return -1;
+
+               p=(unsigned char *)s->init_buf->data;
+
+               /* do the header */
+               *(p++)=SSL3_MT_CERTIFICATE_STATUS;
+               /* message length */
+               l2n3(s->tlsext_ocsp_resplen + 4, p);
+               /* status type */
+               *(p++)= s->tlsext_status_type;
+               /* length of OCSP response */
+               l2n3(s->tlsext_ocsp_resplen, p);
+               /* actual response */
+               memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+               /* number of bytes to write */
+               s->init_num = 8 + s->tlsext_ocsp_resplen;
+               s->state=SSL3_ST_SW_CERT_STATUS_B;
+               s->init_off = 0;
+               }
+
+       /* SSL3_ST_SW_CERT_STATUS_B */
+       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       }
 #endif
index 52caf88b169c04a63595f39434b06ed1f07e8299..10f6d81c2a35b828dfc17e0c80090ba40cc96159 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -767,6 +767,11 @@ struct ssl_ctx_st
        unsigned char tlsext_tick_key_name[16];
        unsigned char tlsext_tick_hmac_key[16];
        unsigned char tlsext_tick_aes_key[16];
+  
+       /* certificate status request info */
+       /* Callback for status request */
+       int (*tlsext_status_cb)(SSL *ssl, void *arg);
+       void *tlsext_status_arg;
 #endif
 
        };
@@ -1003,6 +1008,18 @@ struct ssl_st
                                  1 : prepare 2, allow last ack just after in server callback.
                                  2 : don't call servername callback, no ack in server hello
                               */
+       /* certificate status request info */
+       /* Status type or -1 if no status type */
+       int tlsext_status_type;
+       /* Expect OCSP CertificateStatus message */
+       int tlsext_status_expected;
+       /* OCSP status request only */
+       STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
+       X509_EXTENSIONS *tlsext_ocsp_exts;
+       /* OCSP response received or to be sent */
+       unsigned char *tlsext_ocsp_resp;
+       int tlsext_ocsp_resplen;
+
        /* RFC4507 session ticket expected to be received or sent */
        int tlsext_ticket_expected;
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
@@ -1158,6 +1175,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
 #define SSL_AD_UNSUPPORTED_EXTENSION   TLS1_AD_UNSUPPORTED_EXTENSION
 #define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
 #define SSL_AD_UNRECOGNIZED_NAME       TLS1_AD_UNRECOGNIZED_NAME
+#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
 
 #define SSL_ERROR_NONE                 0
 #define SSL_ERROR_SSL                  1
@@ -1225,6 +1243,16 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
 #define SSL_CTRL_SET_TLSEXT_DEBUG_ARG          57
 #define SSL_CTRL_GET_TLSEXT_TICKET_KEYS                58
 #define SSL_CTRL_SET_TLSEXT_TICKET_KEYS                59
+
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB      63
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG  64
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE    65
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS    66
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS    67
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS     68
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS     69
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP       70
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP       71
 #endif
 
 #define SSL_session_reused(ssl) \
@@ -1670,6 +1698,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL3_ENC                                  134
 #define SSL_F_SSL3_GENERATE_KEY_BLOCK                   238
 #define SSL_F_SSL3_GET_CERTIFICATE_REQUEST              135
+#define SSL_F_SSL3_GET_CERT_STATUS                      288
 #define SSL_F_SSL3_GET_CERT_VERIFY                      136
 #define SSL_F_SSL3_GET_CLIENT_CERTIFICATE               137
 #define SSL_F_SSL3_GET_CLIENT_HELLO                     138
@@ -1854,6 +1883,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_INVALID_CHALLENGE_LENGTH                  158
 #define SSL_R_INVALID_COMMAND                           280
 #define SSL_R_INVALID_PURPOSE                           278
+#define SSL_R_INVALID_STATUS_RESPONSE                   316
 #define SSL_R_INVALID_TICKET_KEYS_LENGTH                275
 #define SSL_R_INVALID_TRUST                             279
 #define SSL_R_KEY_ARG_TOO_LONG                          284
@@ -2010,6 +2040,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE                315
 #define SSL_R_UNSUPPORTED_PROTOCOL                      258
 #define SSL_R_UNSUPPORTED_SSL_VERSION                   259
+#define SSL_R_UNSUPPORTED_STATUS_TYPE                   329
 #define SSL_R_WRITE_BIO_NOT_SET                                 260
 #define SSL_R_WRONG_CIPHER_RETURNED                     261
 #define SSL_R_WRONG_MESSAGE_TYPE                        262
index f484df3f65dbd74d592b656bcf4a9015ffac533c..4b1e2e9834775497d922ab72a7bfc94799398a8d 100644 (file)
@@ -483,6 +483,8 @@ typedef struct ssl3_state_st
 #define SSL3_ST_CR_FINISHED_B          (0x1D1|SSL_ST_CONNECT)
 #define SSL3_ST_CR_SESSION_TICKET_A    (0x1E0|SSL_ST_CONNECT)
 #define SSL3_ST_CR_SESSION_TICKET_B    (0x1E1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_A       (0x1F0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_B       (0x1F1|SSL_ST_CONNECT)
 
 /* server */
 /* extra state */
@@ -526,6 +528,8 @@ typedef struct ssl3_state_st
 #define SSL3_ST_SW_FINISHED_B          (0x1E1|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_SESSION_TICKET_A    (0x1F0|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_SESSION_TICKET_B    (0x1F1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_A       (0x200|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_B       (0x201|SSL_ST_ACCEPT)
 
 #define SSL3_MT_HELLO_REQUEST                  0
 #define SSL3_MT_CLIENT_HELLO                   1
@@ -538,6 +542,7 @@ typedef struct ssl3_state_st
 #define SSL3_MT_CERTIFICATE_VERIFY             15
 #define SSL3_MT_CLIENT_KEY_EXCHANGE            16
 #define SSL3_MT_FINISHED                       20
+#define SSL3_MT_CERTIFICATE_STATUS             22
 #define DTLS1_MT_HELLO_VERIFY_REQUEST    3
 
 
index 62f06d5f1050ee5029648fa9b7445e84a21b7ddb..50779c16325b9ce64be20441371b44963825111b 100644 (file)
@@ -141,6 +141,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL3_ENC),     "SSL3_ENC"},
 {ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK),      "SSL3_GENERATE_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), "SSL3_GET_CERTIFICATE_REQUEST"},
+{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"},
 {ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "SSL3_GET_CERT_VERIFY"},
 {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE),  "SSL3_GET_CLIENT_CERTIFICATE"},
 {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO),        "SSL3_GET_CLIENT_HELLO"},
@@ -328,6 +329,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"},
 {ERR_REASON(SSL_R_INVALID_COMMAND)       ,"invalid command"},
 {ERR_REASON(SSL_R_INVALID_PURPOSE)       ,"invalid purpose"},
+{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE),"invalid status response"},
 {ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
 {ERR_REASON(SSL_R_INVALID_TRUST)         ,"invalid trust"},
 {ERR_REASON(SSL_R_KEY_ARG_TOO_LONG)      ,"key arg too long"},
@@ -484,6 +486,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"},
 {ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL)  ,"unsupported protocol"},
 {ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
+{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"},
 {ERR_REASON(SSL_R_WRITE_BIO_NOT_SET)     ,"write bio not set"},
 {ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
 {ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE)    ,"wrong message type"},
index 73707aab9b54d230de00392f13495826465b2230..065411aea8d792e0c76c9c7002c8069e4d35dcbb 100644 (file)
 #include <openssl/lhash.h>
 #include <openssl/x509v3.h>
 #include <openssl/rand.h>
+#include <openssl/ocsp.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
@@ -311,6 +312,12 @@ SSL *SSL_new(SSL_CTX *ctx)
        s->tlsext_debug_cb = 0;
        s->tlsext_debug_arg = NULL;
        s->tlsext_ticket_expected = 0;
+       s->tlsext_status_type = -1;
+       s->tlsext_status_expected = 0;
+       s->tlsext_ocsp_ids = NULL;
+       s->tlsext_ocsp_exts = NULL;
+       s->tlsext_ocsp_resp = NULL;
+       s->tlsext_ocsp_resplen = -1;
        CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
        s->initial_ctx=ctx;
 #endif
@@ -501,6 +508,13 @@ void SSL_free(SSL *s)
        if (s->ctx) SSL_CTX_free(s->ctx);
 #ifndef OPENSSL_NO_TLSEXT
        if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
+       if (s->tlsext_ocsp_exts)
+               sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+                                               X509_EXTENSION_free);
+       if (s->tlsext_ocsp_ids)
+               sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+       if (s->tlsext_ocsp_resp)
+               OPENSSL_free(s->tlsext_ocsp_resp);
 #endif
        if (s->client_CA != NULL)
                sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
@@ -1494,6 +1508,9 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
                || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
                ret->options |= SSL_OP_NO_TICKET;
 
+       ret->tlsext_status_cb = 0;
+       ret->tlsext_status_arg = NULL;
+
 #endif
 
        return(ret);
index e9fba49c53d61ac27637cd9d4f80f0b86505fe65..de94c0d0c74a818dc85973823792a3ced224a1d7 100644 (file)
@@ -777,6 +777,7 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
 void ssl3_init_finished_mac(SSL *s);
 int ssl3_send_server_certificate(SSL *s);
 int ssl3_send_newsession_ticket(SSL *s);
+int ssl3_send_cert_status(SSL *s);
 int ssl3_get_finished(SSL *s,int state_a,int state_b);
 int ssl3_setup_key_block(SSL *s);
 int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
@@ -870,6 +871,7 @@ int ssl3_client_hello(SSL *s);
 int ssl3_get_server_hello(SSL *s);
 int ssl3_get_certificate_request(SSL *s);
 int ssl3_get_new_session_ticket(SSL *s);
+int ssl3_get_cert_status(SSL *s);
 int ssl3_get_server_done(SSL *s);
 int ssl3_send_client_verify(SSL *s);
 int ssl3_send_client_certificate(SSL *s);
index fabc634d688889a84a91ec77cb8e8a171018a28b..1bd67b40b16989fa69f28e3d5652c78280d7469b 100644 (file)
@@ -60,6 +60,7 @@
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
+#include <openssl/ocsp.h>
 #include "ssl_locl.h"
 
 const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
@@ -190,6 +191,54 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        }
                }
 
+       if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+               {
+               int i;
+               long extlen, idlen, itmp;
+               OCSP_RESPID *id;
+
+               idlen = 0;
+               for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+                       {
+                       id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+                       itmp = i2d_OCSP_RESPID(id, NULL);
+                       if (itmp <= 0)
+                               return NULL;
+                       idlen += itmp + 2;
+                       }
+
+               if (s->tlsext_ocsp_exts)
+                       {
+                       extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+                       if (extlen < 0)
+                               return NULL;
+                       }
+               else
+                       extlen = 0;
+                       
+               if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
+               s2n(TLSEXT_TYPE_status_request, ret);
+               if (extlen + idlen > 0xFFF0)
+                       return NULL;
+               s2n(extlen + idlen + 5, ret);
+               *(ret++) = TLSEXT_STATUSTYPE_ocsp;
+               s2n(idlen, ret);
+               for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+                       {
+                       /* save position of id len */
+                       unsigned char *q = ret;
+                       id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+                       /* skip over id len */
+                       ret += 2;
+                       itmp = i2d_OCSP_RESPID(id, &ret);
+                       /* write id len */
+                       s2n(itmp, q);
+                       }
+               s2n(extlen, ret);
+               if (extlen > 0)
+                       i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+               }
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -220,7 +269,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                s2n(TLSEXT_TYPE_session_ticket,ret);
                s2n(0,ret);
                }
-               
+
+       if (s->tlsext_status_expected)
+               { 
+               if ((long)(limit - ret - 4) < 0) return NULL; 
+               s2n(TLSEXT_TYPE_status_request,ret);
+               s2n(0,ret);
+               }
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -235,6 +291,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned short len;
        unsigned char *data = *p;
        s->servername_done = 0;
+       s->tlsext_status_type = -1;
 
        if (data >= (d+n-2))
                return 1;
@@ -349,6 +406,106 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
 
                        }
+               else if (type == TLSEXT_TYPE_status_request
+                                               && s->ctx->tlsext_status_cb)
+                       {
+               
+                       if (size < 5) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       s->tlsext_status_type = *data++;
+                       size--;
+                       if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+                               {
+                               const unsigned char *sdata;
+                               int dsize;
+                               /* Read in responder_id_list */
+                               n2s(data,dsize);
+                               size -= 2;
+                               if (dsize > size  ) 
+                                       {
+                                       *al = SSL_AD_DECODE_ERROR;
+                                       return 0;
+                                       }
+                               while (dsize > 0)
+                                       {
+                                       OCSP_RESPID *id;
+                                       int idsize;
+                                       if (dsize < 4)
+                                               {
+                                               *al = SSL_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       n2s(data, idsize);
+                                       dsize -= 2 + idsize;
+                                       if (dsize < 0)
+                                               {
+                                               *al = SSL_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       sdata = data;
+                                       data += idsize;
+                                       id = d2i_OCSP_RESPID(NULL,
+                                                               &sdata, idsize);
+                                       if (!id)
+                                               {
+                                               *al = SSL_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       if (data != sdata)
+                                               {
+                                               OCSP_RESPID_free(id);
+                                               *al = SSL_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       if (!s->tlsext_ocsp_ids
+                                               && !(s->tlsext_ocsp_ids =
+                                               sk_OCSP_RESPID_new_null()))
+                                               {
+                                               OCSP_RESPID_free(id);
+                                               *al = SSL_AD_INTERNAL_ERROR;
+                                               return 0;
+                                               }
+                                       if (!sk_OCSP_RESPID_push(
+                                                       s->tlsext_ocsp_ids, id))
+                                               {
+                                               OCSP_RESPID_free(id);
+                                               *al = SSL_AD_INTERNAL_ERROR;
+                                               return 0;
+                                               }
+                                       }
+
+                               /* Read in request_extensions */
+                               n2s(data,dsize);
+                               size -= 2;
+                               if (dsize > size) 
+                                       {
+                                       *al = SSL_AD_DECODE_ERROR;
+                                       return 0;
+                                       }
+                               sdata = data;
+                               if (dsize > 0)
+                                       {
+                                       s->tlsext_ocsp_exts =
+                                               d2i_X509_EXTENSIONS(NULL,
+                                                       &sdata, dsize);
+                                       if (!s->tlsext_ocsp_exts
+                                               || (data + dsize != sdata))
+                                               {
+                                               *al = SSL_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       }
+                               }
+                               /* We don't know what to do with any other type
+                               * so ignore it.
+                               */
+                               else
+                                       s->tlsext_status_type = -1;
+                       }
                /* session ticket processed earlier */
 
                data+=size;             
@@ -403,6 +560,19 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
                        s->tlsext_ticket_expected = 1;
                        }
+               else if (type == TLSEXT_TYPE_status_request)
+                       {
+                       /* MUST be empty and only sent if we've requested
+                        * a status request message.
+                        */ 
+                       if ((s->tlsext_status_type == -1) || (size > 0))
+                               {
+                               *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+                               return 0;
+                               }
+                       /* Set flag to expect CertificateStatus message */
+                       s->tlsext_status_expected = 1;
+                       }
 
                data+=size;             
                }
@@ -448,6 +618,37 @@ int ssl_check_clienthello_tlsext(SSL *s)
        else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
                ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
 
+       /* If status request then ask callback what to do.
+        * Note: this must be called after servername callbacks in case 
+        * the certificate has changed.
+        */
+       if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb)
+               {
+               int r;
+               r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+               switch (r)
+                       {
+                       /* We don't want to send a status request response */
+                       case SSL_TLSEXT_ERR_NOACK:
+                               s->tlsext_status_expected = 0;
+                               break;
+                       /* status request response should be sent */
+                       case SSL_TLSEXT_ERR_OK:
+                               if (s->tlsext_ocsp_resp)
+                                       s->tlsext_status_expected = 1;
+                               else
+                                       s->tlsext_status_expected = 0;
+                               break;
+                       /* something bad happened */
+                       case SSL_TLSEXT_ERR_ALERT_FATAL:
+                               ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                               al = SSL_AD_INTERNAL_ERROR;
+                               goto err;
+                       }
+               }
+       else
+               s->tlsext_status_expected = 0;
+       err:
        switch (ret)
                {
                case SSL_TLSEXT_ERR_ALERT_FATAL:
@@ -475,6 +676,35 @@ int ssl_check_serverhello_tlsext(SSL *s)
        else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
                ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
 
+       /* If we've requested certificate status and we wont get one
+        * tell the callback
+        */
+       if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+                       && s->ctx->tlsext_status_cb)
+               {
+               int r;
+               /* Set resp to NULL, resplen to -1 so callback knows
+                * there is no response.
+                */
+               if (s->tlsext_ocsp_resp)
+                       {
+                       OPENSSL_free(s->tlsext_ocsp_resp);
+                       s->tlsext_ocsp_resp = NULL;
+                       }
+               s->tlsext_ocsp_resplen = -1;
+               r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+               if (r == 0)
+                       {
+                       al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                       }
+               if (r < 0)
+                       {
+                       al = SSL_AD_INTERNAL_ERROR;
+                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                       }
+               }
+
        switch (ret)
                {
                case SSL_TLSEXT_ERR_ALERT_FATAL:
index 00399f988658edf5a902ddbe179a1f16d4fcf59d..7c3b6a8a85e64b334ad2c9e9e449589d0c8b578a 100644 (file)
@@ -117,6 +117,8 @@ extern "C" {
 
 /* NameType value from RFC 3546 */
 #define TLSEXT_NAMETYPE_host_name 0
+/* status request value from RFC 3546 */
+#define TLSEXT_STATUSTYPE_ocsp 1
 
 #ifndef OPENSSL_NO_TLSEXT
 
@@ -134,12 +136,33 @@ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
 #define SSL_set_tlsext_debug_arg(ssl, arg) \
 SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
 
+#define SSL_set_tlsext_status_type(ssl, type) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL)
+
+#define SSL_get_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg)
+
 #define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
 SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
 
-#define SSL_TLSEXT_ERR_OK 0    
-#define SSL_TLSEXT_ERR_ALERT_WARNING 1  
-#define SSL_TLSEXT_ERR_ALERT_FATAL 2 
+#define SSL_TLSEXT_ERR_OK 0
+#define SSL_TLSEXT_ERR_ALERT_WARNING 1
+#define SSL_TLSEXT_ERR_ALERT_FATAL 2
 #define SSL_TLSEXT_ERR_NOACK 3
 
 #define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
@@ -149,6 +172,13 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
        SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
 #define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
        SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
+
+#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \
+SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb)
+
+#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \
+SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg)
+
 #endif
 
 /* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt
index f6519a516e8d7be61e57cec144b8d440f8c23762..5f3d6b589c3071deeb8cc7a2dea57a17a06827ec 100755 (executable)
@@ -3521,3 +3521,11 @@ SEED_ecb_encrypt                        3915     EXIST::FUNCTION:SEED
 EVP_seed_ecb                            3916   EXIST::FUNCTION:SEED
 SEED_set_key                            3917   EXIST::FUNCTION:SEED
 EVP_seed_cfb128                         3918   EXIST::FUNCTION:SEED
+X509_EXTENSIONS_it                      3919   EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+X509_EXTENSIONS_it                      3919   EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+X509_get1_ocsp                          3920   EXIST::FUNCTION:
+OCSP_REQ_CTX_free                       3921   EXIST::FUNCTION:
+i2d_X509_EXTENSIONS                     3922   EXIST::FUNCTION:
+OCSP_sendreq_nbio                       3923   EXIST::FUNCTION:
+OCSP_sendreq_new                        3924   EXIST::FUNCTION:
+d2i_X509_EXTENSIONS                     3925   EXIST::FUNCTION: