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* | ||||
| 
 | ||||
|  * 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 | ||||
| ----------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -106,6 +106,10 @@ int verify_callback(int ok, X509_STORE_CTX *ctx) | |||
|         if (!verify_args.quiet) | ||||
|             policies_print(ctx); | ||||
|         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) | ||||
|         policies_print(ctx); | ||||
|  |  | |||
|  | @ -110,9 +110,10 @@ static char *sess_out = NULL; | |||
| static SSL_SESSION *psksess = NULL; | ||||
| 
 | ||||
| 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); | ||||
| #endif | ||||
| static void print_ocsp_response(BIO *bp, OCSP_RESPONSE *rsp); | ||||
| # endif | ||||
| static int ldap_ExtendedResponse_parse(const char *buf, long rem); | ||||
| 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_BRIEF, OPT_PREXIT, OPT_NO_INTERACTIVE, OPT_CRLF, OPT_QUIET, OPT_NBIO, | ||||
|     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_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE, | ||||
|     OPT_PSK_IDENTITY, OPT_PSK, OPT_PSK_SESS, | ||||
|  | @ -625,6 +629,17 @@ const OPTIONS s_client_options[] = { | |||
|     {"no-interactive", OPT_NO_INTERACTIVE, '-', | ||||
|      "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"), | ||||
|     {"showcerts", OPT_SHOWCERTS, '-', | ||||
|      "Show all certificates sent by the server"}, | ||||
|  | @ -659,9 +674,6 @@ const OPTIONS s_client_options[] = { | |||
|      "Hex dump of all TLS extensions received"}, | ||||
|     {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-', | ||||
|      "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', | ||||
|      "types  Send empty ClientHello extensions (comma-separated numbers)"}, | ||||
|     {"alpn", OPT_ALPN, 's', | ||||
|  | @ -1195,11 +1207,23 @@ int s_client_main(int argc, char **argv) | |||
|         case OPT_TLSEXTDEBUG: | ||||
|             c_tlsextdebug = 1; | ||||
|             break; | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|         case OPT_STATUS: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
|             c_status_req = 1; | ||||
| #endif | ||||
|             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: | ||||
| #ifdef WATT32 | ||||
|             dbug_init(); | ||||
|  | @ -3626,27 +3650,58 @@ static void print_stuff(BIO *bio, SSL *s, int full) | |||
| # ifndef OPENSSL_NO_OCSP | ||||
| static int ocsp_resp_cb(SSL *s, void *arg) | ||||
| { | ||||
|     const unsigned char *p; | ||||
|     int len; | ||||
|     int num, i; | ||||
|     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||
|     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: "); | ||||
|         if (p == NULL) { | ||||
|         BIO_puts(arg, "no response sent\n"); | ||||
|             BIO_puts(arg, "no OCSP response received\n"); | ||||
|             return 1; | ||||
|         } | ||||
|         rsp = d2i_OCSP_RESPONSE(NULL, &p, len); | ||||
|         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); | ||||
|             return 0; | ||||
|         } | ||||
|     BIO_puts(arg, "\n======================================\n"); | ||||
|     OCSP_RESPONSE_print(arg, rsp, 0); | ||||
|     BIO_puts(arg, "======================================\n"); | ||||
|         print_ocsp_response(arg, rsp); | ||||
|         OCSP_RESPONSE_free(rsp); | ||||
|     } | ||||
| 
 | ||||
|     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 | ||||
| 
 | ||||
| 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 "timeouts.h" | ||||
| #ifdef CHARSET_EBCDIC | ||||
| #include <openssl/ebcdic.h> | ||||
| # include <openssl/ebcdic.h> | ||||
| #endif | ||||
| #include "internal/sockets.h" | ||||
| #include "internal/statem.h" | ||||
| 
 | ||||
| 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); | ||||
|  | @ -454,16 +455,20 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) | |||
| /* Structure passed to cert status callback */ | ||||
| typedef struct tlsextstatusctx_st { | ||||
|     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 */ | ||||
|     char *host, *path, *port; | ||||
|     char *proxy, *no_proxy; | ||||
|     int use_ssl; | ||||
|     int verbose; | ||||
|     int status_all; | ||||
| } tlsextstatusctx; | ||||
| 
 | ||||
| static tlsextstatusctx tlscstatp = { -1 }; | ||||
| static tlsextstatusctx tlscstatp = { -1, NULL }; | ||||
| 
 | ||||
| #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 | ||||
|  * 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) | ||||
| { | ||||
|     char *host = NULL, *port = NULL, *path = NULL; | ||||
|     char *proxy = NULL, *no_proxy = NULL; | ||||
|     int use_ssl; | ||||
|     STACK_OF(OPENSSL_STRING) *aia = NULL; | ||||
|     X509 *x = NULL, *cert; | ||||
|     X509 *cert; | ||||
|     X509_NAME *iname; | ||||
|     STACK_OF(X509) *chain = NULL; | ||||
|     SSL_CTX *ssl_ctx; | ||||
|  | @ -494,7 +500,6 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | |||
|     int i; | ||||
| 
 | ||||
|     /* Build up OCSP query from server certificate */ | ||||
|     x = SSL_get_certificate(s); | ||||
|     iname = X509_get_issuer_name(x); | ||||
|     aia = X509_get1_ocsp(x); | ||||
|     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); | ||||
|     for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { | ||||
|         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); | ||||
| 
 | ||||
|         if (!OCSP_REQUEST_add_ext(req, ext, -1)) | ||||
|             goto err; | ||||
|     } | ||||
|  | @ -591,6 +597,212 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, | |||
|     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 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; | ||||
|     OCSP_RESPONSE *resp = NULL; | ||||
|     unsigned char *rspder = NULL; | ||||
|     int rspderlen; | ||||
|     STACK_OF(OCSP_RESPONSE) *sk_resp = NULL; | ||||
|     int ret = SSL_TLSEXT_ERR_ALERT_FATAL; | ||||
|     int i; | ||||
| 
 | ||||
|     if (srctx->verbose) | ||||
|         BIO_puts(bio_err, "cert_status: callback called\n"); | ||||
| 
 | ||||
|     if (srctx->respin != NULL) { | ||||
|         BIO *derbio = bio_open_default(srctx->respin, 'r', FORMAT_ASN1); | ||||
|         if (derbio == NULL) { | ||||
|             BIO_puts(bio_err, "cert_status: Cannot open OCSP response file\n"); | ||||
|             goto err; | ||||
|         } | ||||
|         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; | ||||
|         } | ||||
|     SSL_get0_tlsext_status_ocsp_resp_ex(s, &sk_resp); | ||||
| 
 | ||||
|     if (sk_resp == NULL || sk_OCSP_RESPONSE_num(sk_resp) <= 0) { | ||||
|         if (srctx->sk_resp_in != NULL) { | ||||
|             get_ocsp_resp_from_files(s, srctx, &sk_resp); | ||||
|         } 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) | ||||
|                 goto err; | ||||
|         } | ||||
| 
 | ||||
|     rspderlen = i2d_OCSP_RESPONSE(resp, &rspder); | ||||
|     if (rspderlen <= 0) | ||||
|         goto err; | ||||
|         (void)SSL_set0_tlsext_status_ocsp_resp_ex(s, sk_resp); | ||||
|     } | ||||
| 
 | ||||
|     SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen); | ||||
|     if (srctx->verbose) { | ||||
|         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); | ||||
|             else | ||||
|                 BIO_printf(bio_err, | ||||
|                            "cert_status: no ocsp response for certificate with index %d\n", i); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ret = SSL_TLSEXT_ERR_OK; | ||||
| 
 | ||||
|  err: | ||||
|     if (ret != SSL_TLSEXT_ERR_OK) | ||||
|     if (ret != SSL_TLSEXT_ERR_OK) { | ||||
|         ERR_print_errors(bio_err); | ||||
| 
 | ||||
|     OCSP_RESPONSE_free(resp); | ||||
|         sk_OCSP_RESPONSE_pop_free(sk_resp, OCSP_RESPONSE_free); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
|  | @ -680,6 +892,7 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, | |||
|     if (!s_quiet) { | ||||
|         /* We can assume that |in| is syntactically valid. */ | ||||
|         unsigned int i; | ||||
| 
 | ||||
|         BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); | ||||
|         for (i = 0; i < inlen;) { | ||||
|             if (i) | ||||
|  | @ -692,9 +905,8 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, | |||
| 
 | ||||
|     if (SSL_select_next_proto | ||||
|         ((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; | ||||
|     } | ||||
| 
 | ||||
|     if (!s_quiet) { | ||||
|         BIO_printf(bio_s_out, "ALPN protocols selected: "); | ||||
|  | @ -725,9 +937,9 @@ typedef enum OPTION_choice { | |||
|     OPT_VERIFYCAFILE, | ||||
|     OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, | ||||
|     OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, | ||||
|     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_VERBOSE, | ||||
|     OPT_STATUS_TIMEOUT, OPT_PROXY, OPT_NO_PROXY, OPT_STATUS_URL, | ||||
|     OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, | ||||
|     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_ALL, | ||||
|     OPT_STATUS_VERBOSE, OPT_STATUS_TIMEOUT, OPT_PROXY, OPT_NO_PROXY, | ||||
|     OPT_STATUS_URL, OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, | ||||
|     OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, | ||||
|     OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, | ||||
|     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"}, | ||||
| #endif | ||||
| 
 | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_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, '-', | ||||
|      "Print more output in certificate status callback"}, | ||||
|     {"status_timeout", OPT_STATUS_TIMEOUT, 'n', | ||||
|  | @ -891,8 +1106,8 @@ const OPTIONS s_server_options[] = { | |||
|     {OPT_MORE_STR, 0, 0, | ||||
|      "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, | ||||
|     {"status_file", OPT_STATUS_FILE, '<', | ||||
|      "File containing DER encoded OCSP Response"}, | ||||
| #endif | ||||
|      "File containing DER encoded OCSP Response (can be specified multiple times)"}, | ||||
| # endif | ||||
| 
 | ||||
|     OPT_SECTION("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_file2 = TEST_CERT2, *s_key_file2 = 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; | ||||
| #endif | ||||
| # endif | ||||
|     int no_resume_ephemeral = 0; | ||||
|     unsigned int max_send_fragment = 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; | ||||
|             break; | ||||
|         case OPT_STATUS: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = 1; | ||||
| #endif | ||||
|             tlscstatp.status_all = 0; | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_STATUS_ALL: | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = tlscstatp.status_all = 1; | ||||
| # endif | ||||
|             break; | ||||
| 
 | ||||
|         case OPT_STATUS_VERBOSE: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = tlscstatp.verbose = 1; | ||||
| #endif | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_STATUS_TIMEOUT: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = 1; | ||||
|             tlscstatp.timeout = atoi(opt_arg()); | ||||
| #endif | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_PROXY: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             tlscstatp.proxy = opt_arg(); | ||||
| #endif | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_NO_PROXY: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             tlscstatp.no_proxy = opt_arg(); | ||||
| #endif | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_STATUS_URL: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = 1; | ||||
|             if (!OSSL_HTTP_parse_url(opt_arg(), &tlscstatp.use_ssl, 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"); | ||||
|                 goto end; | ||||
|             } | ||||
| #endif | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_STATUS_FILE: | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|             s_tlsextstatus = 1; | ||||
|             tlscstatp.respin = opt_arg(); | ||||
| #endif | ||||
|             if (tlscstatp.sk_resp_in == NULL | ||||
|                 && (tlscstatp.sk_resp_in = sk_OPENSSL_STRING_new_null()) == NULL) | ||||
|                 goto end; | ||||
|             sk_OPENSSL_STRING_push(tlscstatp.sk_resp_in, opt_arg()); | ||||
| # endif | ||||
|             break; | ||||
|         case OPT_MSG: | ||||
|             s_msg = 1; | ||||
|  | @ -2358,6 +2583,7 @@ int s_server_main(int argc, char *argv[]) | |||
|     OPENSSL_free(port); | ||||
|     X509_VERIFY_PARAM_free(vpm); | ||||
|     free_sessions(); | ||||
|     sk_OPENSSL_STRING_free(tlscstatp.sk_resp_in); | ||||
|     OPENSSL_free(tlscstatp.host); | ||||
|     OPENSSL_free(tlscstatp.port); | ||||
|     OPENSSL_free(tlscstatp.path); | ||||
|  |  | |||
|  | @ -174,6 +174,16 @@ const char *X509_verify_cert_error_string(long n) | |||
|         return "OCSP verification failed"; | ||||
|     case X509_V_ERR_OCSP_CERT_UNKNOWN: | ||||
|         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: | ||||
|         return "Cannot find certificate signature algorithm"; | ||||
|     case X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH: | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
| #include <openssl/asn1.h> | ||||
| #include <openssl/x509.h> | ||||
| #include <openssl/x509v3.h> | ||||
| #include <openssl/ocsp.h> | ||||
| #include <openssl/objects.h> | ||||
| #include <openssl/core_names.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_trust(X509_STORE_CTX *ctx, int num_untrusted); | ||||
| 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_dane_issuer(X509_STORE_CTX *ctx, int depth); | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| #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(). */ | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*-
 | ||||
|  * Returns -1 on internal error. | ||||
|  * 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) | ||||
| { | ||||
|     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; | ||||
|     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; | ||||
|         } else { | ||||
|             /* If checking CRL paths this isn't the EE certificate */ | ||||
|  | @ -1048,17 +1143,124 @@ static int check_revocation(X509_STORE_CTX *ctx) | |||
|                 return 1; | ||||
|             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; | ||||
|         ok = check_cert(ctx); | ||||
|             ok = check_cert_crl(ctx); | ||||
|             if (!ok) | ||||
|                 return ok; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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. */ | ||||
| static int check_cert(X509_STORE_CTX *ctx) | ||||
| static int check_cert_crl(X509_STORE_CTX *ctx) | ||||
| { | ||||
|     X509_CRL *crl = NULL, *dcrl = NULL; | ||||
|     int ok = 0; | ||||
|  | @ -1070,6 +1272,9 @@ static int check_cert(X509_STORE_CTX *ctx) | |||
|     ctx->current_crl_score = 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) | ||||
|         return 1; | ||||
| 
 | ||||
|  | @ -1645,7 +1850,7 @@ static int get_crl_delta(X509_STORE_CTX *ctx, | |||
| 
 | ||||
|     sk_X509_CRL_pop_free(skcrl, X509_CRL_free); | ||||
| 
 | ||||
|  done: | ||||
| done: | ||||
|     /* If we got any kind of CRL use it and return success */ | ||||
|     if (crl != NULL) { | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| #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) | ||||
| { | ||||
|     /*
 | ||||
|  | @ -2490,7 +2702,6 @@ void X509_STORE_CTX_free(X509_STORE_CTX *ctx) | |||
|     OPENSSL_free(ctx); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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)) | ||||
|  | @ -2531,6 +2742,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, | |||
|     ctx->rpk = NULL; | ||||
|     /* Zero ex_data to make sure we're cleanup-safe */ | ||||
|     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 */ | ||||
|     if (store != NULL) | ||||
|  |  | |||
|  | @ -94,6 +94,8 @@ B<openssl> B<s_client> | |||
| [B<-sess_in> I<filename>] | ||||
| [B<-serverinfo> I<types>] | ||||
| [B<-status>] | ||||
| [B<-ocsp_check_leaf>] | ||||
| [B<-ocsp_check_all>] | ||||
| [B<-alpn> I<protocols>] | ||||
| [B<-nextprotoneg> I<protocols>] | ||||
| [B<-ct>] | ||||
|  | @ -671,6 +673,24 @@ file. | |||
| Sends a certificate status request to the server (OCSP stapling). The server | ||||
| 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> | ||||
| 
 | ||||
| These flags enable the Enable the Application-Layer Protocol Negotiation | ||||
|  | @ -1023,6 +1043,11 @@ B<-no_tx_cert_comp>, | |||
| and B<-tfo> | ||||
| 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 | ||||
| 
 | ||||
| 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_ems>] | ||||
| [B<-status>] | ||||
| [B<-status_all>] | ||||
| [B<-status_verbose>] | ||||
| [B<-status_timeout> I<int>] | ||||
| [B<-proxy> I<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]>] | ||||
|  | @ -487,7 +488,15 @@ Disable Extended master secret negotiation. | |||
| 
 | ||||
| =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> | ||||
| 
 | ||||
|  | @ -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 | ||||
| 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> | ||||
| 
 | ||||
|  | @ -925,6 +936,8 @@ B<-no_tx_cert_comp>, | |||
| and B<-tfo> | ||||
| options were added in OpenSSL 3.2. | ||||
| 
 | ||||
| The B<-status_all> option was added in OpenSSL 3.6. | ||||
| 
 | ||||
| =head1 COPYRIGHT | ||||
| 
 | ||||
| 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_get_tlsext_status_type, | ||||
| 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 | ||||
| 
 | ||||
| =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_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 | ||||
| 
 | ||||
| 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 | ||||
| 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() | ||||
|  | @ -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> | ||||
| 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 | ||||
| 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 | ||||
| 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 | ||||
|  | @ -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 | ||||
| return B<TLSEXT_STATUSTYPE_ocsp>, or -1 otherwise. | ||||
| 
 | ||||
| The response returned by the server can be obtained via a call to | ||||
| SSL_get_tlsext_status_ocsp_resp(). The value B<*resp> will be updated to point | ||||
| to the OCSP response data and the return value will be the length of that data. | ||||
| Typically a callback would obtain an OCSP_RESPONSE object from this data via a | ||||
| call to the d2i_OCSP_RESPONSE() function. If the server has not provided any | ||||
| response data then B<*resp> will be NULL and the return value from | ||||
| A single response returned by the server (TLS < 1.3) can be obtained via a call | ||||
| to SSL_get_tlsext_status_ocsp_resp(). The value B<*resp> will be updated to | ||||
| point to the OCSP response data and the return value will be the length of that | ||||
| data. Typically a callback would obtain an OCSP_RESPONSE object from this data | ||||
| via a call to the d2i_OCSP_RESPONSE() function. If the server has not provided | ||||
| any response data then B<*resp> will be NULL and the return value from | ||||
| 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 | ||||
| if it wants to be able to provide clients with OCSP Certificate Status | ||||
| responses. Typically the server callback would obtain the server certificate | ||||
| that is being sent back to the client via a call to SSL_get_certificate(); | ||||
| obtain the 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. | ||||
| responses, where TLS 1.3 allows for multi-stapling, i.e., providing responses | ||||
| for all certificates in the chain of the server certificate (excluding the root | ||||
| CA certificate). | ||||
| The certificates sent back to the client and for which OCSP response(s) | ||||
| should be acquired could be obtained via call to SSL_get_certificate() resp. | ||||
| 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 | ||||
| 
 | ||||
|  | @ -93,8 +128,9 @@ returned) or SSL_TLSEXT_ERR_ALERT_FATAL (meaning that a fatal error has | |||
| occurred). | ||||
| 
 | ||||
| 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_set0_tlsext_status_ocsp_resp_ex() will return always 1. | ||||
| 
 | ||||
| SSL_CTX_get_tlsext_status_type() returns the value previously set by | ||||
| 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 | ||||
| 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 | ||||
| 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. | ||||
|  | @ -115,6 +154,9 @@ L<ssl(7)> | |||
| 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. | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 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 | ||||
| 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: | ||||
| unsupported signature algorithm> | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ X509_STORE_CTX_get0_rpk, | |||
| X509_STORE_CTX_set_default, | ||||
| X509_STORE_CTX_set_verify, | ||||
| X509_STORE_CTX_verify_fn, | ||||
| X509_STORE_CTX_set_ocsp_resp, | ||||
| X509_STORE_CTX_set_purpose, | ||||
| X509_STORE_CTX_set_trust, | ||||
| X509_STORE_CTX_purpose_inherit | ||||
|  | @ -56,6 +57,7 @@ X509_STORE_CTX_purpose_inherit | |||
|  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_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_trust(X509_STORE_CTX *ctx, int trust); | ||||
|  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 | ||||
| (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 | ||||
| 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>, | ||||
|  | @ -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_init_rpk(), X509_STORE_CTX_get0_rpk(), and | ||||
| 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. | ||||
| 
 | ||||
|  |  | |||
|  | @ -221,6 +221,7 @@ struct x509_store_ctx_st {      /* X509_STORE_CTX */ | |||
|     STACK_OF(X509) *untrusted; | ||||
|     /* set of CRLs passed in */ | ||||
|     STACK_OF(X509_CRL) *crls; | ||||
|     STACK_OF(OCSP_RESPONSE) *ocsp_resp; | ||||
|     X509_VERIFY_PARAM *param; | ||||
|     /* Other info for use with get_issuer() */ | ||||
|     void *other_ctx; | ||||
|  |  | |||
|  | @ -1342,6 +1342,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) | |||
| # define SSL_CTRL_GET0_IMPLEMENTED_GROUPS        139 | ||||
| # define SSL_CTRL_GET_SIGNATURE_NAME             140 | ||||
| # 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_NEXT                       2 | ||||
| # 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) \ | ||||
|         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) \ | ||||
|         SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,\ | ||||
|                 (void (*)(void))cb) | ||||
|  |  | |||
|  | @ -39,6 +39,8 @@ use OpenSSL::stackhash qw(generate_stack_macros); | |||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| DEFINE_STACK_OF(OCSP_RESPONSE) | ||||
| 
 | ||||
| /*-
 | ||||
| SSL_CTX -> X509_STORE | ||||
|                 -> 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_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 */ | ||||
| # ifndef OPENSSL_NO_DEPRECATED_1_1_0 | ||||
| #  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 */ | ||||
| # 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_OVERWRITE                  0x2 | ||||
| # 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_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); | ||||
| # 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_trust(X509_STORE_CTX *ctx, int trust); | ||||
| 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 "internal/cryptlib.h" | ||||
| #include "internal/ssl_unwrap.h" | ||||
| #include <openssl/ocsp.h> | ||||
| 
 | ||||
| #define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_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; | ||||
|     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
|     unsigned char *p = NULL; | ||||
|     OCSP_RESPONSE *resp = NULL; | ||||
| #endif | ||||
| 
 | ||||
|     if (sc == NULL) | ||||
|         return ret; | ||||
|  | @ -3666,16 +3671,79 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) | |||
|         break; | ||||
| 
 | ||||
|     case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: | ||||
|         *(unsigned char **)parg = sc->ext.ocsp.resp; | ||||
|         if (sc->ext.ocsp.resp_len == 0 | ||||
|                 || sc->ext.ocsp.resp_len > LONG_MAX) | ||||
|             return -1; | ||||
|         return (long)sc->ext.ocsp.resp_len; | ||||
|         *(unsigned char **)parg = NULL; | ||||
|         ret = -1; | ||||
| 
 | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
|         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: | ||||
|         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); | ||||
|         sc->ext.ocsp.resp = parg; | ||||
|         sc->ext.ocsp.resp_len = larg; | ||||
|             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 = 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; | ||||
|         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_VERIFY_PARAM *param; | ||||
|     SSL_CTX *sctx; | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
|     SSL *ssl; | ||||
| #endif | ||||
| 
 | ||||
|     /* Something must be passed in */ | ||||
|     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)) | ||||
|         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 | ||||
|      * 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.resp = NULL; | ||||
|     s->ext.ocsp.resp_len = 0; | ||||
|     s->ext.ocsp.resp_ex = NULL; | ||||
| 
 | ||||
|     if (!SSL_CTX_up_ref(ctx)) | ||||
|         goto err; | ||||
|  | @ -1497,14 +1498,20 @@ void ossl_ssl_connection_free(SSL *ssl) | |||
|     OPENSSL_free(s->ext.tuples); | ||||
|     OPENSSL_free(s->ext.peer_supportedgroups); | ||||
|     sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free); | ||||
| 
 | ||||
| #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_RESPONSE_pop_free(s->ext.ocsp.resp_ex, OCSP_RESPONSE_free); | ||||
|     s->ext.ocsp.resp_ex = NULL; | ||||
| #endif | ||||
| #ifndef OPENSSL_NO_CT | ||||
|     SCT_LIST_free(s->scts); | ||||
|     OPENSSL_free(s->ext.scts); | ||||
| #endif | ||||
|     OPENSSL_free(s->ext.ocsp.resp); | ||||
|     OPENSSL_free(s->ext.alpn); | ||||
|     OPENSSL_free(s->ext.tls13_cookie); | ||||
|     if (s->clienthello != NULL) | ||||
|  | @ -6428,17 +6435,17 @@ static int ct_extract_ocsp_response_scts(SSL_CONNECTION *s) | |||
| { | ||||
| # ifndef OPENSSL_NO_OCSP | ||||
|     int scts_extracted = 0; | ||||
|     const unsigned char *p; | ||||
|     OCSP_BASICRESP *br = NULL; | ||||
|     OCSP_RESPONSE *rsp = 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; | ||||
| 
 | ||||
|     p = s->ext.ocsp.resp; | ||||
|     rsp = d2i_OCSP_RESPONSE(NULL, &p, (int)s->ext.ocsp.resp_len); | ||||
|     for (j = 0; j < sk_OCSP_RESPONSE_num(s->ext.ocsp.resp_ex); j++) { | ||||
|         rsp = sk_OCSP_RESPONSE_value(s->ext.ocsp.resp_ex, j); | ||||
|         if (rsp == NULL) | ||||
|             goto err; | ||||
| 
 | ||||
|  | @ -6452,17 +6459,35 @@ static int ct_extract_ocsp_response_scts(SSL_CONNECTION *s) | |||
|             if (single == NULL) | ||||
|                 continue; | ||||
| 
 | ||||
|         scts = | ||||
|             OCSP_SINGLERESP_get1_ext_d2i(single, NID_ct_cert_scts, NULL, NULL); | ||||
|         scts_extracted = | ||||
|             ct_move_scts(&s->scts, scts, SCT_SOURCE_OCSP_STAPLED_RESPONSE); | ||||
|         if (scts_extracted < 0) | ||||
|             scts = OCSP_SINGLERESP_get1_ext_d2i(single, | ||||
|                                                 NID_ct_cert_scts, NULL, NULL); | ||||
| 
 | ||||
|             OCSP_SINGLERESP_free(single); | ||||
| 
 | ||||
|             if (scts == NULL)  { | ||||
|                 scts_extracted = -1; | ||||
|                 goto err; | ||||
|             } | ||||
|  err: | ||||
| 
 | ||||
|             ret = ct_move_scts(&s->scts, scts, | ||||
|                                SCT_SOURCE_OCSP_STAPLED_RESPONSE); | ||||
| 
 | ||||
|             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_RESPONSE_free(rsp); | ||||
|     return scts_extracted; | ||||
| # else | ||||
|     /* Behave as if no OCSP response exists */ | ||||
|  |  | |||
|  | @ -1639,6 +1639,7 @@ struct ssl_connection_st { | |||
|             /* OCSP response received or to be sent */ | ||||
|             unsigned char *resp; | ||||
|             size_t resp_len; | ||||
|             STACK_OF(OCSP_RESPONSE) *resp_ex; | ||||
|         } ocsp; | ||||
| 
 | ||||
|         /* 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_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_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, | ||||
|                                    int ref); | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ | |||
| #include "internal/ssl_unwrap.h" | ||||
| #include "../ssl_local.h" | ||||
| #include "statem_local.h" | ||||
| #include <openssl/ocsp.h> | ||||
| 
 | ||||
| static int final_renegotiate(SSL_CONNECTION *s, unsigned int context, int sent); | ||||
| 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); | ||||
|         s->ext.ocsp.resp = NULL; | ||||
|         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; | ||||
|  |  | |||
|  | @ -1510,14 +1510,8 @@ int tls_parse_stoc_status_request(SSL_CONNECTION *s, PACKET *pkt, | |||
|     } | ||||
| 
 | ||||
|     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 */ | ||||
|         return tls_process_cert_status_body(s, pkt); | ||||
|         return tls_process_cert_status_body(s, chainidx, pkt); | ||||
|     } | ||||
| 
 | ||||
|     /* 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) | ||||
|         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) | ||||
|             || !WPACKET_start_sub_packet_u16(pkt)) { | ||||
|         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 | ||||
|      * 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 */ | ||||
|         return EXT_RETURN_FAIL; | ||||
|     } | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
| #include "internal/cryptlib.h" | ||||
| #include "internal/comp.h" | ||||
| #include "internal/ssl_unwrap.h" | ||||
| #include <openssl/ocsp.h> | ||||
| 
 | ||||
| static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL_CONNECTION *s, | ||||
|                                                              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 | ||||
|  * 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; | ||||
| #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) | ||||
|         || type != TLSEXT_STATUSTYPE_ocsp) { | ||||
|         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_UNSUPPORTED_STATUS_TYPE); | ||||
|         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) | ||||
|             || PACKET_remaining(pkt) != resplen) { | ||||
|             SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); | ||||
|             return 0; | ||||
|         } | ||||
|     s->ext.ocsp.resp = OPENSSL_malloc(resplen); | ||||
|     if (s->ext.ocsp.resp == NULL) { | ||||
|         s->ext.ocsp.resp_len = 0; | ||||
| 
 | ||||
|         if (resplen > 0) { | ||||
|             respder = OPENSSL_malloc(resplen); | ||||
| 
 | ||||
|             if (respder == NULL) { | ||||
|                 SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); | ||||
|                 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); | ||||
|                 OPENSSL_free(respder); | ||||
|                 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; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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 */ | ||||
|         return MSG_PROCESS_ERROR; | ||||
|     } | ||||
|  |  | |||
|  | @ -148,7 +148,7 @@ __owur MSG_PROCESS_RETURN tls_process_certificate_request(SSL_CONNECTION *s, | |||
|                                                           PACKET *pkt); | ||||
| __owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, | ||||
|                                                          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, | ||||
|                                                   PACKET *pkt); | ||||
| __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, | ||||
|                                                          WPACKET *pkt); | ||||
| __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, | ||||
|                                                  WPACKET *pkt); | ||||
| __owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL_CONNECTION *s, | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ | |||
| #include <openssl/asn1t.h> | ||||
| #include <openssl/comp.h> | ||||
| #include "internal/comp.h" | ||||
| #include <openssl/ocsp.h> | ||||
| 
 | ||||
| #define TICKET_NONCE_SIZE       8 | ||||
| 
 | ||||
|  | @ -2193,8 +2194,11 @@ static int tls_handle_status_request(SSL_CONNECTION *s) | |||
|                 break; | ||||
|                 /* status request response should be sent */ | ||||
|             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; | ||||
| #endif | ||||
|                 break; | ||||
|                 /* something bad happened */ | ||||
|             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) { | ||||
|         int rv = tls_early_post_process_client_hello(s); | ||||
| 
 | ||||
|         if (rv == 0) { | ||||
|             /* SSLfatal() was already called */ | ||||
|             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 | ||||
|  * 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) | ||||
|             || !WPACKET_sub_memcpy_u24(pkt, s->ext.ocsp.resp, | ||||
|                                        s->ext.ocsp.resp_len)) { | ||||
|     unsigned char *respder = NULL; | ||||
|     int resplen = 0; | ||||
| #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); | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| 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 */ | ||||
|         return CON_FUNC_ERROR; | ||||
|     } | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include <openssl/x509_vfy.h> | ||||
| #include <openssl/ssl.h> | ||||
| #include <openssl/core_names.h> | ||||
| #include <openssl/ocsp.h> | ||||
| 
 | ||||
| #include "../../ssl/ssl_local.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; | ||||
| } | ||||
| 
 | ||||
| static unsigned char dummy_ocsp_resp_good_val = 0xff; | ||||
| static unsigned char dummy_ocsp_resp_bad_val = 0xfe; | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| 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) | ||||
| { | ||||
|     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 | ||||
|      */ | ||||
|     *resp = *(unsigned char *)arg; | ||||
|     if (!SSL_set_tlsext_status_ocsp_resp(s, resp, 1)) { | ||||
|         OPENSSL_free(resp); | ||||
|     if (!SSL_set_tlsext_status_ocsp_resp(s, respder, resplen)) { | ||||
|         OPENSSL_free(respder); | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| static int client_ocsp_cb(SSL *s, void *arg) | ||||
| { | ||||
|     const unsigned char *resp; | ||||
|     int len; | ||||
|     const unsigned char *resp, *p; | ||||
|     OCSP_RESPONSE *rsp; | ||||
|     int len, status; | ||||
| 
 | ||||
|     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); | ||||
|     return 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(); | ||||
|     SSL *ssl; | ||||
| 
 | ||||
|  | @ -320,7 +374,8 @@ static int verify_retry_cb(X509_STORE_CTX *ctx, void *arg) { | |||
|     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; | ||||
| } | ||||
| 
 | ||||
|  | @ -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) { | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
| #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_arg(server_ctx, | ||||
|             ((extra->server.cert_status == SSL_TEST_CERT_STATUS_GOOD_RESPONSE) | ||||
|             ? &dummy_ocsp_resp_good_val : &dummy_ocsp_resp_bad_val)); | ||||
|             SSL_CTX_set_tlsext_status_arg(server_ctx, dummy_ocsp_resp); | ||||
| 
 | ||||
|             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[] = { | ||||
|     {"None", SSL_TEST_CERT_STATUS_NONE}, | ||||
|     {"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, | ||||
|  |  | |||
|  | @ -88,7 +88,9 @@ typedef enum { | |||
| typedef enum { | ||||
|     SSL_TEST_CERT_STATUS_NONE = 0, /* Default */ | ||||
|     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; | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -1,9 +1,11 @@ | |||
| # Generated with generate_ssl_tests.pl | ||||
| 
 | ||||
| num_tests = 2 | ||||
| num_tests = 4 | ||||
| 
 | ||||
| test-0 = 0-certstatus-good | ||||
| test-1 = 1-certstatus-bad | ||||
| test-2 = 2-certstatus-good-ext | ||||
| test-3 = 3-certstatus-bad-ext | ||||
| # =========================================================== | ||||
| 
 | ||||
| [0-certstatus-good] | ||||
|  | @ -60,3 +62,59 @@ server = 1-certstatus-bad-server-extra | |||
| 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" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         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 | ||||
| 
 | ||||
| num_tests = 2 | ||||
| num_tests = 4 | ||||
| 
 | ||||
| test-0 = 0-certstatus-good | ||||
| test-1 = 1-certstatus-bad | ||||
| test-2 = 2-certstatus-good-ext | ||||
| test-3 = 3-certstatus-bad-ext | ||||
| # =========================================================== | ||||
| 
 | ||||
| [0-certstatus-good] | ||||
|  | @ -60,3 +62,59 @@ server = 1-certstatus-bad-server-extra | |||
| 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", | ||||
|             "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" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         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")) { | ||||
|  |  | |||
|  | @ -82,6 +82,13 @@ static int find_session_cb_cnt = 0; | |||
| static int end_of_early_data = 0; | ||||
| #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 *cert = NULL; | ||||
| static char *privkey = NULL; | ||||
|  | @ -110,10 +117,11 @@ static size_t client_log_buffer_index = 0; | |||
| static int error_writing_log = 0; | ||||
| 
 | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
| static const unsigned char orespder[] = "Dummy OCSP Response"; | ||||
| static int ocsp_server_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 X509 *ocspcert = NULL; | ||||
| #endif | ||||
|  | @ -1734,7 +1742,7 @@ static int execute_cleanse_plaintext(const SSL_METHOD *smeth, | |||
|         if (is_fips) { | ||||
|             testresult = 1; | ||||
|             goto end; | ||||
|         }; | ||||
|         } | ||||
|         /*
 | ||||
|          * Default sigalgs are SHA1 based in <DTLS1.2 which is in security | ||||
|          * level 0 | ||||
|  | @ -1847,12 +1855,62 @@ static int test_cleanse_plaintext(void) | |||
| } | ||||
| 
 | ||||
| #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; | ||||
|     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; | ||||
|     OCSP_RESPID *id = NULL; | ||||
|     unsigned char *ocsp_resp_der = NULL; | ||||
|     int resplen = 0; | ||||
| 
 | ||||
|     if (*argi == 2) { | ||||
|         /* 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; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     if (!TEST_true(SSL_set_tlsext_status_ocsp_resp(s, copy, | ||||
|                                                    sizeof(orespder)))) { | ||||
|         OPENSSL_free(copy); | ||||
|     resplen = i2d_OCSP_RESPONSE(ocsp_resp, &ocsp_resp_der); | ||||
|     OCSP_RESPONSE_free(ocsp_resp); | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
|     OPENSSL_free(ocsp_resp_der); | ||||
| 
 | ||||
|     ocsp_server_called = 1; | ||||
|     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; | ||||
|     const unsigned char *respderin; | ||||
|     size_t len; | ||||
|     const unsigned char *resp, *p; | ||||
|     OCSP_RESPONSE *rsp; | ||||
|     int len, resp_status; | ||||
| 
 | ||||
|     if (*argi != 1 && *argi != 2) | ||||
|         return 0; | ||||
| 
 | ||||
|     len = SSL_get_tlsext_status_ocsp_resp(s, &respderin); | ||||
|     if (!TEST_mem_eq(orespder, len, respderin, len)) | ||||
|     len = SSL_get_tlsext_status_ocsp_resp(s, &resp); | ||||
|     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; | ||||
| 
 | ||||
|     ocsp_client_called = 1; | ||||
|  | @ -1899,17 +1971,22 @@ static int ocsp_client_cb(SSL *s, void *arg) | |||
| static int test_tlsext_status_type(void) | ||||
| { | ||||
|     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; | ||||
|     int testresult = 0; | ||||
|     STACK_OF(OCSP_RESPID) *ids = NULL; | ||||
|     OCSP_RESPID *id = 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(), | ||||
|                              TLS1_VERSION, 0, | ||||
|                              &sctx, &cctx, cert, privkey)) | ||||
|                              &sctx, &cctx, leaf, skey)) | ||||
|         return 0; | ||||
| 
 | ||||
|     if (SSL_CTX_use_certificate_chain_file(sctx, leaf_chain) <= 0) | ||||
|         goto end; | ||||
|     if (SSL_CTX_get_tlsext_status_type(cctx) != -1) | ||||
|         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 | ||||
|      * 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_cb(sctx, ocsp_server_cb); | ||||
|     SSL_CTX_set_tlsext_status_cb(sctx, ocsp_server_cb_single); | ||||
|     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, | ||||
|                                       &clientssl, NULL, NULL)) | ||||
|             || !TEST_true(create_ssl_connection(serverssl, clientssl, | ||||
|  | @ -2016,19 +2096,351 @@ static int test_tlsext_status_type(void) | |||
| 
 | ||||
|     testresult = 1; | ||||
| 
 | ||||
|  end: | ||||
| end: | ||||
|     SSL_free(serverssl); | ||||
|     SSL_free(clientssl); | ||||
|     SSL_CTX_free(sctx); | ||||
|     SSL_CTX_free(cctx); | ||||
|     OPENSSL_free(leaf_chain); | ||||
|     OPENSSL_free(skey); | ||||
|     OPENSSL_free(leaf); | ||||
|     sk_OCSP_RESPID_pop_free(ids, OCSP_RESPID_free); | ||||
|     OCSP_RESPID_free(id); | ||||
|     BIO_free(certbio); | ||||
|     X509_free(ocspcert); | ||||
|     OSSL_LIB_CTX_set0_default(tmpctx); | ||||
|     ocspcert = NULL; | ||||
| 
 | ||||
|     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 | ||||
| 
 | ||||
| #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); | ||||
| #ifndef OPENSSL_NO_OCSP | ||||
|     ADD_TEST(test_tlsext_status_type); | ||||
| # ifndef OSSL_NO_USABLE_TLS1_3 | ||||
|     ADD_TEST(test_tlsext_status_type_multi); | ||||
| # endif | ||||
| #endif | ||||
|     ADD_TEST(test_session_with_only_int_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: | ||||
| PEM_ASN1_write_bio_ctx                  ?	3_5_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: | ||||
| i2d_PKCS8PrivateKey                     ?	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_timeout                         define | ||||
| SSL_get_tlsext_status_ocsp_resp         define | ||||
| SSL_get0_tlsext_status_ocsp_resp_ex     define | ||||
| SSL_get_tlsext_status_type              define | ||||
| SSL_get_tmp_key                         define | ||||
| SSL_in_accept_init                      define | ||||
|  | @ -690,6 +691,7 @@ SSL_set_time                            define | |||
| SSL_set_timeout                         define | ||||
| SSL_set_tlsext_host_name                define | ||||
| SSL_set_tlsext_status_ocsp_resp         define | ||||
| SSL_set0_tlsext_status_ocsp_resp_ex     define | ||||
| SSL_set_tlsext_status_type              define | ||||
| SSL_set_tmp_dh                          define | ||||
| SSL_set_tmp_ecdh                        define | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue