Document "openssl s_server" -crl_check* options
[openssl.git] / apps / s_server.c
index 72d0b6cd4b7b038b88a68e04cc5576d99535e17e..a7a728c268978df397fadf0a46186ba472c39a4b 100644 (file)
@@ -179,6 +179,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
@@ -193,6 +194,10 @@ typedef unsigned int u_int;
 #undef FIONBIO
 #endif
 
+#if defined(OPENSSL_SYS_BEOS_R5)
+#include <fcntl.h>
+#endif
+
 #ifndef OPENSSL_NO_RSA
 static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength);
 #endif
@@ -254,7 +259,7 @@ static int accept_socket= -1;
 #undef PROG
 #define PROG           s_server_main
 
-extern int verify_depth;
+extern int verify_depth, verify_return_error;
 
 static char *cipher=NULL;
 static int s_server_verify=SSL_VERIFY_NONE;
@@ -277,6 +282,11 @@ static int www=0;
 
 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;
 
@@ -310,7 +320,7 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity,
                }
        if (s_debug)
                BIO_printf(bio_s_out,"identity_len=%d identity=%s\n",
-                       identity ? strlen(identity) : 0, identity);
+                       identity ? (int)strlen(identity) : 0, identity);
 
        /* here we could lookup the given identity e.g. from a database */
        if (strcmp(identity, psk_identity) != 0)
@@ -398,6 +408,11 @@ static void sv_usage(void)
        BIO_printf(bio_err," -Verify arg   - turn on peer certificate verification, must have a cert.\n");
        BIO_printf(bio_err," -cert arg     - certificate file to use\n");
        BIO_printf(bio_err,"                 (default is %s)\n",TEST_CERT);
+       BIO_printf(bio_err," -crl_check    - check the peer certificate has not been revoked by its CA.\n" \
+                          "                 The CRL(s) are appended to the certificate file\n");
+       BIO_printf(bio_err," -crl_check_all - check the peer certificate has not been revoked by its CA\n" \
+                          "                 or any other CRL in the CA chain. CRL(s) are appened to the\n" \
+                          "                 the certificate file.\n");
        BIO_printf(bio_err," -certform arg - certificate format (PEM or DER) PEM default\n");
        BIO_printf(bio_err," -key arg      - Private Key file to use, in cert file if\n");
        BIO_printf(bio_err,"                 not specified (default is %s)\n",TEST_CERT);
@@ -413,7 +428,7 @@ static void sv_usage(void)
 #ifndef OPENSSL_NO_ECDH
        BIO_printf(bio_err," -named_curve arg  - Elliptic curve name to use for ephemeral ECDH keys.\n" \
                           "                 Use \"openssl ecparam -list_curves\" for all names\n" \
-                          "                 (default is sect163r2).\n");
+                          "                 (default is nistp256).\n");
 #endif
 #ifdef FIONBIO
        BIO_printf(bio_err," -nbio         - Run with non-blocking IO\n");
@@ -467,6 +482,8 @@ static void sv_usage(void)
        BIO_printf(bio_err,"                 (default is %s)\n",TEST_CERT2);
        BIO_printf(bio_err," -key2 arg     - Private Key file to use for servername, in cert file if\n");
        BIO_printf(bio_err,"                 not specified (default is %s)\n",TEST_CERT2);
+       BIO_printf(bio_err," -tlsextdebug  - hex dump of all TLS extensions received\n");
+       BIO_printf(bio_err," -no_ticket    - disable use of RFC4507bis session tickets\n");
 #endif
        }
 
@@ -655,6 +672,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 **);
@@ -834,10 +997,12 @@ int MAIN(int argc, char *argv[])
                        {
                        vflags |= X509_V_FLAG_CRL_CHECK;
                        }
-               else if (strcmp(*argv,"-crl_check") == 0)
+               else if (strcmp(*argv,"-crl_check_all") == 0)
                        {
                        vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
                        }
+               else if (strcmp(*argv,"-verify_return_error") == 0)
+                       verify_return_error = 1;
                else if (strcmp(*argv,"-serverpref") == 0)
                        { off|=SSL_OP_CIPHER_SERVER_PREFERENCE; }
                else if (strcmp(*argv,"-cipher") == 0)
@@ -863,6 +1028,37 @@ int MAIN(int argc, char *argv[])
                        }
                else if (strcmp(*argv,"-debug") == 0)
                        { s_debug=1; }
+#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; }
                else if (strcmp(*argv,"-hack") == 0)
@@ -916,6 +1112,10 @@ int MAIN(int argc, char *argv[])
                        { off|=SSL_OP_NO_TLSv1; }
                else if (strcmp(*argv,"-no_comp") == 0)
                        { off|=SSL_OP_NO_COMPRESSION; }
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-no_ticket") == 0)
+                       { off|=SSL_OP_NO_TICKET; }
+#endif
 #ifndef OPENSSL_NO_SSL2
                else if (strcmp(*argv,"-ssl2") == 0)
                        { meth=SSLv2_server_method(); }
@@ -1308,10 +1508,10 @@ bad:
                else
                        {
                        BIO_printf(bio_s_out,"Using default temp ECDH parameters\n");
-                       ecdh = EC_KEY_new_by_curve_name(NID_sect163r2);
+                       ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
                        if (ecdh == NULL) 
                                {
-                               BIO_printf(bio_err, "unable to create curve (sect163r2)\n");
+                               BIO_printf(bio_err, "unable to create curve (nistp256)\n");
                                goto end;
                                }
                        }
@@ -1441,6 +1641,7 @@ bad:
                }
 
        BIO_printf(bio_s_out,"ACCEPT\n");
+       (void)BIO_flush(bio_s_out);
        if (www)
                do_server(port,socket_type,&accept_socket,www_body, context);
        else
@@ -1511,7 +1712,7 @@ static int sv_body(char *hostname, int s, unsigned char *context)
        unsigned long l;
        SSL *con=NULL;
        BIO *sbio;
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE)
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
        struct timeval tv;
 #endif
 
@@ -1534,6 +1735,19 @@ static int sv_body(char *hostname, int s, unsigned char *context)
 
        if (con == NULL) {
                con=SSL_new(ctx);
+#ifndef OPENSSL_NO_TLSEXT
+       if (s_tlsextdebug)
+               {
+               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)
                         {
@@ -1548,6 +1762,11 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                                                 strlen((char *)context));
        }
        SSL_clear(con);
+#if 0
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_set_tlsext_opaque_prf_input(con, "Test server", 11);
+#endif
+#endif
 
        if (SSL_version(con) == DTLS1_VERSION)
                {
@@ -1596,13 +1815,20 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                {
                con->debug=1;
                BIO_set_callback(SSL_get_rbio(con),bio_dump_callback);
-               BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out);
+               BIO_set_callback_arg(SSL_get_rbio(con),(char *)bio_s_out);
                }
        if (s_msg)
                {
                SSL_set_msg_callback(con, msg_cb);
                SSL_set_msg_callback_arg(con, bio_s_out);
                }
+#ifndef OPENSSL_NO_TLSEXT
+       if (s_tlsextdebug)
+               {
+               SSL_set_tlsext_debug_callback(con, tlsext_cb);
+               SSL_set_tlsext_debug_arg(con, bio_s_out);
+               }
+#endif
 
        width=s+1;
        for (;;)
@@ -1616,10 +1842,10 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                if (!read_from_sslcon)
                        {
                        FD_ZERO(&readfds);
-#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE)
-                       FD_SET(fileno(stdin),&readfds);
+#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined(OPENSSL_SYS_BEOS_R5)
+                       openssl_fdset(fileno(stdin),&readfds);
 #endif
-                       FD_SET(s,&readfds);
+                       openssl_fdset(s,&readfds);
                        /* Note: under VMS with SOCKETSHR the second parameter is
                         * currently of type (int *) whereas under other systems
                         * it is (void *) if you don't have a cast it will choke
@@ -1638,6 +1864,17 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                        if((i < 0) || (!i && !_kbhit() ) )continue;
                        if(_kbhit())
                                read_from_terminal = 1;
+#elif defined(OPENSSL_SYS_BEOS_R5)
+                       /* Under BeOS-R5 the situation is similar to DOS */
+                       tv.tv_sec = 1;
+                       tv.tv_usec = 0;
+                       (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
+                       i=select(width,(void *)&readfds,NULL,NULL,&tv);
+                       if ((i < 0) || (!i && read(fileno(stdin), buf, 0) < 0))
+                               continue;
+                       if (read(fileno(stdin), buf, 0) >= 0)
+                               read_from_terminal = 1;
+                       (void)fcntl(fileno(stdin), F_SETFL, 0);
 #else
                        i=select(width,(void *)&readfds,NULL,NULL,NULL);
                        if (i <= 0) continue;
@@ -1813,13 +2050,16 @@ again:
                        }
                }
 err:
-       BIO_printf(bio_s_out,"shutting down SSL\n");
+       if (con != NULL)
+               {
+               BIO_printf(bio_s_out,"shutting down SSL\n");
 #if 1
-       SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+               SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
 #else
-       SSL_shutdown(con);
+               SSL_shutdown(con);
 #endif
-       if (con != NULL) SSL_free(con);
+               SSL_free(con);
+               }
        BIO_printf(bio_s_out,"CONNECTION CLOSED\n");
        if (buf != NULL)
                {
@@ -1968,6 +2208,13 @@ static int www_body(char *hostname, int s, unsigned char *context)
        if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
 
        if ((con=SSL_new(ctx)) == NULL) goto err;
+#ifndef OPENSSL_NO_TLSEXT
+               if (s_tlsextdebug)
+                       {
+                       SSL_set_tlsext_debug_callback(con, tlsext_cb);
+                       SSL_set_tlsext_debug_arg(con, bio_s_out);
+                       }
+#endif
 #ifndef OPENSSL_NO_KRB5
        if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
                {
@@ -2000,7 +2247,7 @@ static int www_body(char *hostname, int s, unsigned char *context)
                {
                con->debug=1;
                BIO_set_callback(SSL_get_rbio(con),bio_dump_callback);
-               BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out);
+               BIO_set_callback_arg(SSL_get_rbio(con),(char *)bio_s_out);
                }
        if (s_msg)
                {