mirror of https://github.com/openssl/openssl.git
				
				
				
			Add support for TLS 1.3 OCSP multi-stapling for server certs
Co-authored-by: Michael Krueger Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/20945)
This commit is contained in:
		
							parent
							
								
									c108ead284
								
							
						
					
					
						commit
						b1b4b154fd
					
				
							
								
								
									
										12
									
								
								CHANGES.md
								
								
								
								
							
							
						
						
									
										12
									
								
								CHANGES.md
								
								
								
								
							|  | @ -133,6 +133,18 @@ OpenSSL 3.6 | ||||||
| 
 | 
 | ||||||
|    *Adrian Stanciu* |    *Adrian Stanciu* | ||||||
| 
 | 
 | ||||||
|  |  * Added support for TLS 1.3 OCSP multi-stapling for server certs. | ||||||
|  |      * new `s_client` options: | ||||||
|  |        * `-ocsp_check_leaf`: Checks the status of the leaf (server) certificate. | ||||||
|  |        * `-ocsp_check_all`: Checks the status of all certificates in the server chain. | ||||||
|  |      * new `s_server` option: | ||||||
|  |        * `-status_all` Provides OCSP status information for the entire server certificate chain (multi-stapling) for TLS 1.3 and later. | ||||||
|  | 
 | ||||||
|  |      * Improved `-status_file` option can now be given multiple times to provide | ||||||
|  |        multiple files containing OCSP responses. | ||||||
|  | 
 | ||||||
|  |    *Michael Krueger, Martin Rauch* | ||||||
|  | 
 | ||||||
| OpenSSL 3.5 | OpenSSL 3.5 | ||||||
| ----------- | ----------- | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -106,6 +106,10 @@ int verify_callback(int ok, X509_STORE_CTX *ctx) | ||||||
|         if (!verify_args.quiet) |         if (!verify_args.quiet) | ||||||
|             policies_print(ctx); |             policies_print(ctx); | ||||||
|         break; |         break; | ||||||
|  |     case X509_V_ERR_OCSP_NO_RESPONSE: | ||||||
|  |         if (!verify_args.quiet) | ||||||
|  |             BIO_printf(bio_err, "no OCSP response(s) for certificate(s) found.\n"); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|     if (err == X509_V_OK && ok == 2 && !verify_args.quiet) |     if (err == X509_V_OK && ok == 2 && !verify_args.quiet) | ||||||
|         policies_print(ctx); |         policies_print(ctx); | ||||||
|  |  | ||||||
|  | @ -110,9 +110,10 @@ static char *sess_out = NULL; | ||||||
| static SSL_SESSION *psksess = NULL; | static SSL_SESSION *psksess = NULL; | ||||||
| 
 | 
 | ||||||
| static void print_stuff(BIO *berr, SSL *con, int full); | static void print_stuff(BIO *berr, SSL *con, int full); | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
| static int ocsp_resp_cb(SSL *s, void *arg); | static int ocsp_resp_cb(SSL *s, void *arg); | ||||||
| #endif | static void print_ocsp_response(BIO *bp, OCSP_RESPONSE *rsp); | ||||||
|  | # endif | ||||||
| static int ldap_ExtendedResponse_parse(const char *buf, long rem); | static int ldap_ExtendedResponse_parse(const char *buf, long rem); | ||||||
| static int is_dNS_name(const char *host); | static int is_dNS_name(const char *host); | ||||||
| 
 | 
 | ||||||
|  | @ -483,7 +484,10 @@ typedef enum OPTION_choice { | ||||||
|     OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, |     OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, | ||||||
|     OPT_BRIEF, OPT_PREXIT, OPT_NO_INTERACTIVE, OPT_CRLF, OPT_QUIET, OPT_NBIO, |     OPT_BRIEF, OPT_PREXIT, OPT_NO_INTERACTIVE, OPT_CRLF, OPT_QUIET, OPT_NBIO, | ||||||
|     OPT_SSL_CLIENT_ENGINE, OPT_IGN_EOF, OPT_NO_IGN_EOF, |     OPT_SSL_CLIENT_ENGINE, OPT_IGN_EOF, OPT_NO_IGN_EOF, | ||||||
|     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_WDEBUG, |     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_WDEBUG, | ||||||
|  | # ifndef OPENSSL_NO_OCSP | ||||||
|  |     OPT_STATUS, OPT_STATUS_OCSP_CHECK_LEAF, OPT_STATUS_OCSP_CHECK_ALL, | ||||||
|  | # endif | ||||||
|     OPT_MSG, OPT_MSGFILE, OPT_ENGINE, OPT_TRACE, OPT_SECURITY_DEBUG, |     OPT_MSG, OPT_MSGFILE, OPT_ENGINE, OPT_TRACE, OPT_SECURITY_DEBUG, | ||||||
|     OPT_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE, |     OPT_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE, | ||||||
|     OPT_PSK_IDENTITY, OPT_PSK, OPT_PSK_SESS, |     OPT_PSK_IDENTITY, OPT_PSK, OPT_PSK_SESS, | ||||||
|  | @ -625,6 +629,17 @@ const OPTIONS s_client_options[] = { | ||||||
|     {"no-interactive", OPT_NO_INTERACTIVE, '-', |     {"no-interactive", OPT_NO_INTERACTIVE, '-', | ||||||
|      "Don't run the client in the interactive mode"}, |      "Don't run the client in the interactive mode"}, | ||||||
| 
 | 
 | ||||||
|  | # ifndef OPENSSL_NO_OCSP | ||||||
|  |     OPT_SECTION("OCSP stapling"), | ||||||
|  |     {"status", OPT_STATUS, '-', | ||||||
|  |      "Sends a certificate status request to the server (OCSP stapling) " \ | ||||||
|  |      "The server response (if any) will be printed out."}, | ||||||
|  |     {"ocsp_check_leaf", OPT_STATUS_OCSP_CHECK_LEAF, '-', | ||||||
|  |      "Require checking leaf certificate status, attempting to use OCSP stapling first"}, | ||||||
|  |     {"ocsp_check_all", OPT_STATUS_OCSP_CHECK_ALL, '-', | ||||||
|  |      "Require checking status of full chain, attempting to use OCSP stapling first"}, | ||||||
|  | # endif | ||||||
|  | 
 | ||||||
|     OPT_SECTION("Debug"), |     OPT_SECTION("Debug"), | ||||||
|     {"showcerts", OPT_SHOWCERTS, '-', |     {"showcerts", OPT_SHOWCERTS, '-', | ||||||
|      "Show all certificates sent by the server"}, |      "Show all certificates sent by the server"}, | ||||||
|  | @ -659,9 +674,6 @@ const OPTIONS s_client_options[] = { | ||||||
|      "Hex dump of all TLS extensions received"}, |      "Hex dump of all TLS extensions received"}, | ||||||
|     {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-', |     {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-', | ||||||
|      "Do not treat lack of close_notify from a peer as an error"}, |      "Do not treat lack of close_notify from a peer as an error"}, | ||||||
| #ifndef OPENSSL_NO_OCSP |  | ||||||
|     {"status", OPT_STATUS, '-', "Request certificate status from server"}, |  | ||||||
| #endif |  | ||||||
|     {"serverinfo", OPT_SERVERINFO, 's', |     {"serverinfo", OPT_SERVERINFO, 's', | ||||||
|      "types  Send empty ClientHello extensions (comma-separated numbers)"}, |      "types  Send empty ClientHello extensions (comma-separated numbers)"}, | ||||||
|     {"alpn", OPT_ALPN, 's', |     {"alpn", OPT_ALPN, 's', | ||||||
|  | @ -1195,11 +1207,23 @@ int s_client_main(int argc, char **argv) | ||||||
|         case OPT_TLSEXTDEBUG: |         case OPT_TLSEXTDEBUG: | ||||||
|             c_tlsextdebug = 1; |             c_tlsextdebug = 1; | ||||||
|             break; |             break; | ||||||
|  | # ifndef OPENSSL_NO_OCSP | ||||||
|         case OPT_STATUS: |         case OPT_STATUS: | ||||||
| #ifndef OPENSSL_NO_OCSP |  | ||||||
|             c_status_req = 1; |             c_status_req = 1; | ||||||
| #endif |  | ||||||
|             break; |             break; | ||||||
|  |         case OPT_STATUS_OCSP_CHECK_LEAF: | ||||||
|  |             c_status_req = 1; | ||||||
|  |             X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_OCSP_RESP_CHECK); | ||||||
|  |             vpmtouched++; | ||||||
|  |             break; | ||||||
|  |         case OPT_STATUS_OCSP_CHECK_ALL: | ||||||
|  |             c_status_req = 1; | ||||||
|  |             X509_VERIFY_PARAM_set_flags(vpm, | ||||||
|  |                                         X509_V_FLAG_OCSP_RESP_CHECK | | ||||||
|  |                                         X509_V_FLAG_OCSP_RESP_CHECK_ALL); | ||||||
|  |             vpmtouched++; | ||||||
|  |             break; | ||||||
|  | # endif | ||||||
|         case OPT_WDEBUG: |         case OPT_WDEBUG: | ||||||
| #ifdef WATT32 | #ifdef WATT32 | ||||||
|             dbug_init(); |             dbug_init(); | ||||||
|  | @ -3626,27 +3650,58 @@ static void print_stuff(BIO *bio, SSL *s, int full) | ||||||
| # ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
| static int ocsp_resp_cb(SSL *s, void *arg) | static int ocsp_resp_cb(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     const unsigned char *p; |     int num, i; | ||||||
|     int len; |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|     OCSP_RESPONSE *rsp; |     OCSP_RESPONSE *rsp; | ||||||
|     len = SSL_get_tlsext_status_ocsp_resp(s, &p); | 
 | ||||||
|  |     if (SSL_version(s) >= TLS1_3_VERSION) { | ||||||
|  |         (void)SSL_get0_tlsext_status_ocsp_resp_ex(s, &sk_resp); | ||||||
|  | 
 | ||||||
|  |         BIO_puts(arg, "OCSP responses: "); | ||||||
|  | 
 | ||||||
|  |         if (sk_resp == NULL) { | ||||||
|  |             BIO_puts(arg, "no responses sent\n"); | ||||||
|  |             return 1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         num = sk_OCSP_RESPONSE_num(sk_resp); | ||||||
|  | 
 | ||||||
|  |         BIO_printf(arg, "number of responses: %d", num); | ||||||
|  |         for (i = 0; i < num; i++) | ||||||
|  |             print_ocsp_response(arg, sk_OCSP_RESPONSE_value(sk_resp, i)); | ||||||
|  |     } else { | ||||||
|  |         const unsigned char *p; | ||||||
|  |         int len = SSL_get_tlsext_status_ocsp_resp(s, &p); | ||||||
|  | 
 | ||||||
|         BIO_puts(arg, "OCSP response: "); |         BIO_puts(arg, "OCSP response: "); | ||||||
|         if (p == NULL) { |         if (p == NULL) { | ||||||
|         BIO_puts(arg, "no response sent\n"); |             BIO_puts(arg, "no OCSP response received\n"); | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|         rsp = d2i_OCSP_RESPONSE(NULL, &p, len); |         rsp = d2i_OCSP_RESPONSE(NULL, &p, len); | ||||||
|         if (rsp == NULL) { |         if (rsp == NULL) { | ||||||
|         BIO_puts(arg, "response parse error\n"); |             BIO_puts(arg, "OCSP response parse error\n"); | ||||||
|             BIO_dump_indent(arg, (char *)p, len, 4); |             BIO_dump_indent(arg, (char *)p, len, 4); | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|     BIO_puts(arg, "\n======================================\n"); |         print_ocsp_response(arg, rsp); | ||||||
|     OCSP_RESPONSE_print(arg, rsp, 0); |  | ||||||
|     BIO_puts(arg, "======================================\n"); |  | ||||||
|         OCSP_RESPONSE_free(rsp); |         OCSP_RESPONSE_free(rsp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static void print_ocsp_response(BIO *bp, OCSP_RESPONSE *rsp) | ||||||
|  | { | ||||||
|  |     if (rsp == NULL) { | ||||||
|  |         BIO_puts(bp, "no OCSP response to print\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BIO_puts(bp, "\n======================================\n"); | ||||||
|  |     OCSP_RESPONSE_print(bp, rsp, 0); | ||||||
|  |     BIO_puts(bp, "\n======================================\n"); | ||||||
|  | } | ||||||
| # endif | # endif | ||||||
| 
 | 
 | ||||||
| static int ldap_ExtendedResponse_parse(const char *buf, long rem) | static int ldap_ExtendedResponse_parse(const char *buf, long rem) | ||||||
|  |  | ||||||
							
								
								
									
										336
									
								
								apps/s_server.c
								
								
								
								
							
							
						
						
									
										336
									
								
								apps/s_server.c
								
								
								
								
							|  | @ -54,9 +54,10 @@ typedef unsigned int u_int; | ||||||
| #include "s_apps.h" | #include "s_apps.h" | ||||||
| #include "timeouts.h" | #include "timeouts.h" | ||||||
| #ifdef CHARSET_EBCDIC | #ifdef CHARSET_EBCDIC | ||||||
| #include <openssl/ebcdic.h> | # include <openssl/ebcdic.h> | ||||||
| #endif | #endif | ||||||
| #include "internal/sockets.h" | #include "internal/sockets.h" | ||||||
|  | #include "internal/statem.h" | ||||||
| 
 | 
 | ||||||
| static int not_resumable_sess_cb(SSL *s, int is_forward_secure); | static int not_resumable_sess_cb(SSL *s, int is_forward_secure); | ||||||
| static int sv_body(int s, int stype, int prot, unsigned char *context); | static int sv_body(int s, int stype, int prot, unsigned char *context); | ||||||
|  | @ -454,16 +455,20 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) | ||||||
| /* Structure passed to cert status callback */ | /* Structure passed to cert status callback */ | ||||||
| typedef struct tlsextstatusctx_st { | typedef struct tlsextstatusctx_st { | ||||||
|     int timeout; |     int timeout; | ||||||
|     /* File to load OCSP Response from (or NULL if no file) */ |     /*
 | ||||||
|     char *respin; |      * List of filenames, from which we are loading each OCSP Response to | ||||||
|  |      * staple during handshake (or NULL if no file) | ||||||
|  |      */ | ||||||
|  |     STACK_OF(OPENSSL_STRING) *sk_resp_in; | ||||||
|     /* Default responder to use */ |     /* Default responder to use */ | ||||||
|     char *host, *path, *port; |     char *host, *path, *port; | ||||||
|     char *proxy, *no_proxy; |     char *proxy, *no_proxy; | ||||||
|     int use_ssl; |     int use_ssl; | ||||||
|     int verbose; |     int verbose; | ||||||
|  |     int status_all; | ||||||
| } tlsextstatusctx; | } tlsextstatusctx; | ||||||
| 
 | 
 | ||||||
| static tlsextstatusctx tlscstatp = { -1 }; | static tlsextstatusctx tlscstatp = { -1, NULL }; | ||||||
| 
 | 
 | ||||||
| #ifndef OPENSSL_NO_OCSP | #ifndef OPENSSL_NO_OCSP | ||||||
| 
 | 
 | ||||||
|  | @ -474,14 +479,15 @@ static tlsextstatusctx tlscstatp = { -1 }; | ||||||
|  * the OCSP certificate IDs and minimise the number of OCSP responses by caching |  * the OCSP certificate IDs and minimise the number of OCSP responses by caching | ||||||
|  * them until they were considered "expired". |  * them until they were considered "expired". | ||||||
|  */ |  */ | ||||||
| static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | static int get_ocsp_resp_from_responder_single(SSL *s, X509 *x, | ||||||
|  |                                                tlsextstatusctx *srctx, | ||||||
|                                                OCSP_RESPONSE **resp) |                                                OCSP_RESPONSE **resp) | ||||||
| { | { | ||||||
|     char *host = NULL, *port = NULL, *path = NULL; |     char *host = NULL, *port = NULL, *path = NULL; | ||||||
|     char *proxy = NULL, *no_proxy = NULL; |     char *proxy = NULL, *no_proxy = NULL; | ||||||
|     int use_ssl; |     int use_ssl; | ||||||
|     STACK_OF(OPENSSL_STRING) *aia = NULL; |     STACK_OF(OPENSSL_STRING) *aia = NULL; | ||||||
|     X509 *x = NULL, *cert; |     X509 *cert; | ||||||
|     X509_NAME *iname; |     X509_NAME *iname; | ||||||
|     STACK_OF(X509) *chain = NULL; |     STACK_OF(X509) *chain = NULL; | ||||||
|     SSL_CTX *ssl_ctx; |     SSL_CTX *ssl_ctx; | ||||||
|  | @ -494,7 +500,6 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | ||||||
|     int i; |     int i; | ||||||
| 
 | 
 | ||||||
|     /* Build up OCSP query from server certificate */ |     /* Build up OCSP query from server certificate */ | ||||||
|     x = SSL_get_certificate(s); |  | ||||||
|     iname = X509_get_issuer_name(x); |     iname = X509_get_issuer_name(x); | ||||||
|     aia = X509_get1_ocsp(x); |     aia = X509_get1_ocsp(x); | ||||||
|     if (aia != NULL) { |     if (aia != NULL) { | ||||||
|  | @ -559,6 +564,7 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | ||||||
|     SSL_get_tlsext_status_exts(s, &exts); |     SSL_get_tlsext_status_exts(s, &exts); | ||||||
|     for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { |     for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { | ||||||
|         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); |         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); | ||||||
|  | 
 | ||||||
|         if (!OCSP_REQUEST_add_ext(req, ext, -1)) |         if (!OCSP_REQUEST_add_ext(req, ext, -1)) | ||||||
|             goto err; |             goto err; | ||||||
|     } |     } | ||||||
|  | @ -591,6 +597,212 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int bring_ocsp_resp_in_correct_order(SSL *s, tlsextstatusctx *srctx, | ||||||
|  |                                             STACK_OF(OCSP_RESPONSE) *sk_resp_unordered, | ||||||
|  |                                             STACK_OF(OCSP_RESPONSE) **sk_resp) | ||||||
|  | { | ||||||
|  |     STACK_OF(X509) *server_certs = NULL; | ||||||
|  |     X509 *ssl_cert = NULL; | ||||||
|  |     X509 *issuer = NULL; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     OCSP_BASICRESP *bs = NULL; | ||||||
|  |     OCSP_CERTID *cert_id = NULL; | ||||||
|  |     int found = -1; | ||||||
|  |     int i, j, num = 1; | ||||||
|  | 
 | ||||||
|  |     if (*sk_resp != NULL) | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(*sk_resp, OCSP_RESPONSE_free); | ||||||
|  | 
 | ||||||
|  |     SSL_get0_chain_certs(s, &server_certs); | ||||||
|  |     /*
 | ||||||
|  |      * TODO(DTLS-1.3): in future DTLS should also be considered | ||||||
|  |      */ | ||||||
|  |     if (server_certs != NULL && srctx->status_all && | ||||||
|  |         !SSL_is_dtls(s) && SSL_version(s) >= TLS1_3_VERSION) { | ||||||
|  |         /* certificate chain is available */ | ||||||
|  |         num = sk_X509_num(server_certs) + 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* get OCSP response for server certificate first */ | ||||||
|  |     ssl_cert = SSL_get_certificate(s); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * OpenSSL servers with TLS < 1.3 can be configured with no certificate | ||||||
|  |      */ | ||||||
|  |     if (ssl_cert == NULL) | ||||||
|  |         return SSL_TLSEXT_ERR_OK; | ||||||
|  | 
 | ||||||
|  |     /* reserve enough space so the pushes to the stack would not fail */ | ||||||
|  |     *sk_resp = sk_OCSP_RESPONSE_new_reserve(NULL, num); | ||||||
|  | 
 | ||||||
|  |     if (sk_resp == NULL) | ||||||
|  |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         if (i != 0) /* for each certificate in chain (except root) get the OCSP response */ | ||||||
|  |             ssl_cert = sk_X509_value(server_certs, i - 1); | ||||||
|  | 
 | ||||||
|  |         /* issuer certificate is next in chain */ | ||||||
|  |         issuer = sk_X509_value(server_certs, i); | ||||||
|  | 
 | ||||||
|  |         if (issuer == NULL | ||||||
|  |             || (cert_id = OCSP_cert_to_id(NULL, ssl_cert, issuer)) == NULL) { | ||||||
|  |             sk_OCSP_RESPONSE_push(*sk_resp, NULL); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* find the correct OCSP response for the requested certificate */ | ||||||
|  |         found = -1; | ||||||
|  |         for (j = 0; j < sk_OCSP_RESPONSE_num(sk_resp_unordered); j++) { | ||||||
|  |             if ((resp = sk_OCSP_RESPONSE_value(sk_resp_unordered, j)) == NULL) | ||||||
|  |                 continue; | ||||||
|  |             if ((bs = OCSP_response_get1_basic(resp)) == NULL) | ||||||
|  |                 continue; | ||||||
|  |             found = OCSP_resp_find(bs, cert_id, -1); | ||||||
|  |             OCSP_BASICRESP_free(bs); | ||||||
|  |             if (found > -1) { | ||||||
|  |                 /* remove the found OCSP response to prevent freeing it with the remaining list */ | ||||||
|  |                 sk_OCSP_RESPONSE_delete(sk_resp_unordered, j); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (found < 0) | ||||||
|  |             resp = NULL; | ||||||
|  | 
 | ||||||
|  |         OCSP_CERTID_free(cert_id); | ||||||
|  | 
 | ||||||
|  |         /* add response to stack; also insert null response */ | ||||||
|  |         (void)sk_OCSP_RESPONSE_push(*sk_resp, resp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return SSL_TLSEXT_ERR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Helper function to get a list OCSP_RESPONSE from the files specified using | ||||||
|  |  * -status_file options for the server certificate and the chain certificates, | ||||||
|  |  * in the same order as the list of certs returned by SSL_get0_chain_certs(). | ||||||
|  |  * In case of a missing entry, the respective list element will be NULL. | ||||||
|  |  */ | ||||||
|  | static int get_ocsp_resp_from_files(SSL *s, tlsextstatusctx *srctx, | ||||||
|  |                                     STACK_OF(OCSP_RESPONSE) **sk_resp) | ||||||
|  | { | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *sk_resp_unordered = NULL; | ||||||
|  |     char *respfile = NULL; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     BIO *derbio; | ||||||
|  |     int i; | ||||||
|  |     int num = sk_OPENSSL_STRING_num(srctx->sk_resp_in); | ||||||
|  |     int ret = SSL_TLSEXT_ERR_OK; | ||||||
|  | 
 | ||||||
|  |     sk_resp_unordered = sk_OCSP_RESPONSE_new_reserve(NULL, num); | ||||||
|  | 
 | ||||||
|  |     if (sk_resp_unordered == NULL) { | ||||||
|  |         BIO_puts(bio_err, "cert_status: Cannot reserve memory for OCSP responses\n"); | ||||||
|  |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* reading as many responses as files given */ | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         respfile = sk_OPENSSL_STRING_value(srctx->sk_resp_in, i); | ||||||
|  | 
 | ||||||
|  |         derbio = bio_open_default(respfile, 'r', FORMAT_ASN1); | ||||||
|  | 
 | ||||||
|  |         if (derbio == NULL) { | ||||||
|  |             BIO_printf(bio_err, "cert_status: Cannot open OCSP response file %s\n", respfile); | ||||||
|  |             ret = SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  |             goto err; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); | ||||||
|  |         BIO_free(derbio); | ||||||
|  |         if (resp == NULL) { | ||||||
|  |             BIO_printf(bio_err, "cert_status: Error reading OCSP response from file %s\n", | ||||||
|  |                        respfile); | ||||||
|  |             ret = SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  |             goto err; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         sk_OCSP_RESPONSE_push(sk_resp_unordered, resp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ret = bring_ocsp_resp_in_correct_order(s, srctx, sk_resp_unordered, sk_resp); | ||||||
|  | 
 | ||||||
|  | err: | ||||||
|  |     /* free the unordered list, including all remaining OCSP responses */ | ||||||
|  |     sk_OCSP_RESPONSE_pop_free(sk_resp_unordered, OCSP_RESPONSE_free); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Helper function to get a list of OCSP_RESPONSE from a responder | ||||||
|  |  * for the server certificate and the chain certificates | ||||||
|  |  * in the same order as the list of certs returned by SSL_get0_chain_certs(). | ||||||
|  |  * The function get_ocsp_resp_from_responder_single is called for each | ||||||
|  |  * certificate. | ||||||
|  |  * In case of a missing response, the respective list element will be NULL. | ||||||
|  |  * 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 queries by caching responses until they were considered "expired". | ||||||
|  |  */ | ||||||
|  | static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | ||||||
|  |                                         STACK_OF(OCSP_RESPONSE) **sk_resp) | ||||||
|  | { | ||||||
|  |     X509 *ssl_cert = NULL; | ||||||
|  |     int i, num = 0; | ||||||
|  |     STACK_OF(X509) *server_certs = NULL; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  | 
 | ||||||
|  |     if (*sk_resp != NULL) | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(*sk_resp, OCSP_RESPONSE_free); | ||||||
|  | 
 | ||||||
|  |     SSL_get0_chain_certs(s, &server_certs); | ||||||
|  |     /*
 | ||||||
|  |      * TODO(DTLS-1.3): in future DTLS should also be considered | ||||||
|  |      */ | ||||||
|  |     if (server_certs != NULL && srctx->status_all && | ||||||
|  |         !SSL_is_dtls(s) && SSL_version(s) >= TLS1_3_VERSION) { | ||||||
|  |         /* certificate chain is available */ | ||||||
|  |         num = sk_X509_num(server_certs) + 1; | ||||||
|  |     } else { | ||||||
|  |         /*
 | ||||||
|  |          * certificate chain is not available, | ||||||
|  |          * set num to 1 for server certificate | ||||||
|  |          */ | ||||||
|  |         num = 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ssl_cert = SSL_get_certificate(s); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * OpenSSL servers with TLS < 1.3 can be configured with no certificate | ||||||
|  |      */ | ||||||
|  |     if (ssl_cert == NULL) | ||||||
|  |         return SSL_TLSEXT_ERR_OK; | ||||||
|  | 
 | ||||||
|  |     *sk_resp = sk_OCSP_RESPONSE_new_reserve(NULL, num); | ||||||
|  | 
 | ||||||
|  |     if (sk_resp == NULL) | ||||||
|  |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  | 
 | ||||||
|  |     /* for each certificate in chain (except root) get the OCSP response */ | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         if (i != 0) /* get OCSP response for server certificate first */ | ||||||
|  |             ssl_cert = sk_X509_value(server_certs, i - 1); | ||||||
|  | 
 | ||||||
|  |         resp = NULL; | ||||||
|  |         if (get_ocsp_resp_from_responder_single(s, ssl_cert, srctx, &resp) != SSL_TLSEXT_ERR_OK) | ||||||
|  |             resp = NULL; | ||||||
|  | 
 | ||||||
|  |         /* add response to stack; also insert null response */ | ||||||
|  |         sk_OCSP_RESPONSE_push(*sk_resp, resp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return SSL_TLSEXT_ERR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Certificate Status callback. This is called when a client includes a |  * Certificate Status callback. This is called when a client includes a | ||||||
|  * certificate status request extension. The response is either obtained from a |  * certificate status request extension. The response is either obtained from a | ||||||
|  | @ -600,48 +812,48 @@ static int cert_status_cb(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     tlsextstatusctx *srctx = arg; |     tlsextstatusctx *srctx = arg; | ||||||
|     OCSP_RESPONSE *resp = NULL; |     OCSP_RESPONSE *resp = NULL; | ||||||
|     unsigned char *rspder = NULL; |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|     int rspderlen; |  | ||||||
|     int ret = SSL_TLSEXT_ERR_ALERT_FATAL; |     int ret = SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  |     int i; | ||||||
| 
 | 
 | ||||||
|     if (srctx->verbose) |     if (srctx->verbose) | ||||||
|         BIO_puts(bio_err, "cert_status: callback called\n"); |         BIO_puts(bio_err, "cert_status: callback called\n"); | ||||||
| 
 | 
 | ||||||
|     if (srctx->respin != NULL) { |     SSL_get0_tlsext_status_ocsp_resp_ex(s, &sk_resp); | ||||||
|         BIO *derbio = bio_open_default(srctx->respin, 'r', FORMAT_ASN1); | 
 | ||||||
|         if (derbio == NULL) { |     if (sk_resp == NULL || sk_OCSP_RESPONSE_num(sk_resp) <= 0) { | ||||||
|             BIO_puts(bio_err, "cert_status: Cannot open OCSP response file\n"); |         if (srctx->sk_resp_in != NULL) { | ||||||
|             goto err; |             get_ocsp_resp_from_files(s, srctx, &sk_resp); | ||||||
|         } |  | ||||||
|         resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); |  | ||||||
|         BIO_free(derbio); |  | ||||||
|         if (resp == NULL) { |  | ||||||
|             BIO_puts(bio_err, "cert_status: Error reading OCSP response\n"); |  | ||||||
|             goto err; |  | ||||||
|         } |  | ||||||
|         } else { |         } else { | ||||||
|         ret = get_ocsp_resp_from_responder(s, srctx, &resp); |             ret = get_ocsp_resp_from_responder(s, srctx, &sk_resp); | ||||||
|             if (ret != SSL_TLSEXT_ERR_OK) |             if (ret != SSL_TLSEXT_ERR_OK) | ||||||
|                 goto err; |                 goto err; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     rspderlen = i2d_OCSP_RESPONSE(resp, &rspder); |         (void)SSL_set0_tlsext_status_ocsp_resp_ex(s, sk_resp); | ||||||
|     if (rspderlen <= 0) |     } | ||||||
|         goto err; |  | ||||||
| 
 | 
 | ||||||
|     SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen); |  | ||||||
|     if (srctx->verbose) { |     if (srctx->verbose) { | ||||||
|         BIO_puts(bio_err, "cert_status: ocsp response sent:\n"); |         BIO_puts(bio_err, "cert_status: ocsp response sent:\n"); | ||||||
|  |         BIO_printf(bio_err, "cert_status: number of responses: %d\n", | ||||||
|  |                    sk_OCSP_RESPONSE_num(sk_resp)); | ||||||
|  |         for (i = 0; i < sk_OCSP_RESPONSE_num(sk_resp); i++) { | ||||||
|  |             resp = sk_OCSP_RESPONSE_value(sk_resp, i); | ||||||
|  |             if (resp != NULL) | ||||||
|                 OCSP_RESPONSE_print(bio_err, resp, 2); |                 OCSP_RESPONSE_print(bio_err, resp, 2); | ||||||
|  |             else | ||||||
|  |                 BIO_printf(bio_err, | ||||||
|  |                            "cert_status: no ocsp response for certificate with index %d\n", i); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ret = SSL_TLSEXT_ERR_OK; |     ret = SSL_TLSEXT_ERR_OK; | ||||||
| 
 | 
 | ||||||
|  err: |  err: | ||||||
|     if (ret != SSL_TLSEXT_ERR_OK) |     if (ret != SSL_TLSEXT_ERR_OK) { | ||||||
|         ERR_print_errors(bio_err); |         ERR_print_errors(bio_err); | ||||||
| 
 |         sk_OCSP_RESPONSE_pop_free(sk_resp, OCSP_RESPONSE_free); | ||||||
|     OCSP_RESPONSE_free(resp); |     } | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  | @ -680,6 +892,7 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, | ||||||
|     if (!s_quiet) { |     if (!s_quiet) { | ||||||
|         /* We can assume that |in| is syntactically valid. */ |         /* We can assume that |in| is syntactically valid. */ | ||||||
|         unsigned int i; |         unsigned int i; | ||||||
|  | 
 | ||||||
|         BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); |         BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); | ||||||
|         for (i = 0; i < inlen;) { |         for (i = 0; i < inlen;) { | ||||||
|             if (i) |             if (i) | ||||||
|  | @ -692,9 +905,8 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, | ||||||
| 
 | 
 | ||||||
|     if (SSL_select_next_proto |     if (SSL_select_next_proto | ||||||
|         ((unsigned char **)out, outlen, alpn_ctx->data, |         ((unsigned char **)out, outlen, alpn_ctx->data, | ||||||
|          (unsigned int)alpn_ctx->len, in, inlen) != OPENSSL_NPN_NEGOTIATED) { |          (unsigned int)alpn_ctx->len, in, inlen) != OPENSSL_NPN_NEGOTIATED) | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (!s_quiet) { |     if (!s_quiet) { | ||||||
|         BIO_printf(bio_s_out, "ALPN protocols selected: "); |         BIO_printf(bio_s_out, "ALPN protocols selected: "); | ||||||
|  | @ -725,9 +937,9 @@ typedef enum OPTION_choice { | ||||||
|     OPT_VERIFYCAFILE, |     OPT_VERIFYCAFILE, | ||||||
|     OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, |     OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, | ||||||
|     OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, |     OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, | ||||||
|     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_VERBOSE, |     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_ALL, | ||||||
|     OPT_STATUS_TIMEOUT, OPT_PROXY, OPT_NO_PROXY, OPT_STATUS_URL, |     OPT_STATUS_VERBOSE, OPT_STATUS_TIMEOUT, OPT_PROXY, OPT_NO_PROXY, | ||||||
|     OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, |     OPT_STATUS_URL, OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, | ||||||
|     OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, |     OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, | ||||||
|     OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, |     OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, | ||||||
|     OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, |     OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, | ||||||
|  | @ -876,9 +1088,12 @@ const OPTIONS s_server_options[] = { | ||||||
|     {"cert_comp", OPT_CERT_COMP, '-', "Pre-compress server certificates"}, |     {"cert_comp", OPT_CERT_COMP, '-', "Pre-compress server certificates"}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|     OPT_SECTION("OCSP"), |     OPT_SECTION("OCSP"), | ||||||
|     {"status", OPT_STATUS, '-', "Request certificate status from server"}, |     {"status", OPT_STATUS, '-', | ||||||
|  |      "Provide certificate status response if requested, for server cert only"}, | ||||||
|  |     {"status_all", OPT_STATUS_ALL, '-', | ||||||
|  |      "Provide certificate status response(s) if requested, for the whole chain"}, | ||||||
|     {"status_verbose", OPT_STATUS_VERBOSE, '-', |     {"status_verbose", OPT_STATUS_VERBOSE, '-', | ||||||
|      "Print more output in certificate status callback"}, |      "Print more output in certificate status callback"}, | ||||||
|     {"status_timeout", OPT_STATUS_TIMEOUT, 'n', |     {"status_timeout", OPT_STATUS_TIMEOUT, 'n', | ||||||
|  | @ -891,8 +1106,8 @@ const OPTIONS s_server_options[] = { | ||||||
|     {OPT_MORE_STR, 0, 0, |     {OPT_MORE_STR, 0, 0, | ||||||
|      "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, |      "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, | ||||||
|     {"status_file", OPT_STATUS_FILE, '<', |     {"status_file", OPT_STATUS_FILE, '<', | ||||||
|      "File containing DER encoded OCSP Response"}, |      "File containing DER encoded OCSP Response (can be specified multiple times)"}, | ||||||
| #endif | # endif | ||||||
| 
 | 
 | ||||||
|     OPT_SECTION("Debug"), |     OPT_SECTION("Debug"), | ||||||
|     {"security_debug", OPT_SECURITY_DEBUG, '-', |     {"security_debug", OPT_SECURITY_DEBUG, '-', | ||||||
|  | @ -1076,9 +1291,9 @@ int s_server_main(int argc, char *argv[]) | ||||||
|     const char *s_cert_file = TEST_CERT, *s_key_file = NULL, *s_chain_file = NULL; |     const char *s_cert_file = TEST_CERT, *s_key_file = NULL, *s_chain_file = NULL; | ||||||
|     const char *s_cert_file2 = TEST_CERT2, *s_key_file2 = NULL; |     const char *s_cert_file2 = TEST_CERT2, *s_key_file2 = NULL; | ||||||
|     char *s_dcert_file = NULL, *s_dkey_file = NULL, *s_dchain_file = NULL; |     char *s_dcert_file = NULL, *s_dkey_file = NULL, *s_dchain_file = NULL; | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|     int s_tlsextstatus = 0; |     int s_tlsextstatus = 0; | ||||||
| #endif | # endif | ||||||
|     int no_resume_ephemeral = 0; |     int no_resume_ephemeral = 0; | ||||||
|     unsigned int max_send_fragment = 0; |     unsigned int max_send_fragment = 0; | ||||||
|     unsigned int split_send_fragment = 0, max_pipelines = 0; |     unsigned int split_send_fragment = 0, max_pipelines = 0; | ||||||
|  | @ -1390,33 +1605,40 @@ int s_server_main(int argc, char *argv[]) | ||||||
|             s_tlsextdebug = 1; |             s_tlsextdebug = 1; | ||||||
|             break; |             break; | ||||||
|         case OPT_STATUS: |         case OPT_STATUS: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             s_tlsextstatus = 1; |             s_tlsextstatus = 1; | ||||||
| #endif |             tlscstatp.status_all = 0; | ||||||
|  | # endif | ||||||
|             break; |             break; | ||||||
|  |         case OPT_STATUS_ALL: | ||||||
|  | # ifndef OPENSSL_NO_OCSP | ||||||
|  |             s_tlsextstatus = tlscstatp.status_all = 1; | ||||||
|  | # endif | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|         case OPT_STATUS_VERBOSE: |         case OPT_STATUS_VERBOSE: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             s_tlsextstatus = tlscstatp.verbose = 1; |             s_tlsextstatus = tlscstatp.verbose = 1; | ||||||
| #endif | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_STATUS_TIMEOUT: |         case OPT_STATUS_TIMEOUT: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             s_tlsextstatus = 1; |             s_tlsextstatus = 1; | ||||||
|             tlscstatp.timeout = atoi(opt_arg()); |             tlscstatp.timeout = atoi(opt_arg()); | ||||||
| #endif | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_PROXY: |         case OPT_PROXY: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             tlscstatp.proxy = opt_arg(); |             tlscstatp.proxy = opt_arg(); | ||||||
| #endif | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_NO_PROXY: |         case OPT_NO_PROXY: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             tlscstatp.no_proxy = opt_arg(); |             tlscstatp.no_proxy = opt_arg(); | ||||||
| #endif | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_STATUS_URL: |         case OPT_STATUS_URL: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             s_tlsextstatus = 1; |             s_tlsextstatus = 1; | ||||||
|             if (!OSSL_HTTP_parse_url(opt_arg(), &tlscstatp.use_ssl, NULL, |             if (!OSSL_HTTP_parse_url(opt_arg(), &tlscstatp.use_ssl, NULL, | ||||||
|                                      &tlscstatp.host, &tlscstatp.port, NULL, |                                      &tlscstatp.host, &tlscstatp.port, NULL, | ||||||
|  | @ -1424,13 +1646,16 @@ int s_server_main(int argc, char *argv[]) | ||||||
|                 BIO_printf(bio_err, "Error parsing -status_url argument\n"); |                 BIO_printf(bio_err, "Error parsing -status_url argument\n"); | ||||||
|                 goto end; |                 goto end; | ||||||
|             } |             } | ||||||
| #endif | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_STATUS_FILE: |         case OPT_STATUS_FILE: | ||||||
| #ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|             s_tlsextstatus = 1; |             s_tlsextstatus = 1; | ||||||
|             tlscstatp.respin = opt_arg(); |             if (tlscstatp.sk_resp_in == NULL | ||||||
| #endif |                 && (tlscstatp.sk_resp_in = sk_OPENSSL_STRING_new_null()) == NULL) | ||||||
|  |                 goto end; | ||||||
|  |             sk_OPENSSL_STRING_push(tlscstatp.sk_resp_in, opt_arg()); | ||||||
|  | # endif | ||||||
|             break; |             break; | ||||||
|         case OPT_MSG: |         case OPT_MSG: | ||||||
|             s_msg = 1; |             s_msg = 1; | ||||||
|  | @ -2358,6 +2583,7 @@ int s_server_main(int argc, char *argv[]) | ||||||
|     OPENSSL_free(port); |     OPENSSL_free(port); | ||||||
|     X509_VERIFY_PARAM_free(vpm); |     X509_VERIFY_PARAM_free(vpm); | ||||||
|     free_sessions(); |     free_sessions(); | ||||||
|  |     sk_OPENSSL_STRING_free(tlscstatp.sk_resp_in); | ||||||
|     OPENSSL_free(tlscstatp.host); |     OPENSSL_free(tlscstatp.host); | ||||||
|     OPENSSL_free(tlscstatp.port); |     OPENSSL_free(tlscstatp.port); | ||||||
|     OPENSSL_free(tlscstatp.path); |     OPENSSL_free(tlscstatp.path); | ||||||
|  |  | ||||||
|  | @ -174,6 +174,16 @@ const char *X509_verify_cert_error_string(long n) | ||||||
|         return "OCSP verification failed"; |         return "OCSP verification failed"; | ||||||
|     case X509_V_ERR_OCSP_CERT_UNKNOWN: |     case X509_V_ERR_OCSP_CERT_UNKNOWN: | ||||||
|         return "OCSP unknown cert"; |         return "OCSP unknown cert"; | ||||||
|  |     case X509_V_ERR_OCSP_RESP_INVALID: | ||||||
|  |         return "OCSP response(s) invalid"; | ||||||
|  |     case X509_V_ERR_OCSP_SIGNATURE_FAILURE: | ||||||
|  |         return "OCSP response signature verification failure"; | ||||||
|  |     case X509_V_ERR_OCSP_NOT_YET_VALID: | ||||||
|  |         return "OCSP response not yet valid (contains a date in the future)"; | ||||||
|  |     case X509_V_ERR_OCSP_HAS_EXPIRED: | ||||||
|  |         return "OCSP response has expired"; | ||||||
|  |     case X509_V_ERR_OCSP_NO_RESPONSE: | ||||||
|  |         return "no OCSP response available for certificate"; | ||||||
|     case X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM: |     case X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM: | ||||||
|         return "Cannot find certificate signature algorithm"; |         return "Cannot find certificate signature algorithm"; | ||||||
|     case X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH: |     case X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH: | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ | ||||||
| #include <openssl/asn1.h> | #include <openssl/asn1.h> | ||||||
| #include <openssl/x509.h> | #include <openssl/x509.h> | ||||||
| #include <openssl/x509v3.h> | #include <openssl/x509v3.h> | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| #include <openssl/objects.h> | #include <openssl/objects.h> | ||||||
| #include <openssl/core_names.h> | #include <openssl/core_names.h> | ||||||
| #include "internal/dane.h" | #include "internal/dane.h" | ||||||
|  | @ -55,7 +56,10 @@ static int check_name_constraints(X509_STORE_CTX *ctx); | ||||||
| static int check_id(X509_STORE_CTX *ctx); | static int check_id(X509_STORE_CTX *ctx); | ||||||
| static int check_trust(X509_STORE_CTX *ctx, int num_untrusted); | static int check_trust(X509_STORE_CTX *ctx, int num_untrusted); | ||||||
| static int check_revocation(X509_STORE_CTX *ctx); | static int check_revocation(X509_STORE_CTX *ctx); | ||||||
| static int check_cert(X509_STORE_CTX *ctx); | #ifndef OPENSSL_NO_OCSP | ||||||
|  | static int check_cert_ocsp_resp(X509_STORE_CTX *ctx); | ||||||
|  | #endif | ||||||
|  | static int check_cert_crl(X509_STORE_CTX *ctx); | ||||||
| static int check_policy(X509_STORE_CTX *ctx); | static int check_policy(X509_STORE_CTX *ctx); | ||||||
| static int check_dane_issuer(X509_STORE_CTX *ctx, int depth); | static int check_dane_issuer(X509_STORE_CTX *ctx, int depth); | ||||||
| static int check_cert_key_level(X509_STORE_CTX *ctx, X509 *cert); | static int check_cert_key_level(X509_STORE_CTX *ctx, X509 *cert); | ||||||
|  | @ -184,6 +188,24 @@ static int verify_cb_crl(X509_STORE_CTX *ctx, int err) | ||||||
|     return ctx->verify_cb(0, ctx); |     return ctx->verify_cb(0, ctx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  | /*
 | ||||||
|  |  * Inform the verify callback of an error, OCSP-specific variant. | ||||||
|  |  * It is called also on OCSP response errors, if the | ||||||
|  |  * X509_V_FLAG_OCSP_RESP_CHECK or X509_V_FLAG_OCSP_RESP_CHECK_ALL flag | ||||||
|  |  * is set. | ||||||
|  |  * Here, the error depth and certificate are already set, we just specify | ||||||
|  |  * the error number. | ||||||
|  |  * | ||||||
|  |  * Returns 0 to abort verification with an error, non-zero to continue. | ||||||
|  |  */ | ||||||
|  | static int verify_cb_ocsp(X509_STORE_CTX *ctx, int err) | ||||||
|  | { | ||||||
|  |     ctx->error = err; | ||||||
|  |     return ctx->verify_cb(0, ctx); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /* Sadly, returns 0 also on internal error in ctx->verify_cb(). */ | /* Sadly, returns 0 also on internal error in ctx->verify_cb(). */ | ||||||
| static int check_auth_level(X509_STORE_CTX *ctx) | static int check_auth_level(X509_STORE_CTX *ctx) | ||||||
| { | { | ||||||
|  | @ -225,7 +247,6 @@ static int verify_rpk(X509_STORE_CTX *ctx) | ||||||
|     return !!ctx->verify_cb(ctx->error == X509_V_OK, ctx); |     return !!ctx->verify_cb(ctx->error == X509_V_OK, ctx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /*-
 | /*-
 | ||||||
|  * Returns -1 on internal error. |  * Returns -1 on internal error. | ||||||
|  * Sadly, returns 0 also on internal error in ctx->verify_cb(). |  * Sadly, returns 0 also on internal error in ctx->verify_cb(). | ||||||
|  | @ -1037,10 +1058,84 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted) | ||||||
| static int check_revocation(X509_STORE_CTX *ctx) | static int check_revocation(X509_STORE_CTX *ctx) | ||||||
| { | { | ||||||
|     int i = 0, last = 0, ok = 0; |     int i = 0, last = 0, ok = 0; | ||||||
|  |     int crl_check_enabled = | ||||||
|  |         (ctx->param->flags & | ||||||
|  |          (X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL)) != 0; | ||||||
|  |     int crl_check_all_enabled = | ||||||
|  |         (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) != 0; | ||||||
|  |     int ocsp_check_enabled = | ||||||
|  |         (ctx->param->flags & | ||||||
|  |          (X509_V_FLAG_OCSP_RESP_CHECK | X509_V_FLAG_OCSP_RESP_CHECK_ALL)) != 0; | ||||||
|  |     int ocsp_check_all_enabled = | ||||||
|  |         (ctx->param->flags & X509_V_FLAG_OCSP_RESP_CHECK_ALL) != 0; | ||||||
| 
 | 
 | ||||||
|     if ((ctx->param->flags & X509_V_FLAG_CRL_CHECK) == 0) |     if (!crl_check_enabled && !ocsp_check_enabled) | ||||||
|         return 1; |         return 1; | ||||||
|     if ((ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) != 0) { | 
 | ||||||
|  |     if (ocsp_check_enabled) { | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |         /*
 | ||||||
|  |          * certificate status checking with OCSP | ||||||
|  |          */ | ||||||
|  |         if (ocsp_check_all_enabled) | ||||||
|  |             last = sk_X509_num(ctx->chain) - 1; | ||||||
|  |         else if (!crl_check_all_enabled && ctx->parent != NULL) | ||||||
|  |             return 1; /* If checking CRL paths this isn't the EE certificate */ | ||||||
|  | 
 | ||||||
|  |         for (i = 0; i <= last; i++) { | ||||||
|  |             ctx->error_depth = i; | ||||||
|  |             ctx->current_cert = sk_X509_value(ctx->chain, i); | ||||||
|  | 
 | ||||||
|  |             /* skip if cert is apparently self-signed */ | ||||||
|  |             if (ctx->current_cert->ex_flags & EXFLAG_SS) | ||||||
|  |                 continue; | ||||||
|  | 
 | ||||||
|  |             /* the issuer certificate is the next in the chain */ | ||||||
|  |             ctx->current_issuer = sk_X509_value(ctx->chain, i + 1); | ||||||
|  | 
 | ||||||
|  |             ok = check_cert_ocsp_resp(ctx); | ||||||
|  | 
 | ||||||
|  |             /*
 | ||||||
|  |              * In the case the certificate status is REVOKED, the verification | ||||||
|  |              * can stop here. | ||||||
|  |              */ | ||||||
|  |             if (ok == V_OCSP_CERTSTATUS_REVOKED) { | ||||||
|  |                 return verify_cb_ocsp(ctx, ctx->error != 0 | ||||||
|  |                                       ? ctx->error | ||||||
|  |                                       : X509_V_ERR_OCSP_VERIFY_FAILED); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /*
 | ||||||
|  |              * In the case the certificate status is GOOD, continue with the next | ||||||
|  |              * certificate. | ||||||
|  |              */ | ||||||
|  |             if (ok == V_OCSP_CERTSTATUS_GOOD) | ||||||
|  |                 continue; | ||||||
|  | 
 | ||||||
|  |             /*
 | ||||||
|  |              * As stated in RFC 6961 section 2.2: | ||||||
|  |              * If OCSP is not enabled or the client receives a "ocsp_response_list" | ||||||
|  |              * that does not contain a response for one or more of the certificates | ||||||
|  |              * in the completed certificate chain, the client SHOULD attempt to | ||||||
|  |              * validate the certificate using an alternative retrieval method, | ||||||
|  |              * such as downloading the relevant CRL; | ||||||
|  |              */ | ||||||
|  |             if (crl_check_all_enabled || (crl_check_enabled && i == 0)) { | ||||||
|  |                 ok = check_cert_crl(ctx); | ||||||
|  |                 if (!ok) | ||||||
|  |                     return ok; | ||||||
|  |             } else { | ||||||
|  |                 ok = verify_cb_ocsp(ctx, X509_V_ERR_OCSP_VERIFY_FAILED); | ||||||
|  |                 if (!ok) | ||||||
|  |                     return ok; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (crl_check_enabled && !ocsp_check_all_enabled) { | ||||||
|  |         /* certificate status check with CRLs */ | ||||||
|  |         if (crl_check_all_enabled) { | ||||||
|             last = sk_X509_num(ctx->chain) - 1; |             last = sk_X509_num(ctx->chain) - 1; | ||||||
|         } else { |         } else { | ||||||
|             /* If checking CRL paths this isn't the EE certificate */ |             /* If checking CRL paths this isn't the EE certificate */ | ||||||
|  | @ -1048,17 +1143,124 @@ static int check_revocation(X509_STORE_CTX *ctx) | ||||||
|                 return 1; |                 return 1; | ||||||
|             last = 0; |             last = 0; | ||||||
|         } |         } | ||||||
|     for (i = 0; i <= last; i++) { | 
 | ||||||
|  |         /*
 | ||||||
|  |          * in the case that OCSP is only enabled for the server certificate | ||||||
|  |          * and CRL for the complete chain, the rest of the chain has to be | ||||||
|  |          * checked here | ||||||
|  |          */ | ||||||
|  |         if (ocsp_check_enabled && crl_check_all_enabled) | ||||||
|  |             i = 1; | ||||||
|  |         else | ||||||
|  |             i = 0; | ||||||
|  |         for (; i <= last; i++) { | ||||||
|             ctx->error_depth = i; |             ctx->error_depth = i; | ||||||
|         ok = check_cert(ctx); |             ok = check_cert_crl(ctx); | ||||||
|             if (!ok) |             if (!ok) | ||||||
|                 return ok; |                 return ok; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  | static int check_cert_ocsp_resp(X509_STORE_CTX *ctx) | ||||||
|  | { | ||||||
|  |     int cert_status, crl_reason; | ||||||
|  |     int i; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     OCSP_BASICRESP *bs = NULL; | ||||||
|  |     OCSP_SINGLERESP *sr = NULL; | ||||||
|  |     OCSP_CERTID *sr_cert_id = NULL; | ||||||
|  |     ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; | ||||||
|  |     ASN1_OBJECT *cert_id_md_oid; | ||||||
|  |     EVP_MD *cert_id_md; | ||||||
|  |     OCSP_CERTID *cert_id = NULL; | ||||||
|  |     int ret = V_OCSP_CERTSTATUS_UNKNOWN; | ||||||
|  |     int num; | ||||||
|  | 
 | ||||||
|  |     num = sk_OCSP_RESPONSE_num(ctx->ocsp_resp); | ||||||
|  | 
 | ||||||
|  |     if (num < 0 || num <= ctx->error_depth) | ||||||
|  |         return X509_V_ERR_OCSP_NO_RESPONSE; | ||||||
|  | 
 | ||||||
|  |     if ((resp = sk_OCSP_RESPONSE_value(ctx->ocsp_resp, ctx->error_depth)) == NULL | ||||||
|  |         || (bs = OCSP_response_get1_basic(resp)) == NULL | ||||||
|  |         || (num = OCSP_resp_count(bs)) < 1) | ||||||
|  |         return X509_V_ERR_OCSP_NO_RESPONSE; | ||||||
|  | 
 | ||||||
|  |     if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { | ||||||
|  |         OCSP_BASICRESP_free(bs); | ||||||
|  |         ret = X509_V_ERR_OCSP_RESP_INVALID; | ||||||
|  |         goto end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (OCSP_basic_verify(bs, ctx->chain, ctx->store, OCSP_TRUSTOTHER) <= 0) { | ||||||
|  |         ret = X509_V_ERR_OCSP_SIGNATURE_FAILURE; | ||||||
|  |         goto end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* find the right single response in the OCSP response */ | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         sr = OCSP_resp_get0(bs, i); | ||||||
|  | 
 | ||||||
|  |         /* determine the md algorithm which was used to create cert id */ | ||||||
|  |         sr_cert_id = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); | ||||||
|  |         OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, sr_cert_id); | ||||||
|  |         if (cert_id_md_oid != NULL) | ||||||
|  |             cert_id_md = (EVP_MD *)EVP_get_digestbyobj(cert_id_md_oid); | ||||||
|  |         else | ||||||
|  |             cert_id_md = NULL; | ||||||
|  | 
 | ||||||
|  |         /* search the stack for the requested OCSP response */ | ||||||
|  |         cert_id = OCSP_cert_to_id(cert_id_md, ctx->current_cert, ctx->current_issuer); | ||||||
|  |         if (cert_id == NULL) { | ||||||
|  |             ret = X509_V_ERR_OCSP_RESP_INVALID; | ||||||
|  |             goto end; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!OCSP_id_cmp(cert_id, sr_cert_id)) | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         OCSP_CERTID_free(cert_id); | ||||||
|  |         cert_id = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (cert_id == NULL) { | ||||||
|  |         ret = X509_V_ERR_OCSP_NO_RESPONSE; | ||||||
|  |         goto end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (OCSP_resp_find_status(bs, cert_id, &cert_status, &crl_reason, &rev, | ||||||
|  |                               &thisupd, &nextupd) <= 0) { | ||||||
|  |         ret = X509_V_ERR_OCSP_RESP_INVALID; | ||||||
|  |         goto end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (cert_status == V_OCSP_CERTSTATUS_GOOD) { | ||||||
|  |         /*
 | ||||||
|  |          * Note: | ||||||
|  |          * A OCSP stapling result will be accepted up to 5 minutes | ||||||
|  |          * after it expired! | ||||||
|  |          */ | ||||||
|  |         if (!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) | ||||||
|  |             ret = X509_V_ERR_OCSP_HAS_EXPIRED; | ||||||
|  |         else | ||||||
|  |             ret = V_OCSP_CERTSTATUS_GOOD; | ||||||
|  |     } else { | ||||||
|  |         ret = cert_status; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | end: | ||||||
|  |     OCSP_CERTID_free(cert_id); | ||||||
|  |     OCSP_BASICRESP_free(bs); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /* Sadly, returns 0 also on internal error. */ | /* Sadly, returns 0 also on internal error. */ | ||||||
| static int check_cert(X509_STORE_CTX *ctx) | static int check_cert_crl(X509_STORE_CTX *ctx) | ||||||
| { | { | ||||||
|     X509_CRL *crl = NULL, *dcrl = NULL; |     X509_CRL *crl = NULL, *dcrl = NULL; | ||||||
|     int ok = 0; |     int ok = 0; | ||||||
|  | @ -1070,6 +1272,9 @@ static int check_cert(X509_STORE_CTX *ctx) | ||||||
|     ctx->current_crl_score = 0; |     ctx->current_crl_score = 0; | ||||||
|     ctx->current_reasons = 0; |     ctx->current_reasons = 0; | ||||||
| 
 | 
 | ||||||
|  |     /* skip if cert is apparently self-signed */ | ||||||
|  |     if (ctx->current_cert->ex_flags & EXFLAG_SS) | ||||||
|  |         return 1; | ||||||
|     if ((x->ex_flags & EXFLAG_PROXY) != 0) |     if ((x->ex_flags & EXFLAG_PROXY) != 0) | ||||||
|         return 1; |         return 1; | ||||||
| 
 | 
 | ||||||
|  | @ -1645,7 +1850,7 @@ static int get_crl_delta(X509_STORE_CTX *ctx, | ||||||
| 
 | 
 | ||||||
|     sk_X509_CRL_pop_free(skcrl, X509_CRL_free); |     sk_X509_CRL_pop_free(skcrl, X509_CRL_free); | ||||||
| 
 | 
 | ||||||
|  done: | done: | ||||||
|     /* If we got any kind of CRL use it and return success */ |     /* If we got any kind of CRL use it and return success */ | ||||||
|     if (crl != NULL) { |     if (crl != NULL) { | ||||||
|         ctx->current_issuer = issuer; |         ctx->current_issuer = issuer; | ||||||
|  | @ -2374,6 +2579,13 @@ void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk) | ||||||
|     ctx->crls = sk; |     ctx->crls = sk; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  | void X509_STORE_CTX_set_ocsp_resp(X509_STORE_CTX *ctx, STACK_OF(OCSP_RESPONSE) *sk) | ||||||
|  | { | ||||||
|  |     ctx->ocsp_resp = sk; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) | int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) | ||||||
| { | { | ||||||
|     /*
 |     /*
 | ||||||
|  | @ -2490,7 +2702,6 @@ void X509_STORE_CTX_free(X509_STORE_CTX *ctx) | ||||||
|     OPENSSL_free(ctx); |     OPENSSL_free(ctx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| int X509_STORE_CTX_init_rpk(X509_STORE_CTX *ctx, X509_STORE *store, EVP_PKEY *rpk) | int X509_STORE_CTX_init_rpk(X509_STORE_CTX *ctx, X509_STORE *store, EVP_PKEY *rpk) | ||||||
| { | { | ||||||
|     if (!X509_STORE_CTX_init(ctx, store, NULL, NULL)) |     if (!X509_STORE_CTX_init(ctx, store, NULL, NULL)) | ||||||
|  | @ -2531,6 +2742,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, | ||||||
|     ctx->rpk = NULL; |     ctx->rpk = NULL; | ||||||
|     /* Zero ex_data to make sure we're cleanup-safe */ |     /* Zero ex_data to make sure we're cleanup-safe */ | ||||||
|     memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); |     memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); | ||||||
|  |     ctx->ocsp_resp = NULL; | ||||||
| 
 | 
 | ||||||
|     /* store->cleanup is always 0 in OpenSSL, if set must be idempotent */ |     /* store->cleanup is always 0 in OpenSSL, if set must be idempotent */ | ||||||
|     if (store != NULL) |     if (store != NULL) | ||||||
|  |  | ||||||
|  | @ -94,6 +94,8 @@ B<openssl> B<s_client> | ||||||
| [B<-sess_in> I<filename>] | [B<-sess_in> I<filename>] | ||||||
| [B<-serverinfo> I<types>] | [B<-serverinfo> I<types>] | ||||||
| [B<-status>] | [B<-status>] | ||||||
|  | [B<-ocsp_check_leaf>] | ||||||
|  | [B<-ocsp_check_all>] | ||||||
| [B<-alpn> I<protocols>] | [B<-alpn> I<protocols>] | ||||||
| [B<-nextprotoneg> I<protocols>] | [B<-nextprotoneg> I<protocols>] | ||||||
| [B<-ct>] | [B<-ct>] | ||||||
|  | @ -671,6 +673,24 @@ file. | ||||||
| Sends a certificate status request to the server (OCSP stapling). The server | Sends a certificate status request to the server (OCSP stapling). The server | ||||||
| response (if any) is printed out. | response (if any) is printed out. | ||||||
| 
 | 
 | ||||||
|  | =item B<-ocsp_check_leaf> | ||||||
|  | 
 | ||||||
|  | Require performing server (end-entity) certificate status checking, where any | ||||||
|  | OCSP response provided in the TLS handshake (by so-called "OCSP stapling") is tried | ||||||
|  | first. | ||||||
|  | If no valid and conclusive OCSP response can be found, CRL-based checking | ||||||
|  | is attempted as fallback if enabled, otherwise the status check fails. | ||||||
|  | 
 | ||||||
|  | This implies B<-status>. | ||||||
|  | 
 | ||||||
|  | =item B<-ocsp_check_all> | ||||||
|  | 
 | ||||||
|  | As the option before, but require performing certificate status checking also | ||||||
|  | for the issuer chain of the server certificate (i.e., intermediate CA certificates, | ||||||
|  | excluding the trust anchor). | ||||||
|  | 
 | ||||||
|  | This implies the B<-status> and B<-ocsp_check_leaf>. | ||||||
|  | 
 | ||||||
| =item B<-alpn> I<protocols>, B<-nextprotoneg> I<protocols> | =item B<-alpn> I<protocols>, B<-nextprotoneg> I<protocols> | ||||||
| 
 | 
 | ||||||
| These flags enable the Enable the Application-Layer Protocol Negotiation | These flags enable the Enable the Application-Layer Protocol Negotiation | ||||||
|  | @ -1023,6 +1043,11 @@ B<-no_tx_cert_comp>, | ||||||
| and B<-tfo> | and B<-tfo> | ||||||
| options were added in OpenSSL 3.2. | options were added in OpenSSL 3.2. | ||||||
| 
 | 
 | ||||||
|  | The | ||||||
|  | <-ocsp_check_leaf> | ||||||
|  | and B<-ocsp_check_all> | ||||||
|  | options were added in OpenSSL 3.6. | ||||||
|  | 
 | ||||||
| =head1 COPYRIGHT | =head1 COPYRIGHT | ||||||
| 
 | 
 | ||||||
| Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. | Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. | ||||||
|  |  | ||||||
|  | @ -74,6 +74,7 @@ B<openssl> B<s_server> | ||||||
| [B<-no_ign_eof>] | [B<-no_ign_eof>] | ||||||
| [B<-no_ems>] | [B<-no_ems>] | ||||||
| [B<-status>] | [B<-status>] | ||||||
|  | [B<-status_all>] | ||||||
| [B<-status_verbose>] | [B<-status_verbose>] | ||||||
| [B<-status_timeout> I<int>] | [B<-status_timeout> I<int>] | ||||||
| [B<-proxy> I<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]>] | [B<-proxy> I<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]>] | ||||||
|  | @ -487,7 +488,15 @@ Disable Extended master secret negotiation. | ||||||
| 
 | 
 | ||||||
| =item B<-status> | =item B<-status> | ||||||
| 
 | 
 | ||||||
| Enables certificate status request support (aka OCSP stapling). | Enables certificate status request support (aka OCSP stapling): | ||||||
|  | an OCSP response is provided for the leaf (server) certificate | ||||||
|  | if requested by the client side. | ||||||
|  | 
 | ||||||
|  | =item B<-status_all> | ||||||
|  | 
 | ||||||
|  | Like before, but for TLS v1.3 and beyond, status responses for all | ||||||
|  | certificates in the chain (except the trust anchor) are provided | ||||||
|  | if requested by the client side. | ||||||
| 
 | 
 | ||||||
| =item B<-status_verbose> | =item B<-status_verbose> | ||||||
| 
 | 
 | ||||||
|  | @ -530,6 +539,8 @@ Any given query component is handled as part of the path component. | ||||||
| 
 | 
 | ||||||
| Overrides any OCSP responder URLs from the certificate and always provides the | Overrides any OCSP responder URLs from the certificate and always provides the | ||||||
| OCSP Response stored in the file. The file must be in DER format. | OCSP Response stored in the file. The file must be in DER format. | ||||||
|  | This option may be used multiple times to specify OCSP responses for all | ||||||
|  | certificates in the server certificate chain. | ||||||
| 
 | 
 | ||||||
| =item B<-ssl_config> I<val> | =item B<-ssl_config> I<val> | ||||||
| 
 | 
 | ||||||
|  | @ -925,6 +936,8 @@ B<-no_tx_cert_comp>, | ||||||
| and B<-tfo> | and B<-tfo> | ||||||
| options were added in OpenSSL 3.2. | options were added in OpenSSL 3.2. | ||||||
| 
 | 
 | ||||||
|  | The B<-status_all> option was added in OpenSSL 3.6. | ||||||
|  | 
 | ||||||
| =head1 COPYRIGHT | =head1 COPYRIGHT | ||||||
| 
 | 
 | ||||||
| Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. | Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. | ||||||
|  |  | ||||||
|  | @ -11,7 +11,9 @@ SSL_CTX_get_tlsext_status_type, | ||||||
| SSL_set_tlsext_status_type, | SSL_set_tlsext_status_type, | ||||||
| SSL_get_tlsext_status_type, | SSL_get_tlsext_status_type, | ||||||
| SSL_get_tlsext_status_ocsp_resp, | SSL_get_tlsext_status_ocsp_resp, | ||||||
| SSL_set_tlsext_status_ocsp_resp | SSL_set_tlsext_status_ocsp_resp, | ||||||
|  | SSL_get0_tlsext_status_ocsp_resp_ex, | ||||||
|  | SSL_set0_tlsext_status_ocsp_resp_ex | ||||||
| - OCSP Certificate Status Request functions | - OCSP Certificate Status Request functions | ||||||
| 
 | 
 | ||||||
| =head1 SYNOPSIS | =head1 SYNOPSIS | ||||||
|  | @ -33,9 +35,12 @@ SSL_set_tlsext_status_ocsp_resp | ||||||
|  long SSL_get_tlsext_status_ocsp_resp(ssl, unsigned char **resp); |  long SSL_get_tlsext_status_ocsp_resp(ssl, unsigned char **resp); | ||||||
|  long SSL_set_tlsext_status_ocsp_resp(ssl, unsigned char *resp, int len); |  long SSL_set_tlsext_status_ocsp_resp(ssl, unsigned char *resp, int len); | ||||||
| 
 | 
 | ||||||
|  |  long SSL_get0_tlsext_status_ocsp_resp_ex(ssl, STACK_OF(OCSP_RESPONSE) **resp); | ||||||
|  |  long SSL_set0_tlsext_status_ocsp_resp_ex(ssl, STACK_OF(OCSP_RESPONSE) *resp); | ||||||
|  | 
 | ||||||
| =head1 DESCRIPTION | =head1 DESCRIPTION | ||||||
| 
 | 
 | ||||||
| A client application may request that a server send back an OCSP status response | A client application may request that a server send back OCSP status response(s) | ||||||
| (also known as OCSP stapling). To do so the client should call the | (also known as OCSP stapling). To do so the client should call the | ||||||
| SSL_CTX_set_tlsext_status_type() function prior to the creation of any SSL | SSL_CTX_set_tlsext_status_type() function prior to the creation of any SSL | ||||||
| objects. Alternatively an application can call the SSL_set_tlsext_status_type() | objects. Alternatively an application can call the SSL_set_tlsext_status_type() | ||||||
|  | @ -45,9 +50,13 @@ should be passed in the B<type> argument. Calling | ||||||
| SSL_CTX_get_tlsext_status_type() will return the type B<TLSEXT_STATUSTYPE_ocsp> | SSL_CTX_get_tlsext_status_type() will return the type B<TLSEXT_STATUSTYPE_ocsp> | ||||||
| previously set via SSL_CTX_set_tlsext_status_type() or -1 if not set. | previously set via SSL_CTX_set_tlsext_status_type() or -1 if not set. | ||||||
| 
 | 
 | ||||||
|  | For TLS versions before 1.3 only a single OCSP status response is sent back | ||||||
|  | by the server. TLS 1.3 specifies that the server can send OCSP status responses | ||||||
|  | for the whole chain (OCSP multi-stapling). | ||||||
|  | 
 | ||||||
| The client should additionally provide a callback function to decide what to do | The client should additionally provide a callback function to decide what to do | ||||||
| with the returned OCSP response by calling SSL_CTX_set_tlsext_status_cb(). The | with the returned OCSP response by calling SSL_CTX_set_tlsext_status_cb(). The | ||||||
| callback function should determine whether the returned OCSP response is | callback function should determine whether the returned OCSP response(s) are | ||||||
| acceptable or not. The callback will be passed as an argument the value | acceptable or not. The callback will be passed as an argument the value | ||||||
| previously set via a call to SSL_CTX_set_tlsext_status_arg(). Note that the | previously set via a call to SSL_CTX_set_tlsext_status_arg(). Note that the | ||||||
| callback will not be called in the event of a handshake where session resumption | callback will not be called in the event of a handshake where session resumption | ||||||
|  | @ -63,22 +72,48 @@ side SSL_get_tlsext_status_type() can be used to determine whether the client | ||||||
| requested OCSP stapling. If the client requested it then this function will | requested OCSP stapling. If the client requested it then this function will | ||||||
| return B<TLSEXT_STATUSTYPE_ocsp>, or -1 otherwise. | return B<TLSEXT_STATUSTYPE_ocsp>, or -1 otherwise. | ||||||
| 
 | 
 | ||||||
| The response returned by the server can be obtained via a call to | A single response returned by the server (TLS < 1.3) can be obtained via a call | ||||||
| SSL_get_tlsext_status_ocsp_resp(). The value B<*resp> will be updated to point | to SSL_get_tlsext_status_ocsp_resp(). The value B<*resp> will be updated to | ||||||
| to the OCSP response data and the return value will be the length of that data. | point to the OCSP response data and the return value will be the length of that | ||||||
| Typically a callback would obtain an OCSP_RESPONSE object from this data via a | data. Typically a callback would obtain an OCSP_RESPONSE object from this data | ||||||
| call to the d2i_OCSP_RESPONSE() function. If the server has not provided any | via a call to the d2i_OCSP_RESPONSE() function. If the server has not provided | ||||||
| response data then B<*resp> will be NULL and the return value from | any response data then B<*resp> will be NULL and the return value from | ||||||
| SSL_get_tlsext_status_ocsp_resp() will be -1. | SSL_get_tlsext_status_ocsp_resp() will be -1. | ||||||
| 
 | 
 | ||||||
|  | A server application must also call the SSL_CTX_set_tlsext_status_cb() function | ||||||
|  | if it wants to be able to provide clients with (single) OCSP response for the | ||||||
|  | server certificate. Typically the server callback would obtain the server | ||||||
|  | certificate that is being sent back to the client via a call to | ||||||
|  | SSL_get_certificate(); retrieve the related OCSP response to be sent back; and | ||||||
|  | then set that response data by calling SSL_set_tlsext_status_ocsp_resp(). A | ||||||
|  | pointer to the response data should be provided in the B<resp> argument, and | ||||||
|  | the length of that data should be in the B<len> argument. | ||||||
|  | 
 | ||||||
|  | In the case of multi-stapling the responses to be returned by the server can be | ||||||
|  | obtained via a call to SSL_get0_tlsext_status_ocsp_resp_ex(). The value B<*resp> | ||||||
|  | will be updated to point to the OCSP response stack and the return value will | ||||||
|  | be the number of responses on the stack. | ||||||
|  | The OCSP responses on the stack are expected to be in the same order as the | ||||||
|  | certificates in the chain. If no OCSP response is available for a certificate | ||||||
|  | in the chain, a NULL element in the stack will represent this. | ||||||
|  | Typically a callback would obtain an OCSP_RESPONSE object from the stack via a | ||||||
|  | call to sk_OCSP_RESPONSE_pop. If the server has not provided any response data | ||||||
|  | then B<*resp> will be NULL and the return value from | ||||||
|  | SSL_get0_tlsext_status_ocsp_resp_ex() will be -1. | ||||||
|  | 
 | ||||||
| A server application must also call the SSL_CTX_set_tlsext_status_cb() function | A server application must also call the SSL_CTX_set_tlsext_status_cb() function | ||||||
| if it wants to be able to provide clients with OCSP Certificate Status | if it wants to be able to provide clients with OCSP Certificate Status | ||||||
| responses. Typically the server callback would obtain the server certificate | responses, where TLS 1.3 allows for multi-stapling, i.e., providing responses | ||||||
| that is being sent back to the client via a call to SSL_get_certificate(); | for all certificates in the chain of the server certificate (excluding the root | ||||||
| obtain the OCSP response to be sent back; and then set that response data by | CA certificate). | ||||||
| calling SSL_set_tlsext_status_ocsp_resp(). A pointer to the response data should | The certificates sent back to the client and for which OCSP response(s) | ||||||
| be provided in the B<resp> argument, and the length of that data should be in | should be acquired could be obtained via call to SSL_get_certificate() resp. | ||||||
| the B<len> argument. | SSL_get0_chain_certs(). OCSP response(s) then set by calling | ||||||
|  | SSL_set0_tlsext_status_ocsp_resp_ex(). A stack of OCSP responses should be | ||||||
|  | provided in the B<resp> argument. | ||||||
|  | The OCSP responses on the stack are expected to be in the same order as the | ||||||
|  | certificate in the chain. If no OCSP response is available for a certificate in | ||||||
|  | the chain, a NULL element in the stack will represent this. | ||||||
| 
 | 
 | ||||||
| =head1 RETURN VALUES | =head1 RETURN VALUES | ||||||
| 
 | 
 | ||||||
|  | @ -93,8 +128,9 @@ returned) or SSL_TLSEXT_ERR_ALERT_FATAL (meaning that a fatal error has | ||||||
| occurred). | occurred). | ||||||
| 
 | 
 | ||||||
| SSL_CTX_set_tlsext_status_cb(), SSL_CTX_set_tlsext_status_arg(), | SSL_CTX_set_tlsext_status_cb(), SSL_CTX_set_tlsext_status_arg(), | ||||||
| SSL_CTX_set_tlsext_status_type(), SSL_set_tlsext_status_type() and | SSL_CTX_set_tlsext_status_type(), SSL_set_tlsext_status_type(), | ||||||
| SSL_set_tlsext_status_ocsp_resp() return 0 on error or 1 on success. | SSL_set_tlsext_status_ocsp_resp() return 0 on error or 1 on success. | ||||||
|  | SSL_set0_tlsext_status_ocsp_resp_ex() will return always 1. | ||||||
| 
 | 
 | ||||||
| SSL_CTX_get_tlsext_status_type() returns the value previously set by | SSL_CTX_get_tlsext_status_type() returns the value previously set by | ||||||
| SSL_CTX_set_tlsext_status_type(), or -1 if not set. | SSL_CTX_set_tlsext_status_type(), or -1 if not set. | ||||||
|  | @ -102,6 +138,9 @@ SSL_CTX_set_tlsext_status_type(), or -1 if not set. | ||||||
| SSL_get_tlsext_status_ocsp_resp() returns the length of the OCSP response data | SSL_get_tlsext_status_ocsp_resp() returns the length of the OCSP response data | ||||||
| or -1 if there is no OCSP response data. | or -1 if there is no OCSP response data. | ||||||
| 
 | 
 | ||||||
|  | SSL_get0_tlsext_status_ocsp_resp_ex() returns the number of the OCSP responses | ||||||
|  | on the stack or -1 if there is no OCSP response data. | ||||||
|  | 
 | ||||||
| SSL_get_tlsext_status_type() returns B<TLSEXT_STATUSTYPE_ocsp> on the client | SSL_get_tlsext_status_type() returns B<TLSEXT_STATUSTYPE_ocsp> on the client | ||||||
| side if SSL_set_tlsext_status_type() was previously called, or on the server | side if SSL_set_tlsext_status_type() was previously called, or on the server | ||||||
| side if the client requested OCSP stapling. Otherwise -1 is returned. | side if the client requested OCSP stapling. Otherwise -1 is returned. | ||||||
|  | @ -115,6 +154,9 @@ L<ssl(7)> | ||||||
| The SSL_get_tlsext_status_type(), SSL_CTX_get_tlsext_status_type() | The SSL_get_tlsext_status_type(), SSL_CTX_get_tlsext_status_type() | ||||||
| and SSL_CTX_set_tlsext_status_type() functions were added in OpenSSL 1.1.0. | and SSL_CTX_set_tlsext_status_type() functions were added in OpenSSL 1.1.0. | ||||||
| 
 | 
 | ||||||
|  | The SSL_get0_tlsext_status_ocsp_resp_ex() and SSL_set0_tlsext_status_ocsp_resp_ex() | ||||||
|  | macros were added in OpenSSL 3.6. | ||||||
|  | 
 | ||||||
| =head1 COPYRIGHT | =head1 COPYRIGHT | ||||||
| 
 | 
 | ||||||
| Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. | Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. | ||||||
|  |  | ||||||
|  | @ -440,6 +440,32 @@ Returned by the verify callback to indicate OCSP verification failed. | ||||||
| Returned by the verify callback to indicate that the certificate is not | Returned by the verify callback to indicate that the certificate is not | ||||||
| recognized by the OCSP responder. | recognized by the OCSP responder. | ||||||
| 
 | 
 | ||||||
|  | =item B<X509_V_ERR_OCSP_RESP_INVALID: OCSP response(s) invalid> | ||||||
|  | 
 | ||||||
|  | Returned by the verify callback to indicate that one or more OCSP | ||||||
|  | responses are invalid. | ||||||
|  | 
 | ||||||
|  | =item B<X509_V_ERR_OCSP_SIGNATURE_FAILURE: OCSP response signature failure> | ||||||
|  | 
 | ||||||
|  | Returned by the verify callback to indicate OCSP response signature | ||||||
|  | verification failed. | ||||||
|  | 
 | ||||||
|  | =item B<X509_V_ERR_OCSP_NOT_YET_VALID: OCSP response not yet valid> | ||||||
|  | OCSP response not yet valid (contains a date in the future)> | ||||||
|  | 
 | ||||||
|  | Returned by the verify callback to indicate that OCSP response has a | ||||||
|  | I<thisUpdate> date in the future. | ||||||
|  | 
 | ||||||
|  | =item B<X509_V_ERR_OCSP_HAS_EXPIRED: OCSP response has expired> | ||||||
|  | 
 | ||||||
|  | Returned by the verify callback to indicate that the OCSP response has expired. | ||||||
|  | 
 | ||||||
|  | =item B<X509_V_ERR_OCSP_NO_RESPONSE: | ||||||
|  | no OCSP response available for certificate> | ||||||
|  | 
 | ||||||
|  | Returned by the verify callback to indicate that no OCSP response is available | ||||||
|  | for the certificate. | ||||||
|  | 
 | ||||||
| =item B<X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM: | =item B<X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM: | ||||||
| unsupported signature algorithm> | unsupported signature algorithm> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ X509_STORE_CTX_get0_rpk, | ||||||
| X509_STORE_CTX_set_default, | X509_STORE_CTX_set_default, | ||||||
| X509_STORE_CTX_set_verify, | X509_STORE_CTX_set_verify, | ||||||
| X509_STORE_CTX_verify_fn, | X509_STORE_CTX_verify_fn, | ||||||
|  | X509_STORE_CTX_set_ocsp_resp, | ||||||
| X509_STORE_CTX_set_purpose, | X509_STORE_CTX_set_purpose, | ||||||
| X509_STORE_CTX_set_trust, | X509_STORE_CTX_set_trust, | ||||||
| X509_STORE_CTX_purpose_inherit | X509_STORE_CTX_purpose_inherit | ||||||
|  | @ -56,6 +57,7 @@ X509_STORE_CTX_purpose_inherit | ||||||
|  typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *); |  typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *); | ||||||
|  void X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx, X509_STORE_CTX_verify_fn verify); |  void X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx, X509_STORE_CTX_verify_fn verify); | ||||||
| 
 | 
 | ||||||
|  |  void X509_STORE_CTX_set_ocsp_resp(X509_STORE_CTX *ctx, STACK_OF(OCSP_RESPONSE) *sk); | ||||||
|  int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); |  int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); | ||||||
|  int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); |  int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); | ||||||
|  int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, |  int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, | ||||||
|  | @ -217,6 +219,12 @@ validate extended key usage information in certificates will need to define a | ||||||
| custom "purpose" (see below) or supply a nondefault verification callback | custom "purpose" (see below) or supply a nondefault verification callback | ||||||
| (L<X509_STORE_set_verify_cb_func(3)>). | (L<X509_STORE_set_verify_cb_func(3)>). | ||||||
| 
 | 
 | ||||||
|  | X509_STORE_CTX_set_ocsp_resp() sets the OCSP response(s) for the verification | ||||||
|  | of a certificate chain or for including in the TLS handshake, when the client | ||||||
|  | requests OCSP stapling. The stack of OCSP responses I<sk> is not copied but | ||||||
|  | just stored to the context. | ||||||
|  | I<ctx> holds a pointer to the stack, so the stack must outlive the I<ctx>. | ||||||
|  | 
 | ||||||
| X509_STORE_CTX_set_purpose() sets the purpose for the target certificate being | X509_STORE_CTX_set_purpose() sets the purpose for the target certificate being | ||||||
| verified in the I<ctx>. Built-in available values for the I<purpose> argument | verified in the I<ctx>. Built-in available values for the I<purpose> argument | ||||||
| are B<X509_PURPOSE_SSL_CLIENT>, B<X509_PURPOSE_SSL_SERVER>, | are B<X509_PURPOSE_SSL_CLIENT>, B<X509_PURPOSE_SSL_SERVER>, | ||||||
|  | @ -314,6 +322,7 @@ The X509_STORE_CTX_get_num_untrusted() function was added in OpenSSL 1.1.0. | ||||||
| The X509_STORE_CTX_new_ex() function was added in OpenSSL 3.0. | The X509_STORE_CTX_new_ex() function was added in OpenSSL 3.0. | ||||||
| The X509_STORE_CTX_init_rpk(), X509_STORE_CTX_get0_rpk(), and | The X509_STORE_CTX_init_rpk(), X509_STORE_CTX_get0_rpk(), and | ||||||
| X509_STORE_CTX_set0_rpk() functions were added in OpenSSL 3.2. | X509_STORE_CTX_set0_rpk() functions were added in OpenSSL 3.2. | ||||||
|  | X509_STORE_CTX_set_ocsp_resp() function was added in OpenSSL 3.6. | ||||||
| 
 | 
 | ||||||
| There is no need to call X509_STORE_CTX_cleanup() explicitly since OpenSSL 3.0. | There is no need to call X509_STORE_CTX_cleanup() explicitly since OpenSSL 3.0. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -221,6 +221,7 @@ struct x509_store_ctx_st {      /* X509_STORE_CTX */ | ||||||
|     STACK_OF(X509) *untrusted; |     STACK_OF(X509) *untrusted; | ||||||
|     /* set of CRLs passed in */ |     /* set of CRLs passed in */ | ||||||
|     STACK_OF(X509_CRL) *crls; |     STACK_OF(X509_CRL) *crls; | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *ocsp_resp; | ||||||
|     X509_VERIFY_PARAM *param; |     X509_VERIFY_PARAM *param; | ||||||
|     /* Other info for use with get_issuer() */ |     /* Other info for use with get_issuer() */ | ||||||
|     void *other_ctx; |     void *other_ctx; | ||||||
|  |  | ||||||
|  | @ -1342,6 +1342,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) | ||||||
| # define SSL_CTRL_GET0_IMPLEMENTED_GROUPS        139 | # define SSL_CTRL_GET0_IMPLEMENTED_GROUPS        139 | ||||||
| # define SSL_CTRL_GET_SIGNATURE_NAME             140 | # define SSL_CTRL_GET_SIGNATURE_NAME             140 | ||||||
| # define SSL_CTRL_GET_PEER_SIGNATURE_NAME        141 | # define SSL_CTRL_GET_PEER_SIGNATURE_NAME        141 | ||||||
|  | # define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP_EX        142 | ||||||
|  | # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP_EX        143 | ||||||
| # define SSL_CERT_SET_FIRST                      1 | # define SSL_CERT_SET_FIRST                      1 | ||||||
| # define SSL_CERT_SET_NEXT                       2 | # define SSL_CERT_SET_NEXT                       2 | ||||||
| # define SSL_CERT_SET_SERVER                     3 | # define SSL_CERT_SET_SERVER                     3 | ||||||
|  |  | ||||||
|  | @ -325,6 +325,12 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) | ||||||
| # define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ | # define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ | ||||||
|         SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen,arg) |         SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen,arg) | ||||||
| 
 | 
 | ||||||
|  | # define SSL_get0_tlsext_status_ocsp_resp_ex(ssl, arg) \ | ||||||
|  |     SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP_EX, 0, arg) | ||||||
|  | 
 | ||||||
|  | # define SSL_set0_tlsext_status_ocsp_resp_ex(ssl, arg) \ | ||||||
|  |     SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP_EX, 0, arg) | ||||||
|  | 
 | ||||||
| # define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ | # define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ | ||||||
|         SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,\ |         SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,\ | ||||||
|                 (void (*)(void))cb) |                 (void (*)(void))cb) | ||||||
|  |  | ||||||
|  | @ -39,6 +39,8 @@ use OpenSSL::stackhash qw(generate_stack_macros); | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | DEFINE_STACK_OF(OCSP_RESPONSE) | ||||||
|  | 
 | ||||||
| /*-
 | /*-
 | ||||||
| SSL_CTX -> X509_STORE | SSL_CTX -> X509_STORE | ||||||
|                 -> X509_LOOKUP |                 -> X509_LOOKUP | ||||||
|  | @ -316,6 +318,14 @@ X509_LOOKUP_ctrl_ex((x), X509_L_ADD_STORE, (name), 0, NULL,           \ | ||||||
| # define X509_V_ERR_EC_KEY_EXPLICIT_PARAMS               94 | # define X509_V_ERR_EC_KEY_EXPLICIT_PARAMS               94 | ||||||
| # define X509_V_ERR_RPK_UNTRUSTED                        95 | # define X509_V_ERR_RPK_UNTRUSTED                        95 | ||||||
| 
 | 
 | ||||||
|  | /* additional OCSP status errors */ | ||||||
|  | # define X509_V_ERR_OCSP_RESP_INVALID                    96 | ||||||
|  | # define X509_V_ERR_OCSP_SIGNATURE_FAILURE               97 | ||||||
|  | # define X509_V_ERR_OCSP_NOT_YET_VALID                   98 | ||||||
|  | # define X509_V_ERR_OCSP_HAS_EXPIRED                     99 | ||||||
|  | # define X509_V_ERR_OCSP_NO_RESPONSE                    100 | ||||||
|  | # define X509_V_ERR_CRL_VERIFY_FAILED                   101 | ||||||
|  | 
 | ||||||
| /* Certificate verify flags */ | /* Certificate verify flags */ | ||||||
| # ifndef OPENSSL_NO_DEPRECATED_1_1_0 | # ifndef OPENSSL_NO_DEPRECATED_1_1_0 | ||||||
| #  define X509_V_FLAG_CB_ISSUER_CHECK             0x0   /* Deprecated */ | #  define X509_V_FLAG_CB_ISSUER_CHECK             0x0   /* Deprecated */ | ||||||
|  | @ -367,6 +377,11 @@ X509_LOOKUP_ctrl_ex((x), X509_L_ADD_STORE, (name), 0, NULL,           \ | ||||||
| /* Do not check certificate/CRL validity against current time */ | /* Do not check certificate/CRL validity against current time */ | ||||||
| # define X509_V_FLAG_NO_CHECK_TIME               0x200000 | # define X509_V_FLAG_NO_CHECK_TIME               0x200000 | ||||||
| 
 | 
 | ||||||
|  | /* Verify OCSP stapling response for server certificate */ | ||||||
|  | # define X509_V_FLAG_OCSP_RESP_CHECK 0x400000 | ||||||
|  | /* Verify OCSP stapling responses for whole chain */ | ||||||
|  | # define X509_V_FLAG_OCSP_RESP_CHECK_ALL 0x800000 | ||||||
|  | 
 | ||||||
| # define X509_VP_FLAG_DEFAULT                    0x1 | # define X509_VP_FLAG_DEFAULT                    0x1 | ||||||
| # define X509_VP_FLAG_OVERWRITE                  0x2 | # define X509_VP_FLAG_OVERWRITE                  0x2 | ||||||
| # define X509_VP_FLAG_RESET_FLAGS                0x4 | # define X509_VP_FLAG_RESET_FLAGS                0x4 | ||||||
|  | @ -675,6 +690,9 @@ void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *target); | ||||||
| void X509_STORE_CTX_set0_rpk(X509_STORE_CTX *ctx, EVP_PKEY *target); | void X509_STORE_CTX_set0_rpk(X509_STORE_CTX *ctx, EVP_PKEY *target); | ||||||
| void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *c, STACK_OF(X509) *sk); | void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *c, STACK_OF(X509) *sk); | ||||||
| void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk); | void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk); | ||||||
|  | # ifndef OPENSSL_NO_OCSP | ||||||
|  | void X509_STORE_CTX_set_ocsp_resp(X509_STORE_CTX *ctx, STACK_OF(OCSP_RESPONSE) *sk); | ||||||
|  | # endif | ||||||
| int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); | int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); | ||||||
| int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); | int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); | ||||||
| int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, | int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, | ||||||
|  |  | ||||||
							
								
								
									
										82
									
								
								ssl/s3_lib.c
								
								
								
								
							
							
						
						
									
										82
									
								
								ssl/s3_lib.c
								
								
								
								
							|  | @ -22,6 +22,7 @@ | ||||||
| #include <openssl/core_names.h> | #include <openssl/core_names.h> | ||||||
| #include "internal/cryptlib.h" | #include "internal/cryptlib.h" | ||||||
| #include "internal/ssl_unwrap.h" | #include "internal/ssl_unwrap.h" | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| 
 | 
 | ||||||
| #define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_ciphers) | #define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_ciphers) | ||||||
| #define SSL3_NUM_CIPHERS        OSSL_NELEM(ssl3_ciphers) | #define SSL3_NUM_CIPHERS        OSSL_NELEM(ssl3_ciphers) | ||||||
|  | @ -3534,6 +3535,10 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) | ||||||
| { | { | ||||||
|     int ret = 0; |     int ret = 0; | ||||||
|     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); |     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     unsigned char *p = NULL; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     if (sc == NULL) |     if (sc == NULL) | ||||||
|         return ret; |         return ret; | ||||||
|  | @ -3666,16 +3671,79 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: |     case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: | ||||||
|         *(unsigned char **)parg = sc->ext.ocsp.resp; |         *(unsigned char **)parg = NULL; | ||||||
|         if (sc->ext.ocsp.resp_len == 0 |         ret = -1; | ||||||
|                 || sc->ext.ocsp.resp_len > LONG_MAX) | 
 | ||||||
|             return -1; | #ifndef OPENSSL_NO_OCSP | ||||||
|         return (long)sc->ext.ocsp.resp_len; |         resp = sk_OCSP_RESPONSE_value(sc->ext.ocsp.resp_ex, 0); | ||||||
|  | 
 | ||||||
|  |         if (resp != NULL) { | ||||||
|  |             int resp_len = i2d_OCSP_RESPONSE(resp, &p); | ||||||
|  | 
 | ||||||
|  |             if (resp_len > 0) { | ||||||
|  |                 OPENSSL_free(sc->ext.ocsp.resp); | ||||||
|  |                 *(unsigned char **)parg = sc->ext.ocsp.resp = p; | ||||||
|  |                 sc->ext.ocsp.resp_len = (size_t)resp_len; | ||||||
|  |                 ret = resp_len; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |         break; | ||||||
| 
 | 
 | ||||||
|     case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: |     case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: | ||||||
|  |         ret = 1; | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |         /*
 | ||||||
|  |          * cleanup single values, which might be set somewhere else | ||||||
|  |          * we only use the extended values | ||||||
|  |          */ | ||||||
|  |         if (sc->ext.ocsp.resp != NULL) { | ||||||
|             OPENSSL_free(sc->ext.ocsp.resp); |             OPENSSL_free(sc->ext.ocsp.resp); | ||||||
|         sc->ext.ocsp.resp = parg; |             sc->ext.ocsp.resp = NULL; | ||||||
|         sc->ext.ocsp.resp_len = larg; |             sc->ext.ocsp.resp_len = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(sc->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||||
|  |         sc->ext.ocsp.resp_ex = NULL; | ||||||
|  | 
 | ||||||
|  |         if (parg != NULL) { | ||||||
|  |             sc->ext.ocsp.resp_ex = sk_OCSP_RESPONSE_new_reserve(NULL, 1); | ||||||
|  |             if (sc->ext.ocsp.resp_ex == NULL) | ||||||
|  |                 return 0; | ||||||
|  | 
 | ||||||
|  |             p = parg; | ||||||
|  |             resp = d2i_OCSP_RESPONSE(NULL, (const unsigned char **)&p, larg); | ||||||
|  |             if (resp != NULL) | ||||||
|  |                 sk_OCSP_RESPONSE_push(sc->ext.ocsp.resp_ex, resp); | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP_EX: | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |         *(STACK_OF(OCSP_RESPONSE) **)parg = sc->ext.ocsp.resp_ex; | ||||||
|  |         ret = sk_OCSP_RESPONSE_num(sc->ext.ocsp.resp_ex); | ||||||
|  | #else | ||||||
|  |         *(unsigned char **)parg = NULL; | ||||||
|  |         ret = -1; | ||||||
|  | #endif | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP_EX: | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |         /*
 | ||||||
|  |          * cleanup single values, which might be set somewhere else | ||||||
|  |          * we only use the extended values | ||||||
|  |          */ | ||||||
|  |         if (sc->ext.ocsp.resp != NULL) { | ||||||
|  |             OPENSSL_free(sc->ext.ocsp.resp); | ||||||
|  |             sc->ext.ocsp.resp = NULL; | ||||||
|  |             sc->ext.ocsp.resp_len = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(sc->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||||
|  |         sc->ext.ocsp.resp_ex = (STACK_OF(OCSP_RESPONSE) *)parg; | ||||||
|  | #endif | ||||||
|         ret = 1; |         ret = 1; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -433,6 +433,9 @@ static int ssl_verify_internal(SSL_CONNECTION *s, STACK_OF(X509) *sk, EVP_PKEY * | ||||||
|     X509_STORE_CTX *ctx = NULL; |     X509_STORE_CTX *ctx = NULL; | ||||||
|     X509_VERIFY_PARAM *param; |     X509_VERIFY_PARAM *param; | ||||||
|     SSL_CTX *sctx; |     SSL_CTX *sctx; | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     SSL *ssl; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     /* Something must be passed in */ |     /* Something must be passed in */ | ||||||
|     if ((sk == NULL || sk_X509_num(sk) == 0) && rpk == NULL) |     if ((sk == NULL || sk_X509_num(sk) == 0) && rpk == NULL) | ||||||
|  | @ -486,6 +489,26 @@ static int ssl_verify_internal(SSL_CONNECTION *s, STACK_OF(X509) *sk, EVP_PKEY * | ||||||
|     if (DANETLS_ENABLED(&s->dane)) |     if (DANETLS_ENABLED(&s->dane)) | ||||||
|         X509_STORE_CTX_set0_dane(ctx, &s->dane); |         X509_STORE_CTX_set0_dane(ctx, &s->dane); | ||||||
| 
 | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Set OCSP Responses for verification: | ||||||
|  |      * This function is called in the SERVER_CERTIFICATE message, in TLS 1.2 | ||||||
|  |      * the OCSP responses are sent in the CERT_STATUS message after that. | ||||||
|  |      * Therefore the verification code currently only works in TLS 1.3. | ||||||
|  |      */ | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     ssl = SSL_CONNECTION_GET_SSL(s); | ||||||
|  |     /*
 | ||||||
|  |      * TODO(DTLS-1.3): in future DTLS should also be considered | ||||||
|  |      */ | ||||||
|  |     if (!SSL_is_dtls(ssl) && SSL_version(ssl) >= TLS1_3_VERSION) { | ||||||
|  |         /* ignore status_request_v2 if TLS version < 1.3 */ | ||||||
|  |         int status = SSL_get_tlsext_status_type(ssl); | ||||||
|  | 
 | ||||||
|  |         if (status == TLSEXT_STATUSTYPE_ocsp) | ||||||
|  |             X509_STORE_CTX_set_ocsp_resp(ctx, s->ext.ocsp.resp_ex); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     /*
 |     /*
 | ||||||
|      * We need to inherit the verify parameters. These can be determined by |      * We need to inherit the verify parameters. These can be determined by | ||||||
|      * the context: if its a server it will verify SSL client certificates or |      * the context: if its a server it will verify SSL client certificates or | ||||||
|  |  | ||||||
|  | @ -831,6 +831,7 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, SSL *user_ssl, | ||||||
|     s->ext.ocsp.exts = NULL; |     s->ext.ocsp.exts = NULL; | ||||||
|     s->ext.ocsp.resp = NULL; |     s->ext.ocsp.resp = NULL; | ||||||
|     s->ext.ocsp.resp_len = 0; |     s->ext.ocsp.resp_len = 0; | ||||||
|  |     s->ext.ocsp.resp_ex = NULL; | ||||||
| 
 | 
 | ||||||
|     if (!SSL_CTX_up_ref(ctx)) |     if (!SSL_CTX_up_ref(ctx)) | ||||||
|         goto err; |         goto err; | ||||||
|  | @ -1497,14 +1498,20 @@ void ossl_ssl_connection_free(SSL *ssl) | ||||||
|     OPENSSL_free(s->ext.tuples); |     OPENSSL_free(s->ext.tuples); | ||||||
|     OPENSSL_free(s->ext.peer_supportedgroups); |     OPENSSL_free(s->ext.peer_supportedgroups); | ||||||
|     sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free); |     sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free); | ||||||
|  | 
 | ||||||
| #ifndef OPENSSL_NO_OCSP | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     OPENSSL_free(s->ext.ocsp.resp); | ||||||
|  |     s->ext.ocsp.resp = NULL; | ||||||
|  |     s->ext.ocsp.resp_len = 0; | ||||||
|  | 
 | ||||||
|     sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free); |     sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free); | ||||||
|  |     sk_OCSP_RESPONSE_pop_free(s->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||||
|  |     s->ext.ocsp.resp_ex = NULL; | ||||||
| #endif | #endif | ||||||
| #ifndef OPENSSL_NO_CT | #ifndef OPENSSL_NO_CT | ||||||
|     SCT_LIST_free(s->scts); |     SCT_LIST_free(s->scts); | ||||||
|     OPENSSL_free(s->ext.scts); |     OPENSSL_free(s->ext.scts); | ||||||
| #endif | #endif | ||||||
|     OPENSSL_free(s->ext.ocsp.resp); |  | ||||||
|     OPENSSL_free(s->ext.alpn); |     OPENSSL_free(s->ext.alpn); | ||||||
|     OPENSSL_free(s->ext.tls13_cookie); |     OPENSSL_free(s->ext.tls13_cookie); | ||||||
|     if (s->clienthello != NULL) |     if (s->clienthello != NULL) | ||||||
|  | @ -6428,17 +6435,17 @@ static int ct_extract_ocsp_response_scts(SSL_CONNECTION *s) | ||||||
| { | { | ||||||
| # ifndef OPENSSL_NO_OCSP | # ifndef OPENSSL_NO_OCSP | ||||||
|     int scts_extracted = 0; |     int scts_extracted = 0; | ||||||
|     const unsigned char *p; |  | ||||||
|     OCSP_BASICRESP *br = NULL; |     OCSP_BASICRESP *br = NULL; | ||||||
|     OCSP_RESPONSE *rsp = NULL; |     OCSP_RESPONSE *rsp = NULL; | ||||||
|     STACK_OF(SCT) *scts = NULL; |     STACK_OF(SCT) *scts = NULL; | ||||||
|     int i; |     int ret; | ||||||
|  |     int i, j; | ||||||
| 
 | 
 | ||||||
|     if (s->ext.ocsp.resp == NULL || s->ext.ocsp.resp_len == 0) |     if (s->ext.ocsp.resp_ex == NULL) | ||||||
|         goto err; |         goto err; | ||||||
| 
 | 
 | ||||||
|     p = s->ext.ocsp.resp; |     for (j = 0; j < sk_OCSP_RESPONSE_num(s->ext.ocsp.resp_ex); j++) { | ||||||
|     rsp = d2i_OCSP_RESPONSE(NULL, &p, (int)s->ext.ocsp.resp_len); |         rsp = sk_OCSP_RESPONSE_value(s->ext.ocsp.resp_ex, j); | ||||||
|         if (rsp == NULL) |         if (rsp == NULL) | ||||||
|             goto err; |             goto err; | ||||||
| 
 | 
 | ||||||
|  | @ -6452,17 +6459,35 @@ static int ct_extract_ocsp_response_scts(SSL_CONNECTION *s) | ||||||
|             if (single == NULL) |             if (single == NULL) | ||||||
|                 continue; |                 continue; | ||||||
| 
 | 
 | ||||||
|         scts = |             scts = OCSP_SINGLERESP_get1_ext_d2i(single, | ||||||
|             OCSP_SINGLERESP_get1_ext_d2i(single, NID_ct_cert_scts, NULL, NULL); |                                                 NID_ct_cert_scts, NULL, NULL); | ||||||
|         scts_extracted = | 
 | ||||||
|             ct_move_scts(&s->scts, scts, SCT_SOURCE_OCSP_STAPLED_RESPONSE); |             OCSP_SINGLERESP_free(single); | ||||||
|         if (scts_extracted < 0) | 
 | ||||||
|  |             if (scts == NULL)  { | ||||||
|  |                 scts_extracted = -1; | ||||||
|                 goto err; |                 goto err; | ||||||
|             } |             } | ||||||
|  err: | 
 | ||||||
|  |             ret = ct_move_scts(&s->scts, scts, | ||||||
|  |                                SCT_SOURCE_OCSP_STAPLED_RESPONSE); | ||||||
|  | 
 | ||||||
|             SCT_LIST_free(scts); |             SCT_LIST_free(scts); | ||||||
|  | 
 | ||||||
|  |             if (ret < 0) { | ||||||
|  |                 scts_extracted = -1; | ||||||
|  |                 goto err; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             scts_extracted += ret; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         OCSP_BASICRESP_free(br); | ||||||
|  |         /* to assure that is not freed twice */ | ||||||
|  |         br = NULL; | ||||||
|  |     } | ||||||
|  |  err: | ||||||
|     OCSP_BASICRESP_free(br); |     OCSP_BASICRESP_free(br); | ||||||
|     OCSP_RESPONSE_free(rsp); |  | ||||||
|     return scts_extracted; |     return scts_extracted; | ||||||
| # else | # else | ||||||
|     /* Behave as if no OCSP response exists */ |     /* Behave as if no OCSP response exists */ | ||||||
|  |  | ||||||
|  | @ -1639,6 +1639,7 @@ struct ssl_connection_st { | ||||||
|             /* OCSP response received or to be sent */ |             /* OCSP response received or to be sent */ | ||||||
|             unsigned char *resp; |             unsigned char *resp; | ||||||
|             size_t resp_len; |             size_t resp_len; | ||||||
|  |             STACK_OF(OCSP_RESPONSE) *resp_ex; | ||||||
|         } ocsp; |         } ocsp; | ||||||
| 
 | 
 | ||||||
|         /* RFC4507 session ticket expected to be received or sent */ |         /* RFC4507 session ticket expected to be received or sent */ | ||||||
|  | @ -2594,6 +2595,7 @@ void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg); | ||||||
| 
 | 
 | ||||||
| __owur int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk); | __owur int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk); | ||||||
| __owur int ssl_verify_rpk(SSL_CONNECTION *s, EVP_PKEY *rpk); | __owur int ssl_verify_rpk(SSL_CONNECTION *s, EVP_PKEY *rpk); | ||||||
|  | __owur int ssl_verify_ocsp(SSL *s, STACK_OF(X509) *sk); | ||||||
| __owur int ssl_build_cert_chain(SSL_CONNECTION *s, SSL_CTX *ctx, int flags); | __owur int ssl_build_cert_chain(SSL_CONNECTION *s, SSL_CTX *ctx, int flags); | ||||||
| __owur int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, | __owur int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, | ||||||
|                                    int ref); |                                    int ref); | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include "internal/ssl_unwrap.h" | #include "internal/ssl_unwrap.h" | ||||||
| #include "../ssl_local.h" | #include "../ssl_local.h" | ||||||
| #include "statem_local.h" | #include "statem_local.h" | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| 
 | 
 | ||||||
| static int final_renegotiate(SSL_CONNECTION *s, unsigned int context, int sent); | static int final_renegotiate(SSL_CONNECTION *s, unsigned int context, int sent); | ||||||
| static int init_server_name(SSL_CONNECTION *s, unsigned int context); | static int init_server_name(SSL_CONNECTION *s, unsigned int context); | ||||||
|  | @ -1148,6 +1149,9 @@ static int init_status_request(SSL_CONNECTION *s, unsigned int context) | ||||||
|         OPENSSL_free(s->ext.ocsp.resp); |         OPENSSL_free(s->ext.ocsp.resp); | ||||||
|         s->ext.ocsp.resp = NULL; |         s->ext.ocsp.resp = NULL; | ||||||
|         s->ext.ocsp.resp_len = 0; |         s->ext.ocsp.resp_len = 0; | ||||||
|  | 
 | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(s->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||||
|  |         s->ext.ocsp.resp_ex = NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 1; |     return 1; | ||||||
|  |  | ||||||
|  | @ -1510,14 +1510,8 @@ int tls_parse_stoc_status_request(SSL_CONNECTION *s, PACKET *pkt, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (SSL_CONNECTION_IS_TLS13(s)) { |     if (SSL_CONNECTION_IS_TLS13(s)) { | ||||||
|         /* We only know how to handle this if it's for the first Certificate in
 |  | ||||||
|          * the chain. We ignore any other responses. |  | ||||||
|          */ |  | ||||||
|         if (chainidx != 0) |  | ||||||
|             return 1; |  | ||||||
| 
 |  | ||||||
|         /* SSLfatal() already called */ |         /* SSLfatal() already called */ | ||||||
|         return tls_process_cert_status_body(s, pkt); |         return tls_process_cert_status_body(s, chainidx, pkt); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Set flag to expect CertificateStatus message */ |     /* Set flag to expect CertificateStatus message */ | ||||||
|  |  | ||||||
|  | @ -1751,9 +1751,6 @@ EXT_RETURN tls_construct_stoc_status_request(SSL_CONNECTION *s, WPACKET *pkt, | ||||||
|     if (!s->ext.status_expected) |     if (!s->ext.status_expected) | ||||||
|         return EXT_RETURN_NOT_SENT; |         return EXT_RETURN_NOT_SENT; | ||||||
| 
 | 
 | ||||||
|     if (SSL_CONNECTION_IS_TLS13(s) && chainidx != 0) |  | ||||||
|         return EXT_RETURN_NOT_SENT; |  | ||||||
| 
 |  | ||||||
|     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request) |     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request) | ||||||
|             || !WPACKET_start_sub_packet_u16(pkt)) { |             || !WPACKET_start_sub_packet_u16(pkt)) { | ||||||
|         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); |         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); | ||||||
|  | @ -1765,7 +1762,8 @@ EXT_RETURN tls_construct_stoc_status_request(SSL_CONNECTION *s, WPACKET *pkt, | ||||||
|      * send back an empty extension, with the certificate status appearing as a |      * send back an empty extension, with the certificate status appearing as a | ||||||
|      * separate message |      * separate message | ||||||
|      */ |      */ | ||||||
|     if (SSL_CONNECTION_IS_TLS13(s) && !tls_construct_cert_status_body(s, pkt)) { |     if (SSL_CONNECTION_IS_TLS13(s) | ||||||
|  |         && !tls_construct_cert_status_body(s, chainidx, pkt)) { | ||||||
|         /* SSLfatal() already called */ |         /* SSLfatal() already called */ | ||||||
|         return EXT_RETURN_FAIL; |         return EXT_RETURN_FAIL; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ | ||||||
| #include "internal/cryptlib.h" | #include "internal/cryptlib.h" | ||||||
| #include "internal/comp.h" | #include "internal/comp.h" | ||||||
| #include "internal/ssl_unwrap.h" | #include "internal/ssl_unwrap.h" | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| 
 | 
 | ||||||
| static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL_CONNECTION *s, | static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL_CONNECTION *s, | ||||||
|                                                              PACKET *pkt); |                                                              PACKET *pkt); | ||||||
|  | @ -2900,40 +2901,77 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, | ||||||
|  * In TLSv1.3 this is called from the extensions code, otherwise it is used to |  * In TLSv1.3 this is called from the extensions code, otherwise it is used to | ||||||
|  * parse a separate message. Returns 1 on success or 0 on failure |  * parse a separate message. Returns 1 on success or 0 on failure | ||||||
|  */ |  */ | ||||||
| int tls_process_cert_status_body(SSL_CONNECTION *s, PACKET *pkt) | int tls_process_cert_status_body(SSL_CONNECTION *s, size_t chainidx, PACKET *pkt) | ||||||
| { | { | ||||||
|     size_t resplen; |  | ||||||
|     unsigned int type; |     unsigned int type; | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     size_t resplen; | ||||||
|  |     unsigned char *respder; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     const unsigned char *p; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     if (!PACKET_get_1(pkt, &type) |     if (!PACKET_get_1(pkt, &type) | ||||||
|         || type != TLSEXT_STATUSTYPE_ocsp) { |         || type != TLSEXT_STATUSTYPE_ocsp) { | ||||||
|         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_UNSUPPORTED_STATUS_TYPE); |         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_UNSUPPORTED_STATUS_TYPE); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     OPENSSL_free(s->ext.ocsp.resp); | ||||||
|  |     s->ext.ocsp.resp = NULL; | ||||||
|  |     s->ext.ocsp.resp_len = 0; | ||||||
|  | 
 | ||||||
|  |     if (s->ext.ocsp.resp_ex == NULL) | ||||||
|  |         s->ext.ocsp.resp_ex = sk_OCSP_RESPONSE_new_null(); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * TODO(DTLS-1.3): in future DTLS should also be considered | ||||||
|  |      */ | ||||||
|  |     if (!SSL_CONNECTION_IS_TLS13(s) && type == TLSEXT_STATUSTYPE_ocsp) { | ||||||
|  |         sk_OCSP_RESPONSE_pop_free(s->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||||
|  |         s->ext.ocsp.resp_ex = sk_OCSP_RESPONSE_new_null(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (PACKET_remaining(pkt) > 0) { | ||||||
|         if (!PACKET_get_net_3_len(pkt, &resplen) |         if (!PACKET_get_net_3_len(pkt, &resplen) | ||||||
|             || PACKET_remaining(pkt) != resplen) { |             || PACKET_remaining(pkt) != resplen) { | ||||||
|             SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); |             SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|     s->ext.ocsp.resp = OPENSSL_malloc(resplen); | 
 | ||||||
|     if (s->ext.ocsp.resp == NULL) { |         if (resplen > 0) { | ||||||
|         s->ext.ocsp.resp_len = 0; |             respder = OPENSSL_malloc(resplen); | ||||||
|  | 
 | ||||||
|  |             if (respder == NULL) { | ||||||
|                 SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); |                 SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); | ||||||
|                 return 0; |                 return 0; | ||||||
|             } |             } | ||||||
|     s->ext.ocsp.resp_len = resplen; | 
 | ||||||
|     if (!PACKET_copy_bytes(pkt, s->ext.ocsp.resp, resplen)) { |             if (!PACKET_copy_bytes(pkt, respder, resplen)) { | ||||||
|                 SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); |                 SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); | ||||||
|  |                 OPENSSL_free(respder); | ||||||
|                 return 0; |                 return 0; | ||||||
|             } |             } | ||||||
|  |             p = respder; | ||||||
|  |             resp = d2i_OCSP_RESPONSE(NULL, &p, (long)resplen); | ||||||
|  |             OPENSSL_free(respder); | ||||||
|  |             if (resp == NULL) { | ||||||
|  |                 SSLfatal(s, TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE, | ||||||
|  |                          SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE); | ||||||
|  |                 return 0; | ||||||
|  |             } | ||||||
|  |             sk_OCSP_RESPONSE_insert(s->ext.ocsp.resp_ex, resp, (int)chainidx); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  | #endif | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| MSG_PROCESS_RETURN tls_process_cert_status(SSL_CONNECTION *s, PACKET *pkt) | MSG_PROCESS_RETURN tls_process_cert_status(SSL_CONNECTION *s, PACKET *pkt) | ||||||
| { | { | ||||||
|     if (!tls_process_cert_status_body(s, pkt)) { |     if (!tls_process_cert_status_body(s, 0, pkt)) { | ||||||
|         /* SSLfatal() already called */ |         /* SSLfatal() already called */ | ||||||
|         return MSG_PROCESS_ERROR; |         return MSG_PROCESS_ERROR; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -148,7 +148,7 @@ __owur MSG_PROCESS_RETURN tls_process_certificate_request(SSL_CONNECTION *s, | ||||||
|                                                           PACKET *pkt); |                                                           PACKET *pkt); | ||||||
| __owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, | __owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, | ||||||
|                                                          PACKET *pkt); |                                                          PACKET *pkt); | ||||||
| __owur int tls_process_cert_status_body(SSL_CONNECTION *s, PACKET *pkt); | __owur int tls_process_cert_status_body(SSL_CONNECTION *s, size_t chainidx, PACKET *pkt); | ||||||
| __owur MSG_PROCESS_RETURN tls_process_cert_status(SSL_CONNECTION *s, | __owur MSG_PROCESS_RETURN tls_process_cert_status(SSL_CONNECTION *s, | ||||||
|                                                   PACKET *pkt); |                                                   PACKET *pkt); | ||||||
| __owur MSG_PROCESS_RETURN tls_process_server_done(SSL_CONNECTION *s, | __owur MSG_PROCESS_RETURN tls_process_server_done(SSL_CONNECTION *s, | ||||||
|  | @ -168,7 +168,7 @@ __owur int ssl_do_client_cert_cb(SSL_CONNECTION *s, X509 **px509, | ||||||
| __owur CON_FUNC_RETURN tls_construct_client_key_exchange(SSL_CONNECTION *s, | __owur CON_FUNC_RETURN tls_construct_client_key_exchange(SSL_CONNECTION *s, | ||||||
|                                                          WPACKET *pkt); |                                                          WPACKET *pkt); | ||||||
| __owur int tls_client_key_exchange_post_work(SSL_CONNECTION *s); | __owur int tls_client_key_exchange_post_work(SSL_CONNECTION *s); | ||||||
| __owur int tls_construct_cert_status_body(SSL_CONNECTION *s, WPACKET *pkt); | __owur int tls_construct_cert_status_body(SSL_CONNECTION *s, size_t chainidx, WPACKET *pkt); | ||||||
| __owur CON_FUNC_RETURN tls_construct_cert_status(SSL_CONNECTION *s, | __owur CON_FUNC_RETURN tls_construct_cert_status(SSL_CONNECTION *s, | ||||||
|                                                  WPACKET *pkt); |                                                  WPACKET *pkt); | ||||||
| __owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL_CONNECTION *s, | __owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL_CONNECTION *s, | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
| #include <openssl/asn1t.h> | #include <openssl/asn1t.h> | ||||||
| #include <openssl/comp.h> | #include <openssl/comp.h> | ||||||
| #include "internal/comp.h" | #include "internal/comp.h" | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| 
 | 
 | ||||||
| #define TICKET_NONCE_SIZE       8 | #define TICKET_NONCE_SIZE       8 | ||||||
| 
 | 
 | ||||||
|  | @ -2193,8 +2194,11 @@ static int tls_handle_status_request(SSL_CONNECTION *s) | ||||||
|                 break; |                 break; | ||||||
|                 /* status request response should be sent */ |                 /* status request response should be sent */ | ||||||
|             case SSL_TLSEXT_ERR_OK: |             case SSL_TLSEXT_ERR_OK: | ||||||
|                 if (s->ext.ocsp.resp) | #ifndef OPENSSL_NO_OCSP | ||||||
|  |                 if (s->ext.ocsp.resp_ex != NULL | ||||||
|  |                         && sk_OCSP_RESPONSE_num(s->ext.ocsp.resp_ex) > 0) | ||||||
|                     s->ext.status_expected = 1; |                     s->ext.status_expected = 1; | ||||||
|  | #endif | ||||||
|                 break; |                 break; | ||||||
|                 /* something bad happened */ |                 /* something bad happened */ | ||||||
|             case SSL_TLSEXT_ERR_ALERT_FATAL: |             case SSL_TLSEXT_ERR_ALERT_FATAL: | ||||||
|  | @ -2298,6 +2302,7 @@ WORK_STATE tls_post_process_client_hello(SSL_CONNECTION *s, WORK_STATE wst) | ||||||
| 
 | 
 | ||||||
|     if (wst == WORK_MORE_A) { |     if (wst == WORK_MORE_A) { | ||||||
|         int rv = tls_early_post_process_client_hello(s); |         int rv = tls_early_post_process_client_hello(s); | ||||||
|  | 
 | ||||||
|         if (rv == 0) { |         if (rv == 0) { | ||||||
|             /* SSLfatal() was already called */ |             /* SSLfatal() was already called */ | ||||||
|             goto err; |             goto err; | ||||||
|  | @ -4327,21 +4332,149 @@ CON_FUNC_RETURN tls_construct_new_session_ticket(SSL_CONNECTION *s, WPACKET *pkt | ||||||
|  * In TLSv1.3 this is called from the extensions code, otherwise it is used to |  * In TLSv1.3 this is called from the extensions code, otherwise it is used to | ||||||
|  * create a separate message. Returns 1 on success or 0 on failure. |  * create a separate message. Returns 1 on success or 0 on failure. | ||||||
|  */ |  */ | ||||||
| int tls_construct_cert_status_body(SSL_CONNECTION *s, WPACKET *pkt) | int tls_construct_cert_status_body(SSL_CONNECTION *s, size_t chainidx, WPACKET *pkt) | ||||||
| { | { | ||||||
|     if (!WPACKET_put_bytes_u8(pkt, s->ext.status_type) |     unsigned char *respder = NULL; | ||||||
|             || !WPACKET_sub_memcpy_u24(pkt, s->ext.ocsp.resp, |     int resplen = 0; | ||||||
|                                        s->ext.ocsp.resp_len)) { | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     int i = 0, num = 0; | ||||||
|  |     unsigned int len; | ||||||
|  |     X509 *x = NULL; | ||||||
|  |     STACK_OF(X509) *chain_certs = NULL; | ||||||
|  |     SSL *ssl = SSL_CONNECTION_GET_SSL(s); | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     OCSP_BASICRESP *bs = NULL; | ||||||
|  |     OCSP_SINGLERESP *sr = NULL; | ||||||
|  |     OCSP_CERTID *cid = NULL; | ||||||
|  |     OCSP_CERTID *sr_cert_id = NULL; | ||||||
|  |     ASN1_OBJECT *cert_id_md_oid; | ||||||
|  |     const EVP_MD *cert_id_md; | ||||||
|  |     ASN1_INTEGER *respSerial; | ||||||
|  |     ASN1_OCTET_STRING *respIssuerNameHash; | ||||||
|  |     ASN1_OCTET_STRING *certIssuerNameHash; | ||||||
|  |     const X509_NAME *certIssuerName; | ||||||
|  |     unsigned char md[EVP_MAX_MD_SIZE]; | ||||||
|  |     const ASN1_INTEGER *certSerial; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     if (!WPACKET_put_bytes_u8(pkt, s->ext.status_type)) { | ||||||
|         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); |         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |     /*
 | ||||||
|  |      * In TLSv1.3 the caller gives the index of the certificate for which the | ||||||
|  |      * status message should be created. | ||||||
|  |      * Prior to TLSv1.3 the chain index is 0 and the body should contain only | ||||||
|  |      * the status of the server certificate itself. | ||||||
|  |      */ | ||||||
|  |     SSL_get0_chain_certs(ssl, &chain_certs); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * if the certificate chain was built, get the status message for the | ||||||
|  |      * requested certificate specified by chainidx  SSL_get0_chain_certs | ||||||
|  |      * contains certificate chain except the server cert | ||||||
|  |      * | ||||||
|  |      * if chainidx = 0 the server certificate is requested | ||||||
|  |      * if chainidx > 0 an intermediate certificate is requested | ||||||
|  |      */ | ||||||
|  |     if (chain_certs != NULL && (int)chainidx <= sk_X509_num(chain_certs) && chainidx > 0) | ||||||
|  |         x = sk_X509_value(chain_certs, (int)chainidx - 1); | ||||||
|  |     else | ||||||
|  |         x = SSL_get_certificate(ssl); | ||||||
|  |     if (x == NULL) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     /* for a selfsigned certificate there will be no OCSP response */ | ||||||
|  |     if (X509_self_signed(x, 0)) | ||||||
|  |         return 1; | ||||||
|  | 
 | ||||||
|  |     if ((resp = sk_OCSP_RESPONSE_value(s->ext.ocsp.resp_ex, (int)chainidx)) != NULL) { | ||||||
|  |         /*
 | ||||||
|  |          * check if its the right response in the case it is a successful response | ||||||
|  |          * as not every time the issuer certificate is available the check just | ||||||
|  |          * uses the issuer name and the serial number from the current certificate | ||||||
|  |          */ | ||||||
|  |         if (OCSP_response_status(resp) == OCSP_RESPONSE_STATUS_SUCCESSFUL) { | ||||||
|  |             /*
 | ||||||
|  |              * set a mark for the error queue her to be able to ignore errors | ||||||
|  |              * happening because of test cases | ||||||
|  |              */ | ||||||
|  |             ERR_set_mark(); | ||||||
|  |             if (((bs = OCSP_response_get1_basic(resp)) != NULL) | ||||||
|  |                 && ((sr = OCSP_resp_get0(bs, 0)) != NULL)) { | ||||||
|  |                 /* use the first single response to get the algorithm used */ | ||||||
|  |                 cid = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); | ||||||
|  | 
 | ||||||
|  |                 OCSP_id_get0_info(&respIssuerNameHash, &cert_id_md_oid, NULL, &respSerial, cid); | ||||||
|  |                 if (cert_id_md_oid != NULL) | ||||||
|  |                     cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); | ||||||
|  |                 else | ||||||
|  |                     cert_id_md = EVP_sha1(); | ||||||
|  | 
 | ||||||
|  |                 /* get serial number and issuer name hash of the certificate from the chain */ | ||||||
|  |                 certSerial = X509_get0_serialNumber(x); | ||||||
|  |                 certIssuerName = X509_get_issuer_name(x); | ||||||
|  |                 certIssuerNameHash = ASN1_OCTET_STRING_new(); | ||||||
|  |                 if (!X509_NAME_digest(certIssuerName, cert_id_md, md, &len) || | ||||||
|  |                     !(ASN1_OCTET_STRING_set(certIssuerNameHash, md, len))) { | ||||||
|  |                     ASN1_OCTET_STRING_free(certIssuerNameHash); | ||||||
|  |                     OCSP_BASICRESP_free(bs); | ||||||
|  |                     ERR_clear_last_mark(); | ||||||
|  |                     return 0; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 num = OCSP_resp_count(bs); | ||||||
|  |                 for (i = 0; i < num; i++) { | ||||||
|  |                     sr = OCSP_resp_get0(bs, i); | ||||||
|  | 
 | ||||||
|  |                     /* determine the md algorithm which was used to create cert id */ | ||||||
|  |                     sr_cert_id = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); | ||||||
|  | 
 | ||||||
|  |                     OCSP_id_get0_info(&respIssuerNameHash, NULL, NULL, &respSerial, sr_cert_id); | ||||||
|  | 
 | ||||||
|  |                     if (!ASN1_INTEGER_cmp(certSerial, respSerial) && | ||||||
|  |                         !ASN1_OCTET_STRING_cmp(certIssuerNameHash, respIssuerNameHash)) | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 ASN1_OCTET_STRING_free(certIssuerNameHash); | ||||||
|  |                 OCSP_BASICRESP_free(bs); | ||||||
|  | 
 | ||||||
|  |                 /*
 | ||||||
|  |                  * if we did not find the right single response in the OCSP response we | ||||||
|  |                  * construct an empty message | ||||||
|  |                  */ | ||||||
|  |                 if (i == num) | ||||||
|  |                     resp = NULL; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /*
 | ||||||
|  |              * in a test case a response without a basic response is used the error set | ||||||
|  |              * could be ignored here | ||||||
|  |              */ | ||||||
|  |             ERR_pop_to_mark(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (resp != NULL) | ||||||
|  |         resplen = i2d_OCSP_RESPONSE(resp, &respder); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     if (!WPACKET_sub_memcpy_u24(pkt, respder, resplen)) { | ||||||
|  |         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); | ||||||
|  |         OPENSSL_free(respder); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     OPENSSL_free(respder); | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CON_FUNC_RETURN tls_construct_cert_status(SSL_CONNECTION *s, WPACKET *pkt) | CON_FUNC_RETURN tls_construct_cert_status(SSL_CONNECTION *s, WPACKET *pkt) | ||||||
| { | { | ||||||
|     if (!tls_construct_cert_status_body(s, pkt)) { |     if (!tls_construct_cert_status_body(s, 0, pkt)) { | ||||||
|         /* SSLfatal() already called */ |         /* SSLfatal() already called */ | ||||||
|         return CON_FUNC_ERROR; |         return CON_FUNC_ERROR; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include <openssl/x509_vfy.h> | #include <openssl/x509_vfy.h> | ||||||
| #include <openssl/ssl.h> | #include <openssl/ssl.h> | ||||||
| #include <openssl/core_names.h> | #include <openssl/core_names.h> | ||||||
|  | #include <openssl/ocsp.h> | ||||||
| 
 | 
 | ||||||
| #include "../../ssl/ssl_local.h" | #include "../../ssl/ssl_local.h" | ||||||
| #include "internal/ssl_unwrap.h" | #include "internal/ssl_unwrap.h" | ||||||
|  | @ -265,47 +266,100 @@ static int client_hello_nov12_cb(SSL *s, int *al, void *arg) | ||||||
|     return SSL_CLIENT_HELLO_SUCCESS; |     return SSL_CLIENT_HELLO_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static unsigned char dummy_ocsp_resp_good_val = 0xff; | #ifndef OPENSSL_NO_OCSP | ||||||
| static unsigned char dummy_ocsp_resp_bad_val = 0xfe; | static OCSP_RESPONSE *dummy_ocsp_resp = NULL; | ||||||
|  | static STACK_OF(OCSP_RESPONSE) *dummy_sk_resp = NULL; | ||||||
| 
 | 
 | ||||||
| static int server_ocsp_cb(SSL *s, void *arg) | static int server_ocsp_cb(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     unsigned char *resp; |     unsigned char *respder = NULL; | ||||||
|  |     int resplen = 0; | ||||||
|  | 
 | ||||||
|  |     resplen = i2d_OCSP_RESPONSE(arg, &respder); | ||||||
| 
 | 
 | ||||||
|     resp = OPENSSL_malloc(1); |  | ||||||
|     if (resp == NULL) |  | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |  | ||||||
|     /*
 |     /*
 | ||||||
|      * For the purposes of testing we just send back a dummy OCSP response |      * For the purposes of testing we just send back a dummy OCSP response | ||||||
|      */ |      */ | ||||||
|     *resp = *(unsigned char *)arg; |     if (!SSL_set_tlsext_status_ocsp_resp(s, respder, resplen)) { | ||||||
|     if (!SSL_set_tlsext_status_ocsp_resp(s, resp, 1)) { |         OPENSSL_free(respder); | ||||||
|         OPENSSL_free(resp); |  | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     OPENSSL_free(respder); | ||||||
|  | 
 | ||||||
|  |     return SSL_TLSEXT_ERR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int server_ocsp_cb_ext(SSL *s, void *arg) | ||||||
|  | { | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * For the purposes of testing we just send back a dummy OCSP response | ||||||
|  |      */ | ||||||
|  |     sk_resp = (STACK_OF(OCSP_RESPONSE) *)arg; | ||||||
|  |     if (!SSL_set0_tlsext_status_ocsp_resp_ex(s, sk_resp)) | ||||||
|  |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  | 
 | ||||||
|     return SSL_TLSEXT_ERR_OK; |     return SSL_TLSEXT_ERR_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int client_ocsp_cb(SSL *s, void *arg) | static int client_ocsp_cb(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     const unsigned char *resp; |     const unsigned char *resp, *p; | ||||||
|     int len; |     OCSP_RESPONSE *rsp; | ||||||
|  |     int len, status; | ||||||
| 
 | 
 | ||||||
|     len = SSL_get_tlsext_status_ocsp_resp(s, &resp); |     len = SSL_get_tlsext_status_ocsp_resp(s, &resp); | ||||||
|     if (len != 1 || *resp != dummy_ocsp_resp_good_val) |  | ||||||
|         return 0; |  | ||||||
| 
 | 
 | ||||||
|     return 1; |     p = resp; | ||||||
|  |     rsp = d2i_OCSP_RESPONSE(NULL, &p, len); | ||||||
|  | 
 | ||||||
|  |     status = OCSP_response_status(rsp); | ||||||
|  | 
 | ||||||
|  |     OCSP_RESPONSE_free(rsp); | ||||||
|  |     SSL_set_tlsext_status_ocsp_resp(s, NULL, 0); | ||||||
|  | 
 | ||||||
|  |     OCSP_RESPONSE_free(dummy_ocsp_resp); | ||||||
|  | 
 | ||||||
|  |     return status == OCSP_RESPONSE_STATUS_SUCCESSFUL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int verify_reject_cb(X509_STORE_CTX *ctx, void *arg) { | static int client_ocsp_cb_ext(SSL *s, void *arg) | ||||||
|  | { | ||||||
|  |     int len, status; | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|  |     OCSP_RESPONSE *rsp; | ||||||
|  | 
 | ||||||
|  |     SSL_get0_tlsext_status_ocsp_resp_ex(s, &sk_resp); | ||||||
|  | 
 | ||||||
|  |     if (sk_resp == NULL) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     len = sk_OCSP_RESPONSE_num(sk_resp); | ||||||
|  | 
 | ||||||
|  |     if (len != 1) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     rsp = sk_OCSP_RESPONSE_value(sk_resp, 0); | ||||||
|  | 
 | ||||||
|  |     status = OCSP_response_status(rsp); | ||||||
|  | 
 | ||||||
|  |     SSL_set0_tlsext_status_ocsp_resp_ex(s, NULL); | ||||||
|  | 
 | ||||||
|  |     return status == OCSP_RESPONSE_STATUS_SUCCESSFUL; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static int verify_reject_cb(X509_STORE_CTX *ctx, void *arg) | ||||||
|  | { | ||||||
|     X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); |     X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int n_retries = 0; | static int n_retries = 0; | ||||||
| static int verify_retry_cb(X509_STORE_CTX *ctx, void *arg) { | static int verify_retry_cb(X509_STORE_CTX *ctx, void *arg) | ||||||
|  | { | ||||||
|     int idx = SSL_get_ex_data_X509_STORE_CTX_idx(); |     int idx = SSL_get_ex_data_X509_STORE_CTX_idx(); | ||||||
|     SSL *ssl; |     SSL *ssl; | ||||||
| 
 | 
 | ||||||
|  | @ -320,7 +374,8 @@ static int verify_retry_cb(X509_STORE_CTX *ctx, void *arg) { | ||||||
|     return SSL_set_retry_verify(ssl); |     return SSL_set_retry_verify(ssl); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int verify_accept_cb(X509_STORE_CTX *ctx, void *arg) { | static int verify_accept_cb(X509_STORE_CTX *ctx, void *arg) | ||||||
|  | { | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -566,13 +621,67 @@ static int configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) { |     if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) { | ||||||
|  | 
 | ||||||
|         SSL_CTX_set_tlsext_status_type(client_ctx, TLSEXT_STATUSTYPE_ocsp); |         SSL_CTX_set_tlsext_status_type(client_ctx, TLSEXT_STATUSTYPE_ocsp); | ||||||
|         SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb); |  | ||||||
|         SSL_CTX_set_tlsext_status_arg(client_ctx, NULL); |         SSL_CTX_set_tlsext_status_arg(client_ctx, NULL); | ||||||
|  | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  |         switch (extra->server.cert_status) { | ||||||
|  |         case SSL_TEST_CERT_STATUS_GOOD_RESPONSE: | ||||||
|  | 
 | ||||||
|  |             dummy_ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, NULL); | ||||||
|  | 
 | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb); | ||||||
|             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb); |             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb); | ||||||
|         SSL_CTX_set_tlsext_status_arg(server_ctx, |             SSL_CTX_set_tlsext_status_arg(server_ctx, dummy_ocsp_resp); | ||||||
|             ((extra->server.cert_status == SSL_TEST_CERT_STATUS_GOOD_RESPONSE) | 
 | ||||||
|             ? &dummy_ocsp_resp_good_val : &dummy_ocsp_resp_bad_val)); |             break; | ||||||
|  | 
 | ||||||
|  |         case SSL_TEST_CERT_STATUS_BAD_RESPONSE: | ||||||
|  | 
 | ||||||
|  |             dummy_ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, NULL); | ||||||
|  | 
 | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb); | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb); | ||||||
|  |             SSL_CTX_set_tlsext_status_arg(server_ctx, dummy_ocsp_resp); | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case SSL_TEST_CERT_STATUS_GOOD_RESPONSE_EXT: | ||||||
|  | 
 | ||||||
|  |             dummy_sk_resp = sk_OCSP_RESPONSE_new_null(); | ||||||
|  |             dummy_ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, NULL); | ||||||
|  |             sk_OCSP_RESPONSE_push(dummy_sk_resp, dummy_ocsp_resp); | ||||||
|  | 
 | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb_ext); | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb_ext); | ||||||
|  |             SSL_CTX_set_tlsext_status_arg(server_ctx, dummy_sk_resp); | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case SSL_TEST_CERT_STATUS_BAD_RESPONSE_EXT: | ||||||
|  | 
 | ||||||
|  |             dummy_sk_resp = sk_OCSP_RESPONSE_new_null(); | ||||||
|  |             dummy_ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, NULL); | ||||||
|  |             sk_OCSP_RESPONSE_push(dummy_sk_resp, dummy_ocsp_resp); | ||||||
|  | 
 | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb_ext); | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb_ext); | ||||||
|  |             SSL_CTX_set_tlsext_status_arg(server_ctx, dummy_sk_resp); | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  | 
 | ||||||
|  |             dummy_ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, NULL); | ||||||
|  | 
 | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb); | ||||||
|  |             SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb); | ||||||
|  |             SSL_CTX_set_tlsext_status_arg(server_ctx, &dummy_ocsp_resp); | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /*
 |     /*
 | ||||||
|  |  | ||||||
|  | @ -460,7 +460,9 @@ IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, enable_server_sctp_label_bug) | ||||||
| static const test_enum ssl_certstatus[] = { | static const test_enum ssl_certstatus[] = { | ||||||
|     {"None", SSL_TEST_CERT_STATUS_NONE}, |     {"None", SSL_TEST_CERT_STATUS_NONE}, | ||||||
|     {"GoodResponse", SSL_TEST_CERT_STATUS_GOOD_RESPONSE}, |     {"GoodResponse", SSL_TEST_CERT_STATUS_GOOD_RESPONSE}, | ||||||
|     {"BadResponse", SSL_TEST_CERT_STATUS_BAD_RESPONSE} |     {"BadResponse", SSL_TEST_CERT_STATUS_BAD_RESPONSE}, | ||||||
|  |     {"GoodResponseExt", SSL_TEST_CERT_STATUS_GOOD_RESPONSE_EXT}, | ||||||
|  |     {"BadResponseExt", SSL_TEST_CERT_STATUS_BAD_RESPONSE_EXT} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| __owur static int parse_certstatus(SSL_TEST_SERVER_CONF *server_conf, | __owur static int parse_certstatus(SSL_TEST_SERVER_CONF *server_conf, | ||||||
|  |  | ||||||
|  | @ -88,7 +88,9 @@ typedef enum { | ||||||
| typedef enum { | typedef enum { | ||||||
|     SSL_TEST_CERT_STATUS_NONE = 0, /* Default */ |     SSL_TEST_CERT_STATUS_NONE = 0, /* Default */ | ||||||
|     SSL_TEST_CERT_STATUS_GOOD_RESPONSE, |     SSL_TEST_CERT_STATUS_GOOD_RESPONSE, | ||||||
|     SSL_TEST_CERT_STATUS_BAD_RESPONSE |     SSL_TEST_CERT_STATUS_BAD_RESPONSE, | ||||||
|  |     SSL_TEST_CERT_STATUS_GOOD_RESPONSE_EXT, | ||||||
|  |     SSL_TEST_CERT_STATUS_BAD_RESPONSE_EXT | ||||||
| } ssl_cert_status_t; | } ssl_cert_status_t; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -1,9 +1,11 @@ | ||||||
| # Generated with generate_ssl_tests.pl | # Generated with generate_ssl_tests.pl | ||||||
| 
 | 
 | ||||||
| num_tests = 2 | num_tests = 4 | ||||||
| 
 | 
 | ||||||
| test-0 = 0-certstatus-good | test-0 = 0-certstatus-good | ||||||
| test-1 = 1-certstatus-bad | test-1 = 1-certstatus-bad | ||||||
|  | test-2 = 2-certstatus-good-ext | ||||||
|  | test-3 = 3-certstatus-bad-ext | ||||||
| # =========================================================== | # =========================================================== | ||||||
| 
 | 
 | ||||||
| [0-certstatus-good] | [0-certstatus-good] | ||||||
|  | @ -60,3 +62,59 @@ server = 1-certstatus-bad-server-extra | ||||||
| CertStatus = BadResponse | CertStatus = BadResponse | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # =========================================================== | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext] | ||||||
|  | ssl_conf = 2-certstatus-good-ext-ssl | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-ssl] | ||||||
|  | server = 2-certstatus-good-ext-server | ||||||
|  | client = 2-certstatus-good-ext-client | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-server] | ||||||
|  | Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem | ||||||
|  | CipherString = DEFAULT | ||||||
|  | PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-client] | ||||||
|  | CipherString = DEFAULT | ||||||
|  | VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem | ||||||
|  | VerifyMode = Peer | ||||||
|  | 
 | ||||||
|  | [test-2] | ||||||
|  | ExpectedResult = Success | ||||||
|  | Method = TLS | ||||||
|  | server = 2-certstatus-good-ext-server-extra | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-server-extra] | ||||||
|  | CertStatus = GoodResponseExt | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # =========================================================== | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext] | ||||||
|  | ssl_conf = 3-certstatus-bad-ext-ssl | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-ssl] | ||||||
|  | server = 3-certstatus-bad-ext-server | ||||||
|  | client = 3-certstatus-bad-ext-client | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-server] | ||||||
|  | Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem | ||||||
|  | CipherString = DEFAULT | ||||||
|  | PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-client] | ||||||
|  | CipherString = DEFAULT | ||||||
|  | VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem | ||||||
|  | VerifyMode = Peer | ||||||
|  | 
 | ||||||
|  | [test-3] | ||||||
|  | ExpectedResult = ClientFail | ||||||
|  | Method = TLS | ||||||
|  | server = 3-certstatus-bad-ext-server-extra | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-server-extra] | ||||||
|  | CertStatus = BadResponseExt | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -42,4 +42,30 @@ our @tests = ( | ||||||
|             "ExpectedResult" => "ClientFail" |             "ExpectedResult" => "ClientFail" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-good-ext", | ||||||
|  |         server => { | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "GoodResponseExt", | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => {}, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "TLS", | ||||||
|  |             "ExpectedResult" => "Success" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-bad-ext", | ||||||
|  |         server => { | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "BadResponseExt", | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => {}, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "TLS", | ||||||
|  |             "ExpectedResult" => "ClientFail" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | @ -1,9 +1,11 @@ | ||||||
| # Generated with generate_ssl_tests.pl | # Generated with generate_ssl_tests.pl | ||||||
| 
 | 
 | ||||||
| num_tests = 2 | num_tests = 4 | ||||||
| 
 | 
 | ||||||
| test-0 = 0-certstatus-good | test-0 = 0-certstatus-good | ||||||
| test-1 = 1-certstatus-bad | test-1 = 1-certstatus-bad | ||||||
|  | test-2 = 2-certstatus-good-ext | ||||||
|  | test-3 = 3-certstatus-bad-ext | ||||||
| # =========================================================== | # =========================================================== | ||||||
| 
 | 
 | ||||||
| [0-certstatus-good] | [0-certstatus-good] | ||||||
|  | @ -60,3 +62,59 @@ server = 1-certstatus-bad-server-extra | ||||||
| CertStatus = BadResponse | CertStatus = BadResponse | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # =========================================================== | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext] | ||||||
|  | ssl_conf = 2-certstatus-good-ext-ssl | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-ssl] | ||||||
|  | server = 2-certstatus-good-ext-server | ||||||
|  | client = 2-certstatus-good-ext-client | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-server] | ||||||
|  | Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem | ||||||
|  | CipherString = DEFAULT:@SECLEVEL=0 | ||||||
|  | PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-client] | ||||||
|  | CipherString = DEFAULT:@SECLEVEL=0 | ||||||
|  | VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem | ||||||
|  | VerifyMode = Peer | ||||||
|  | 
 | ||||||
|  | [test-2] | ||||||
|  | ExpectedResult = Success | ||||||
|  | Method = DTLS | ||||||
|  | server = 2-certstatus-good-ext-server-extra | ||||||
|  | 
 | ||||||
|  | [2-certstatus-good-ext-server-extra] | ||||||
|  | CertStatus = GoodResponseExt | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # =========================================================== | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext] | ||||||
|  | ssl_conf = 3-certstatus-bad-ext-ssl | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-ssl] | ||||||
|  | server = 3-certstatus-bad-ext-server | ||||||
|  | client = 3-certstatus-bad-ext-client | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-server] | ||||||
|  | Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem | ||||||
|  | CipherString = DEFAULT:@SECLEVEL=0 | ||||||
|  | PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-client] | ||||||
|  | CipherString = DEFAULT:@SECLEVEL=0 | ||||||
|  | VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem | ||||||
|  | VerifyMode = Peer | ||||||
|  | 
 | ||||||
|  | [test-3] | ||||||
|  | ExpectedResult = ClientFail | ||||||
|  | Method = DTLS | ||||||
|  | server = 3-certstatus-bad-ext-server-extra | ||||||
|  | 
 | ||||||
|  | [3-certstatus-bad-ext-server-extra] | ||||||
|  | CertStatus = BadResponseExt | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -51,6 +51,38 @@ our @tests_standard = ( | ||||||
|             "Method" => "DTLS", |             "Method" => "DTLS", | ||||||
|             "ExpectedResult" => "ClientFail" |             "ExpectedResult" => "ClientFail" | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-good-ext", | ||||||
|  |         server => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "GoodResponseExt" | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |         }, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "DTLS", | ||||||
|  |             "ExpectedResult" => "Success" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-bad-ext", | ||||||
|  |         server => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "BadResponseExt", | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |         }, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "DTLS", | ||||||
|  |             "ExpectedResult" => "ClientFail" | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | @ -89,6 +121,40 @@ our @tests_sctp = ( | ||||||
|             "ExpectedResult" => "ClientFail" |             "ExpectedResult" => "ClientFail" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-good-ext", | ||||||
|  |         server => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "GoodResponseExt", | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |         }, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "DTLS", | ||||||
|  |             "UseSCTP" => "Yes", | ||||||
|  |             "ExpectedResult" => "Success" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         name => "certstatus-bad-ext", | ||||||
|  |         server => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |             extra => { | ||||||
|  |                 "CertStatus" => "BadResponseExt", | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         client => { | ||||||
|  |             "CipherString" => "DEFAULT:\@SECLEVEL=0", | ||||||
|  |         }, | ||||||
|  |         test => { | ||||||
|  |             "Method" => "DTLS", | ||||||
|  |             "UseSCTP" => "Yes", | ||||||
|  |             "ExpectedResult" => "ClientFail" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| if  (!$fips_mode || !disabled("dtls1_2")) { | if  (!$fips_mode || !disabled("dtls1_2")) { | ||||||
|  |  | ||||||
|  | @ -82,6 +82,13 @@ static int find_session_cb_cnt = 0; | ||||||
| static int end_of_early_data = 0; | static int end_of_early_data = 0; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifndef OPENSSL_NO_OCSP | ||||||
|  | static int test_tlsext_status_type(void); | ||||||
|  | # ifndef OSSL_NO_USABLE_TLS1_3 | ||||||
|  | static int test_tlsext_status_type_multi(void); | ||||||
|  | # endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static char *certsdir = NULL; | static char *certsdir = NULL; | ||||||
| static char *cert = NULL; | static char *cert = NULL; | ||||||
| static char *privkey = NULL; | static char *privkey = NULL; | ||||||
|  | @ -110,10 +117,11 @@ static size_t client_log_buffer_index = 0; | ||||||
| static int error_writing_log = 0; | static int error_writing_log = 0; | ||||||
| 
 | 
 | ||||||
| #ifndef OPENSSL_NO_OCSP | #ifndef OPENSSL_NO_OCSP | ||||||
| static const unsigned char orespder[] = "Dummy OCSP Response"; |  | ||||||
| static int ocsp_server_called = 0; | static int ocsp_server_called = 0; | ||||||
| static int ocsp_client_called = 0; | static int ocsp_client_called = 0; | ||||||
| 
 | # ifndef OSSL_NO_USABLE_TLS1_3 | ||||||
|  | static int ocsp_verify_cb_called = 0; | ||||||
|  | # endif | ||||||
| static int cdummyarg = 1; | static int cdummyarg = 1; | ||||||
| static X509 *ocspcert = NULL; | static X509 *ocspcert = NULL; | ||||||
| #endif | #endif | ||||||
|  | @ -1734,7 +1742,7 @@ static int execute_cleanse_plaintext(const SSL_METHOD *smeth, | ||||||
|         if (is_fips) { |         if (is_fips) { | ||||||
|             testresult = 1; |             testresult = 1; | ||||||
|             goto end; |             goto end; | ||||||
|         }; |         } | ||||||
|         /*
 |         /*
 | ||||||
|          * Default sigalgs are SHA1 based in <DTLS1.2 which is in security |          * Default sigalgs are SHA1 based in <DTLS1.2 which is in security | ||||||
|          * level 0 |          * level 0 | ||||||
|  | @ -1847,12 +1855,62 @@ static int test_cleanse_plaintext(void) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifndef OPENSSL_NO_OCSP | #ifndef OPENSSL_NO_OCSP | ||||||
| static int ocsp_server_cb(SSL *s, void *arg) | static OCSP_RESPONSE *create_ocsp_resp(X509 *ssl_cert, X509 *issuer, int status, | ||||||
|  |                                        char *signer_key_files, char *signer_cert_files) | ||||||
|  | { | ||||||
|  |     ASN1_TIME *thisupd = X509_gmtime_adj(NULL, 0); | ||||||
|  |     ASN1_TIME *nextupd = X509_time_adj_ex(NULL, 1, 0, NULL); | ||||||
|  |     OCSP_CERTID *cert_id = NULL; | ||||||
|  |     char *signer_key_file = NULL; | ||||||
|  |     char *signer_cert_file = NULL; | ||||||
|  |     EVP_PKEY *signer_key = NULL; | ||||||
|  |     X509 *signer_cert = NULL; | ||||||
|  |     OCSP_RESPONSE *ocsp_resp = NULL; | ||||||
|  |     EVP_MD *md = EVP_MD_fetch(libctx, "SHA-256", NULL); | ||||||
|  |     OCSP_BASICRESP *bs = OCSP_BASICRESP_new(); | ||||||
|  | 
 | ||||||
|  |     if (signer_key_files != NULL && signer_cert_files != NULL) { | ||||||
|  |         cert_id = OCSP_cert_to_id(md, ssl_cert, issuer); | ||||||
|  |         OCSP_basic_add1_status(bs, cert_id, status, 0, thisupd, thisupd, nextupd); | ||||||
|  | 
 | ||||||
|  |         signer_key_file = test_mk_file_path(certsdir, signer_key_files); | ||||||
|  |         if (!TEST_ptr(signer_key = load_pkey_pem(signer_key_file, libctx))) | ||||||
|  |             goto end; | ||||||
|  |         signer_cert_file = test_mk_file_path(certsdir, signer_cert_files); | ||||||
|  |         if (!TEST_ptr(signer_cert = load_cert_pem(signer_cert_file, libctx)) | ||||||
|  |             || !TEST_true(OCSP_basic_sign(bs, signer_cert, signer_key, EVP_sha256(), | ||||||
|  |                                           NULL, OCSP_NOCERTS))) | ||||||
|  |             goto end; | ||||||
|  |         ocsp_resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); | ||||||
|  |     } else { | ||||||
|  |         ocsp_resp = OCSP_response_create(status, NULL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | end: | ||||||
|  |     OPENSSL_free(signer_key_file); | ||||||
|  |     OPENSSL_free(signer_cert_file); | ||||||
|  |     X509_free(signer_cert); | ||||||
|  |     EVP_PKEY_free(signer_key); | ||||||
|  |     ASN1_UTCTIME_free(thisupd); | ||||||
|  |     ASN1_TIME_free(nextupd); | ||||||
|  |     OCSP_BASICRESP_free(bs); | ||||||
|  |     OCSP_CERTID_free(cert_id); | ||||||
|  |     EVP_MD_free(md); | ||||||
|  | 
 | ||||||
|  |     return ocsp_resp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ocsp_server_cb_single(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     int *argi = (int *)arg; |     int *argi = (int *)arg; | ||||||
|     unsigned char *copy = NULL; |     STACK_OF(X509) *server_certs = NULL; | ||||||
|  |     X509 *ssl_cert = NULL; | ||||||
|  |     X509 *issuer = NULL; | ||||||
|  |     OCSP_RESPONSE *ocsp_resp; | ||||||
|     STACK_OF(OCSP_RESPID) *ids = NULL; |     STACK_OF(OCSP_RESPID) *ids = NULL; | ||||||
|     OCSP_RESPID *id = NULL; |     OCSP_RESPID *id = NULL; | ||||||
|  |     unsigned char *ocsp_resp_der = NULL; | ||||||
|  |     int resplen = 0; | ||||||
| 
 | 
 | ||||||
|     if (*argi == 2) { |     if (*argi == 2) { | ||||||
|         /* In this test we are expecting exactly 1 OCSP_RESPID */ |         /* In this test we are expecting exactly 1 OCSP_RESPID */ | ||||||
|  | @ -1867,29 +1925,43 @@ static int ocsp_server_cb(SSL *s, void *arg) | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!TEST_ptr(copy = OPENSSL_memdup(orespder, sizeof(orespder)))) |     ssl_cert = SSL_get_certificate(s); | ||||||
|  |     SSL_get0_chain_certs(s, &server_certs); | ||||||
|  |     issuer = sk_X509_value(server_certs, 0); | ||||||
|  | 
 | ||||||
|  |     ocsp_resp = create_ocsp_resp(ssl_cert, issuer, V_OCSP_CERTSTATUS_GOOD, "subinterCA.key", "subinterCA.pem"); | ||||||
|  |     if (!TEST_ptr(ocsp_resp)) | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
| 
 | 
 | ||||||
|     if (!TEST_true(SSL_set_tlsext_status_ocsp_resp(s, copy, |     resplen = i2d_OCSP_RESPONSE(ocsp_resp, &ocsp_resp_der); | ||||||
|                                                    sizeof(orespder)))) { |     OCSP_RESPONSE_free(ocsp_resp); | ||||||
|         OPENSSL_free(copy); | 
 | ||||||
|  |     if (!TEST_true(SSL_set_tlsext_status_ocsp_resp(s, ocsp_resp_der, resplen))) { | ||||||
|  |         OPENSSL_free(ocsp_resp_der); | ||||||
|         return SSL_TLSEXT_ERR_ALERT_FATAL; |         return SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|     } |     } | ||||||
|  |     OPENSSL_free(ocsp_resp_der); | ||||||
|  | 
 | ||||||
|     ocsp_server_called = 1; |     ocsp_server_called = 1; | ||||||
|     return SSL_TLSEXT_ERR_OK; |     return SSL_TLSEXT_ERR_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ocsp_client_cb(SSL *s, void *arg) | static int ocsp_client_cb_single(SSL *s, void *arg) | ||||||
| { | { | ||||||
|     int *argi = (int *)arg; |     int *argi = (int *)arg; | ||||||
|     const unsigned char *respderin; |     const unsigned char *resp, *p; | ||||||
|     size_t len; |     OCSP_RESPONSE *rsp; | ||||||
|  |     int len, resp_status; | ||||||
| 
 | 
 | ||||||
|     if (*argi != 1 && *argi != 2) |     if (*argi != 1 && *argi != 2) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     len = SSL_get_tlsext_status_ocsp_resp(s, &respderin); |     len = SSL_get_tlsext_status_ocsp_resp(s, &resp); | ||||||
|     if (!TEST_mem_eq(orespder, len, respderin, len)) |     p = resp; | ||||||
|  |     rsp = d2i_OCSP_RESPONSE(NULL, &p, len); | ||||||
|  |     resp_status = OCSP_response_status(rsp); | ||||||
|  |     OCSP_RESPONSE_free(rsp); | ||||||
|  |     if (resp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     ocsp_client_called = 1; |     ocsp_client_called = 1; | ||||||
|  | @ -1899,17 +1971,22 @@ static int ocsp_client_cb(SSL *s, void *arg) | ||||||
| static int test_tlsext_status_type(void) | static int test_tlsext_status_type(void) | ||||||
| { | { | ||||||
|     SSL_CTX *cctx = NULL, *sctx = NULL; |     SSL_CTX *cctx = NULL, *sctx = NULL; | ||||||
|  |     char *leaf_chain = test_mk_file_path(certsdir, "leaf-chain.pem"); | ||||||
|  |     char *skey = test_mk_file_path(certsdir, "leaf.key"); | ||||||
|  |     char *leaf = test_mk_file_path(certsdir, "leaf.pem"); | ||||||
|     SSL *clientssl = NULL, *serverssl = NULL; |     SSL *clientssl = NULL, *serverssl = NULL; | ||||||
|     int testresult = 0; |     int testresult = 0; | ||||||
|     STACK_OF(OCSP_RESPID) *ids = NULL; |     STACK_OF(OCSP_RESPID) *ids = NULL; | ||||||
|     OCSP_RESPID *id = NULL; |     OCSP_RESPID *id = NULL; | ||||||
|     BIO *certbio = NULL; |     BIO *certbio = NULL; | ||||||
|  |     OSSL_LIB_CTX *tmpctx = OSSL_LIB_CTX_set0_default(libctx); | ||||||
| 
 | 
 | ||||||
|     if (!create_ssl_ctx_pair(libctx, TLS_server_method(), TLS_client_method(), |     if (!create_ssl_ctx_pair(libctx, TLS_server_method(), TLS_client_method(), | ||||||
|                              TLS1_VERSION, 0, |                              TLS1_VERSION, 0, | ||||||
|                              &sctx, &cctx, cert, privkey)) |                              &sctx, &cctx, leaf, skey)) | ||||||
|         return 0; |         return 0; | ||||||
| 
 |     if (SSL_CTX_use_certificate_chain_file(sctx, leaf_chain) <= 0) | ||||||
|  |         goto end; | ||||||
|     if (SSL_CTX_get_tlsext_status_type(cctx) != -1) |     if (SSL_CTX_get_tlsext_status_type(cctx) != -1) | ||||||
|         goto end; |         goto end; | ||||||
| 
 | 
 | ||||||
|  | @ -1944,10 +2021,13 @@ static int test_tlsext_status_type(void) | ||||||
|      * Now actually do a handshake and check OCSP information is exchanged and |      * Now actually do a handshake and check OCSP information is exchanged and | ||||||
|      * the callbacks get called |      * the callbacks get called | ||||||
|      */ |      */ | ||||||
|     SSL_CTX_set_tlsext_status_cb(cctx, ocsp_client_cb); |     SSL_CTX_set_tlsext_status_cb(cctx, ocsp_client_cb_single); | ||||||
|     SSL_CTX_set_tlsext_status_arg(cctx, &cdummyarg); |     SSL_CTX_set_tlsext_status_arg(cctx, &cdummyarg); | ||||||
|     SSL_CTX_set_tlsext_status_cb(sctx, ocsp_server_cb); |     SSL_CTX_set_tlsext_status_cb(sctx, ocsp_server_cb_single); | ||||||
|     SSL_CTX_set_tlsext_status_arg(sctx, &cdummyarg); |     SSL_CTX_set_tlsext_status_arg(sctx, &cdummyarg); | ||||||
|  |     ocsp_client_called = 0; | ||||||
|  |     ocsp_server_called = 0; | ||||||
|  |     cdummyarg = 1; | ||||||
|     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, |     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, | ||||||
|                                       &clientssl, NULL, NULL)) |                                       &clientssl, NULL, NULL)) | ||||||
|             || !TEST_true(create_ssl_connection(serverssl, clientssl, |             || !TEST_true(create_ssl_connection(serverssl, clientssl, | ||||||
|  | @ -2016,19 +2096,351 @@ static int test_tlsext_status_type(void) | ||||||
| 
 | 
 | ||||||
|     testresult = 1; |     testresult = 1; | ||||||
| 
 | 
 | ||||||
|  end: | end: | ||||||
|     SSL_free(serverssl); |     SSL_free(serverssl); | ||||||
|     SSL_free(clientssl); |     SSL_free(clientssl); | ||||||
|     SSL_CTX_free(sctx); |     SSL_CTX_free(sctx); | ||||||
|     SSL_CTX_free(cctx); |     SSL_CTX_free(cctx); | ||||||
|  |     OPENSSL_free(leaf_chain); | ||||||
|  |     OPENSSL_free(skey); | ||||||
|  |     OPENSSL_free(leaf); | ||||||
|     sk_OCSP_RESPID_pop_free(ids, OCSP_RESPID_free); |     sk_OCSP_RESPID_pop_free(ids, OCSP_RESPID_free); | ||||||
|     OCSP_RESPID_free(id); |     OCSP_RESPID_free(id); | ||||||
|     BIO_free(certbio); |     BIO_free(certbio); | ||||||
|     X509_free(ocspcert); |     X509_free(ocspcert); | ||||||
|  |     OSSL_LIB_CTX_set0_default(tmpctx); | ||||||
|     ocspcert = NULL; |     ocspcert = NULL; | ||||||
| 
 | 
 | ||||||
|     return testresult; |     return testresult; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | # ifndef OSSL_NO_USABLE_TLS1_3 | ||||||
|  | static int ocsp_server_cb_multi(SSL *s, void *arg) | ||||||
|  | { | ||||||
|  |     int *argi = (int *)arg; | ||||||
|  |     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s); | ||||||
|  |     X509 *ssl_cert = NULL; | ||||||
|  |     X509 *issuer = NULL; | ||||||
|  |     int i, num = 0; | ||||||
|  |     STACK_OF(X509) *server_certs = NULL; | ||||||
|  |     OCSP_RESPONSE *ocsp_resp; | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|  |     char *signer_key_files[] = { "subinterCA.key", "interCA.key", "rootCA.key" }; | ||||||
|  |     char *signer_cert_files[] = { "subinterCA.pem", "interCA.pem", "rootCA.pem" }; | ||||||
|  |     int ret = SSL_TLSEXT_ERR_ALERT_FATAL; | ||||||
|  | 
 | ||||||
|  |     if (*argi != 1 && *argi != 3) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     ocsp_server_called += 1; | ||||||
|  | 
 | ||||||
|  |     SSL_get0_chain_certs(s, &server_certs); | ||||||
|  | 
 | ||||||
|  |     if (server_certs != NULL && sc != NULL) { | ||||||
|  |         /* certificate chain is available */ | ||||||
|  |         num = sk_X509_num(server_certs); | ||||||
|  |     } else if (sc != NULL) { | ||||||
|  |         /*
 | ||||||
|  |          * certificate chain is not available, | ||||||
|  |          * set num to 1 for server certificate | ||||||
|  |          */ | ||||||
|  |         num = 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* in the test case with arg = 1 we only send the EE certificate response */ | ||||||
|  |     if (*argi == 1) | ||||||
|  |         num = *argi; | ||||||
|  | 
 | ||||||
|  |     sk_resp = sk_OCSP_RESPONSE_new_reserve(NULL, num); | ||||||
|  |     if (sk_resp == NULL) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         if (i == 0) { | ||||||
|  |             /* get OCSP response for server certificate first */ | ||||||
|  |             ssl_cert = SSL_get_certificate(s); | ||||||
|  |         } else { | ||||||
|  |             /*
 | ||||||
|  |              * for each certificate in chain (except root) get | ||||||
|  |              * the OCSP response | ||||||
|  |              */ | ||||||
|  |             ssl_cert = sk_X509_value(server_certs, i - 1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         issuer = sk_X509_value(server_certs, i); | ||||||
|  | 
 | ||||||
|  |         if (ocsp_server_called == 3 && i == 0) | ||||||
|  |             ocsp_resp = create_ocsp_resp(ssl_cert, issuer, OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, | ||||||
|  |                                          NULL, NULL); | ||||||
|  |         else if (ocsp_server_called == 4 && i == 0) | ||||||
|  |             ocsp_resp = create_ocsp_resp(ssl_cert, issuer, V_OCSP_CERTSTATUS_REVOKED, | ||||||
|  |                                          signer_key_files[i], signer_cert_files[i]); | ||||||
|  |         else | ||||||
|  |             ocsp_resp = create_ocsp_resp(ssl_cert, issuer, V_OCSP_CERTSTATUS_GOOD, | ||||||
|  |                                          signer_key_files[i], signer_cert_files[i]); | ||||||
|  | 
 | ||||||
|  |         sk_OCSP_RESPONSE_push(sk_resp, ocsp_resp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ret = SSL_TLSEXT_ERR_OK; | ||||||
|  | 
 | ||||||
|  |     (void)SSL_set0_tlsext_status_ocsp_resp_ex(s, sk_resp); | ||||||
|  | 
 | ||||||
|  | end: | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ocsp_client_cb_multi(SSL *s, void *arg) | ||||||
|  | { | ||||||
|  |     int *argi = (int *)arg; | ||||||
|  |     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||||
|  |     OCSP_RESPONSE *resp = NULL; | ||||||
|  |     STACK_OF(X509) *server_certs = NULL; | ||||||
|  |     X509 *ssl_cert = NULL, *issuer_cert = NULL; | ||||||
|  |     OCSP_BASICRESP *bs = NULL; | ||||||
|  |     OCSP_CERTID *cert_id = NULL; | ||||||
|  |     OCSP_SINGLERESP *sr = NULL; | ||||||
|  |     OCSP_CERTID *cid = NULL; | ||||||
|  |     ASN1_OBJECT *cert_id_md_oid; | ||||||
|  |     const EVP_MD *cert_id_md; | ||||||
|  |     int i, num = 0; | ||||||
|  |     int testresult = 0; | ||||||
|  | 
 | ||||||
|  |     SSL_get0_tlsext_status_ocsp_resp_ex(s, &sk_resp); | ||||||
|  |     num = sk_OCSP_RESPONSE_num(sk_resp); | ||||||
|  | 
 | ||||||
|  |     /* check if we get as many OCSP responses as expected */ | ||||||
|  |     if (*argi < 1 || *argi > 3 || num != *argi) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     ocsp_client_called += 1; | ||||||
|  | 
 | ||||||
|  |     server_certs = SSL_get_peer_cert_chain(s); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * check if OCSP responses for all certificates in the chain are received | ||||||
|  |      * and they are in the correct order | ||||||
|  |      */ | ||||||
|  |     for (i = 0; i < num; i++) { | ||||||
|  |         if ((ssl_cert = sk_X509_value(server_certs, i)) == NULL) | ||||||
|  |             return 0; | ||||||
|  | 
 | ||||||
|  |         /* for a selfsigned certificate we expect no OCSP response */ | ||||||
|  |         if (X509_self_signed(ssl_cert, 0)) | ||||||
|  |             continue; | ||||||
|  | 
 | ||||||
|  |         if ((resp = sk_OCSP_RESPONSE_value(sk_resp, i)) == NULL) | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         if (ocsp_client_called != 3) { | ||||||
|  |             if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { | ||||||
|  |                 resp = NULL; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if ((bs = OCSP_response_get1_basic(resp)) == NULL) | ||||||
|  |                 break; | ||||||
|  |             /* we send a OCSP response with one single response so we check only the first */ | ||||||
|  |             if ((sr = OCSP_resp_get0(bs, 0)) == NULL) { | ||||||
|  |                 resp = NULL; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /* determine the md algorithm which was used to create cert id */ | ||||||
|  |             cid = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); | ||||||
|  |             OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid); | ||||||
|  |             if (cert_id_md_oid != NULL) | ||||||
|  |                 cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); | ||||||
|  |             else | ||||||
|  |                 cert_id_md = NULL; | ||||||
|  | 
 | ||||||
|  |             issuer_cert = sk_X509_value(server_certs, i + 1); | ||||||
|  |             if (issuer_cert == NULL) { | ||||||
|  |                 resp = NULL; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             /* search the stack for the requested OCSP response */ | ||||||
|  |             cert_id = OCSP_cert_to_id(cert_id_md, ssl_cert, issuer_cert); | ||||||
|  |             if (cert_id == NULL) { | ||||||
|  |                 resp = NULL; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if (OCSP_resp_find(bs, cert_id, -1) < 0) | ||||||
|  |                 resp = NULL; | ||||||
|  | 
 | ||||||
|  |             OCSP_BASICRESP_free(bs); | ||||||
|  |             bs = NULL; | ||||||
|  |             OCSP_CERTID_free(cert_id); | ||||||
|  |             cert_id = NULL; | ||||||
|  |         } else { | ||||||
|  |             /* in that test case we expect a OCSP response with an error status */ | ||||||
|  |             if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_MALFORMEDREQUEST) { | ||||||
|  |                 resp = NULL; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (resp == NULL) | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     testresult = resp != NULL; | ||||||
|  | 
 | ||||||
|  |     OCSP_BASICRESP_free(bs); | ||||||
|  |     OCSP_CERTID_free(cert_id); | ||||||
|  | 
 | ||||||
|  |     return testresult; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int verify_cb_multi_stapling(int preverify_ok, X509_STORE_CTX *x509_ctx) | ||||||
|  | { | ||||||
|  |     int res = preverify_ok; | ||||||
|  | 
 | ||||||
|  |     /* in that test cases the verify of the first response should be not ok */ | ||||||
|  |     if (ocsp_server_called == 3 || ocsp_server_called == 4) | ||||||
|  |         if (ocsp_verify_cb_called == 0 && preverify_ok == 0) | ||||||
|  |             res = 1; | ||||||
|  | 
 | ||||||
|  |     ocsp_verify_cb_called += 1; | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int test_tlsext_status_type_multi(void) | ||||||
|  | { | ||||||
|  |     SSL_CTX *cctx = NULL, *sctx = NULL; | ||||||
|  |     SSL *clientssl = NULL, *serverssl = NULL; | ||||||
|  |     int testresult = 0; | ||||||
|  |     char *leaf_chain = test_mk_file_path(certsdir, "leaf-chain.pem"); | ||||||
|  |     char *skey = test_mk_file_path(certsdir, "leaf.key"); | ||||||
|  |     char *leaf = test_mk_file_path(certsdir, "leaf.pem"); | ||||||
|  |     char *root = test_mk_file_path(certsdir, "rootCA.pem"); | ||||||
|  |     OSSL_LIB_CTX *tmpctx = OSSL_LIB_CTX_set0_default(libctx); | ||||||
|  |     X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new(), *out_vpm = NULL; | ||||||
|  | 
 | ||||||
|  |     if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), TLS_client_method(), | ||||||
|  |                                        TLS1_VERSION, 0, &sctx, &cctx, leaf, skey))) | ||||||
|  |         goto end; | ||||||
|  |     if (TEST_int_lt(SSL_CTX_use_certificate_chain_file(sctx, leaf_chain), 0)) | ||||||
|  |         goto end; | ||||||
|  |     if (!TEST_true(SSL_CTX_load_verify_locations(cctx, root, NULL))) | ||||||
|  |         goto end; | ||||||
|  |     if (TEST_int_ne(SSL_CTX_get_tlsext_status_type(cctx), -1)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     /* set verify callback function */ | ||||||
|  |     SSL_CTX_set_verify(cctx, SSL_VERIFY_PEER, verify_cb_multi_stapling); | ||||||
|  | 
 | ||||||
|  |     /* First just do various checks getting and setting tlsext_status_type */ | ||||||
|  |     clientssl = SSL_new(cctx); | ||||||
|  |     if (!TEST_ptr(clientssl)) | ||||||
|  |         goto end; | ||||||
|  |     if (!TEST_int_eq(SSL_get_tlsext_status_type(clientssl), -1) | ||||||
|  |             || !TEST_true(SSL_set_tlsext_status_type(clientssl, | ||||||
|  |                                                      TLSEXT_STATUSTYPE_ocsp)) | ||||||
|  |             || !TEST_int_eq(SSL_get_tlsext_status_type(clientssl), | ||||||
|  |                             TLSEXT_STATUSTYPE_ocsp)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     clientssl = NULL; | ||||||
|  | 
 | ||||||
|  |     if (!TEST_true(SSL_CTX_set_tlsext_status_type(cctx, TLSEXT_STATUSTYPE_ocsp)) | ||||||
|  |         || TEST_int_ne(SSL_CTX_get_tlsext_status_type(cctx), TLSEXT_STATUSTYPE_ocsp)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Now actually do a handshake and check OCSP information is exchanged and | ||||||
|  |      * the callbacks get called | ||||||
|  |      */ | ||||||
|  |     SSL_CTX_set_tlsext_status_cb(cctx, ocsp_client_cb_multi); | ||||||
|  |     SSL_CTX_set_tlsext_status_arg(cctx, &cdummyarg); | ||||||
|  |     SSL_CTX_set_tlsext_status_cb(sctx, ocsp_server_cb_multi); | ||||||
|  |     SSL_CTX_set_tlsext_status_arg(sctx, &cdummyarg); | ||||||
|  |     ocsp_client_called = 0; | ||||||
|  |     ocsp_server_called = 0; | ||||||
|  |     ocsp_verify_cb_called = 0; | ||||||
|  |     cdummyarg = 3; /* expect three OCSP responses */ | ||||||
|  |     X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_OCSP_RESP_CHECK | X509_V_FLAG_OCSP_RESP_CHECK_ALL); | ||||||
|  |     if (!TEST_true(SSL_CTX_set1_param(cctx, vpm))) | ||||||
|  |         goto end; | ||||||
|  |     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) | ||||||
|  |             || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) | ||||||
|  |             || !TEST_int_eq(ocsp_client_called, 1) || !TEST_int_eq(ocsp_server_called, 1) | ||||||
|  |             || !TEST_true(ocsp_verify_cb_called)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     SSL_free(serverssl); | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     serverssl = NULL; | ||||||
|  |     clientssl = NULL; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * This time we only transfer the OCSP information for the server certificate | ||||||
|  |      */ | ||||||
|  |     ocsp_verify_cb_called = 0; | ||||||
|  |     cdummyarg = 1; /* expect one OCSP response */ | ||||||
|  |     out_vpm = SSL_CTX_get0_param(cctx); | ||||||
|  |     X509_VERIFY_PARAM_clear_flags(out_vpm, X509_V_FLAG_OCSP_RESP_CHECK_ALL); | ||||||
|  |     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) | ||||||
|  |             || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) | ||||||
|  |             || !TEST_int_eq(ocsp_client_called, 2) || !TEST_int_eq(ocsp_server_called, 2) | ||||||
|  |             || !TEST_true(ocsp_verify_cb_called)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     SSL_free(serverssl); | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     serverssl = NULL; | ||||||
|  |     clientssl = NULL; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * tbd | ||||||
|  |      */ | ||||||
|  |     ocsp_verify_cb_called = 0; | ||||||
|  |     cdummyarg = 1; /* expect one OCSP response */ | ||||||
|  |     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) | ||||||
|  |             || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) | ||||||
|  |             || !TEST_int_eq(ocsp_client_called, 3) || !TEST_int_eq(ocsp_server_called, 3) | ||||||
|  |             || !TEST_true(ocsp_verify_cb_called)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     SSL_free(serverssl); | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     serverssl = NULL; | ||||||
|  |     clientssl = NULL; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * In the third test case we set the status of the server certificate to REVOKED. | ||||||
|  |      * The SSL connection should fail and the ocsp_client_cb_multi should not be called. | ||||||
|  |      */ | ||||||
|  |     ocsp_verify_cb_called = 0; | ||||||
|  |     cdummyarg = 3; /* expect three OCSP responses */ | ||||||
|  |     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) | ||||||
|  |             || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) | ||||||
|  |             || !TEST_int_eq(ocsp_client_called, 4) || !TEST_int_eq(ocsp_server_called, 4) | ||||||
|  |             || !TEST_true(ocsp_verify_cb_called)) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     SSL_free(serverssl); | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     serverssl = NULL; | ||||||
|  |     clientssl = NULL; | ||||||
|  | 
 | ||||||
|  |     testresult = 1; | ||||||
|  | 
 | ||||||
|  | end: | ||||||
|  |     OPENSSL_free(leaf_chain); | ||||||
|  |     OPENSSL_free(skey); | ||||||
|  |     OPENSSL_free(leaf); | ||||||
|  |     OPENSSL_free(root); | ||||||
|  |     X509_VERIFY_PARAM_free(vpm); | ||||||
|  |     OSSL_LIB_CTX_set0_default(tmpctx); | ||||||
|  |     SSL_free(serverssl); | ||||||
|  |     SSL_free(clientssl); | ||||||
|  |     SSL_CTX_free(sctx); | ||||||
|  |     SSL_CTX_free(cctx); | ||||||
|  |     return testresult; | ||||||
|  | } | ||||||
|  | # endif | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if !defined(OSSL_NO_USABLE_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) | #if !defined(OSSL_NO_USABLE_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) | ||||||
|  | @ -13476,6 +13888,9 @@ int setup_tests(void) | ||||||
|     ADD_TEST(test_cleanse_plaintext); |     ADD_TEST(test_cleanse_plaintext); | ||||||
| #ifndef OPENSSL_NO_OCSP | #ifndef OPENSSL_NO_OCSP | ||||||
|     ADD_TEST(test_tlsext_status_type); |     ADD_TEST(test_tlsext_status_type); | ||||||
|  | # ifndef OSSL_NO_USABLE_TLS1_3 | ||||||
|  |     ADD_TEST(test_tlsext_status_type_multi); | ||||||
|  | # endif | ||||||
| #endif | #endif | ||||||
|     ADD_TEST(test_session_with_only_int_cache); |     ADD_TEST(test_session_with_only_int_cache); | ||||||
|     ADD_TEST(test_session_with_only_ext_cache); |     ADD_TEST(test_session_with_only_ext_cache); | ||||||
|  |  | ||||||
|  | @ -5925,6 +5925,7 @@ OSSL_AA_DIST_POINT_new                  ?	3_5_0	EXIST::FUNCTION: | ||||||
| OSSL_AA_DIST_POINT_it                   ?	3_5_0	EXIST::FUNCTION: | OSSL_AA_DIST_POINT_it                   ?	3_5_0	EXIST::FUNCTION: | ||||||
| PEM_ASN1_write_bio_ctx                  ?	3_5_0	EXIST::FUNCTION: | PEM_ASN1_write_bio_ctx                  ?	3_5_0	EXIST::FUNCTION: | ||||||
| EVP_PKEY_get_security_category          ?	3_6_0	EXIST::FUNCTION: | EVP_PKEY_get_security_category          ?	3_6_0	EXIST::FUNCTION: | ||||||
|  | X509_STORE_CTX_set_ocsp_resp            ?	3_6_0	EXIST::FUNCTION:OCSP | ||||||
| OPENSSL_sk_set_thunks                   ?	3_6_0	EXIST::FUNCTION: | OPENSSL_sk_set_thunks                   ?	3_6_0	EXIST::FUNCTION: | ||||||
| i2d_PKCS8PrivateKey                     ?	3_6_0	EXIST::FUNCTION: | i2d_PKCS8PrivateKey                     ?	3_6_0	EXIST::FUNCTION: | ||||||
| OSSL_PARAM_set_octet_string_or_ptr      ?	3_6_0	EXIST::FUNCTION: | OSSL_PARAM_set_octet_string_or_ptr      ?	3_6_0	EXIST::FUNCTION: | ||||||
|  |  | ||||||
|  | @ -653,6 +653,7 @@ SSL_get_signature_nid                   define | ||||||
| SSL_get_time                            define | SSL_get_time                            define | ||||||
| SSL_get_timeout                         define | SSL_get_timeout                         define | ||||||
| SSL_get_tlsext_status_ocsp_resp         define | SSL_get_tlsext_status_ocsp_resp         define | ||||||
|  | SSL_get0_tlsext_status_ocsp_resp_ex     define | ||||||
| SSL_get_tlsext_status_type              define | SSL_get_tlsext_status_type              define | ||||||
| SSL_get_tmp_key                         define | SSL_get_tmp_key                         define | ||||||
| SSL_in_accept_init                      define | SSL_in_accept_init                      define | ||||||
|  | @ -690,6 +691,7 @@ SSL_set_time                            define | ||||||
| SSL_set_timeout                         define | SSL_set_timeout                         define | ||||||
| SSL_set_tlsext_host_name                define | SSL_set_tlsext_host_name                define | ||||||
| SSL_set_tlsext_status_ocsp_resp         define | SSL_set_tlsext_status_ocsp_resp         define | ||||||
|  | SSL_set0_tlsext_status_ocsp_resp_ex     define | ||||||
| SSL_set_tlsext_status_type              define | SSL_set_tlsext_status_type              define | ||||||
| SSL_set_tmp_dh                          define | SSL_set_tmp_dh                          define | ||||||
| SSL_set_tmp_ecdh                        define | SSL_set_tmp_ecdh                        define | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue