@ -1,6 +1,6 @@
/*
* SSL / TLS interface functions for OpenSSL
* Copyright ( c ) 2004 - 201 1 , Jouni Malinen < j @ w1 . fi >
* Copyright ( c ) 2004 - 201 3 , Jouni Malinen < j @ w1 . fi >
*
* This software may be distributed under the terms of the BSD license .
* See README for more details .
@ -51,6 +51,13 @@
# endif
# endif
# ifdef SSL_set_tlsext_status_type
# ifndef OPENSSL_NO_TLSEXT
# define HAVE_OCSP
# include <openssl/ocsp.h>
# endif /* OPENSSL_NO_TLSEXT */
# endif /* SSL_set_tlsext_status_type */
static int tls_openssl_ref_count = 0 ;
struct tls_context {
@ -58,6 +65,7 @@ struct tls_context {
union tls_event_data * data ) ;
void * cb_ctx ;
int cert_in_cb ;
char * ocsp_stapling_response ;
} ;
static struct tls_context * tls_global = NULL ;
@ -88,6 +96,9 @@ struct tls_connection {
u8 srv_cert_hash [ 32 ] ;
unsigned int flags ;
X509 * peer_cert ;
X509 * peer_issuer ;
} ;
@ -827,6 +838,8 @@ void tls_deinit(void *ssl_ctx)
ERR_remove_state ( 0 ) ;
ERR_free_strings ( ) ;
EVP_cleanup ( ) ;
os_free ( tls_global - > ocsp_stapling_response ) ;
tls_global - > ocsp_stapling_response = NULL ;
os_free ( tls_global ) ;
tls_global = NULL ;
}
@ -1241,6 +1254,12 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
conn = SSL_get_app_data ( ssl ) ;
if ( conn = = NULL )
return 0 ;
if ( depth = = 0 )
conn - > peer_cert = err_cert ;
else if ( depth = = 1 )
conn - > peer_issuer = err_cert ;
context = conn - > context ;
match = conn - > subject_match ;
altmatch = conn - > altsubject_match ;
@ -2755,11 +2774,187 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
}
# ifdef HAVE_OCSP
static void ocsp_debug_print_resp ( OCSP_RESPONSE * rsp )
{
# ifndef CONFIG_NO_STDOUT_DEBUG
extern int wpa_debug_level ;
BIO * out ;
size_t rlen ;
char * txt ;
int res ;
if ( wpa_debug_level > MSG_DEBUG )
return ;
out = BIO_new ( BIO_s_mem ( ) ) ;
if ( ! out )
return ;
OCSP_RESPONSE_print ( out , rsp , 0 ) ;
rlen = BIO_ctrl_pending ( out ) ;
txt = os_malloc ( rlen + 1 ) ;
if ( ! txt ) {
BIO_free ( out ) ;
return ;
}
res = BIO_read ( out , txt , rlen ) ;
if ( res > 0 ) {
txt [ res ] = ' \0 ' ;
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP Response \n %s " , txt ) ;
}
os_free ( txt ) ;
BIO_free ( out ) ;
# endif /* CONFIG_NO_STDOUT_DEBUG */
}
static int ocsp_resp_cb ( SSL * s , void * arg )
{
struct tls_connection * conn = arg ;
const unsigned char * p ;
int len , status , reason ;
OCSP_RESPONSE * rsp ;
OCSP_BASICRESP * basic ;
OCSP_CERTID * id ;
ASN1_GENERALIZEDTIME * produced_at , * this_update , * next_update ;
len = SSL_get_tlsext_status_ocsp_resp ( s , & p ) ;
if ( ! p ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: No OCSP response received " ) ;
return ( conn - > flags & TLS_CONN_REQUIRE_OCSP ) ? 0 : 1 ;
}
wpa_hexdump ( MSG_DEBUG , " OpenSSL: OCSP response " , p , len ) ;
rsp = d2i_OCSP_RESPONSE ( NULL , & p , len ) ;
if ( ! rsp ) {
wpa_printf ( MSG_INFO , " OpenSSL: Failed to parse OCSP response " ) ;
return 0 ;
}
ocsp_debug_print_resp ( rsp ) ;
status = OCSP_response_status ( rsp ) ;
if ( status ! = OCSP_RESPONSE_STATUS_SUCCESSFUL ) {
wpa_printf ( MSG_INFO , " OpenSSL: OCSP responder error %d (%s) " ,
status , OCSP_response_status_str ( status ) ) ;
return 0 ;
}
basic = OCSP_response_get1_basic ( rsp ) ;
if ( ! basic ) {
wpa_printf ( MSG_INFO , " OpenSSL: Could not find BasicOCSPResponse " ) ;
return 0 ;
}
status = OCSP_basic_verify ( basic , NULL , SSL_CTX_get_cert_store ( s - > ctx ) ,
0 ) ;
if ( status < = 0 ) {
tls_show_errors ( MSG_INFO , __func__ ,
" OpenSSL: OCSP response failed verification " ) ;
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
return 0 ;
}
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP response verification succeeded " ) ;
if ( ! conn - > peer_cert | | ! conn - > peer_issuer ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: Peer certificate or issue certificate not available for OCSP status check " ) ;
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
return 0 ;
}
id = OCSP_cert_to_id ( NULL , conn - > peer_cert , conn - > peer_issuer ) ;
if ( ! id ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: Could not create OCSP certificate identifier " ) ;
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
return 0 ;
}
if ( ! OCSP_resp_find_status ( basic , id , & status , & reason , & produced_at ,
& this_update , & next_update ) ) {
wpa_printf ( MSG_INFO , " OpenSSL: Could not find current server certificate from OCSP response%s " ,
( conn - > flags & TLS_CONN_REQUIRE_OCSP ) ? " " :
" (OCSP not required) " ) ;
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
return ( conn - > flags & TLS_CONN_REQUIRE_OCSP ) ? 0 : 1 ;
}
if ( ! OCSP_check_validity ( this_update , next_update , 5 * 60 , - 1 ) ) {
tls_show_errors ( MSG_INFO , __func__ ,
" OpenSSL: OCSP status times invalid " ) ;
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
return 0 ;
}
OCSP_BASICRESP_free ( basic ) ;
OCSP_RESPONSE_free ( rsp ) ;
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status for server certificate: %s " ,
OCSP_cert_status_str ( status ) ) ;
if ( status = = V_OCSP_CERTSTATUS_GOOD )
return 1 ;
if ( status = = V_OCSP_CERTSTATUS_REVOKED )
return 0 ;
if ( conn - > flags & TLS_CONN_REQUIRE_OCSP ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status unknown, but OCSP required " ) ;
return 0 ;
}
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue " ) ;
return 1 ;
}
static int ocsp_status_cb ( SSL * s , void * arg )
{
char * tmp ;
char * resp ;
size_t len ;
if ( tls_global - > ocsp_stapling_response = = NULL ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status callback - no response configured " ) ;
return SSL_TLSEXT_ERR_OK ;
}
resp = os_readfile ( tls_global - > ocsp_stapling_response , & len ) ;
if ( resp = = NULL ) {
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status callback - could not read response file " ) ;
/* TODO: Build OCSPResponse with responseStatus = internalError
*/
return SSL_TLSEXT_ERR_OK ;
}
wpa_printf ( MSG_DEBUG , " OpenSSL: OCSP status callback - send cached response " ) ;
tmp = OPENSSL_malloc ( len ) ;
if ( tmp = = NULL ) {
os_free ( resp ) ;
return SSL_TLSEXT_ERR_ALERT_FATAL ;
}
os_memcpy ( tmp , resp , len ) ;
os_free ( resp ) ;
SSL_set_tlsext_status_ocsp_resp ( s , tmp , len ) ;
return SSL_TLSEXT_ERR_OK ;
}
# endif /* HAVE_OCSP */
int tls_connection_set_params ( void * tls_ctx , struct tls_connection * conn ,
const struct tls_connection_params * params )
{
int ret ;
unsigned long err ;
SSL_CTX * ssl_ctx = tls_ctx ;
if ( conn = = NULL )
return - 1 ;
@ -2827,6 +3022,14 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
SSL_clear_options ( conn - > ssl , SSL_OP_NO_TICKET ) ;
# endif /* SSL_OP_NO_TICKET */
# ifdef HAVE_OCSP
if ( params - > flags & TLS_CONN_REQUEST_OCSP ) {
SSL_set_tlsext_status_type ( conn - > ssl , TLSEXT_STATUSTYPE_ocsp ) ;
SSL_CTX_set_tlsext_status_cb ( ssl_ctx , ocsp_resp_cb ) ;
SSL_CTX_set_tlsext_status_arg ( ssl_ctx , conn ) ;
}
# endif /* HAVE_OCSP */
conn - > flags = params - > flags ;
tls_get_errors ( tls_ctx ) ;
@ -2869,6 +3072,17 @@ int tls_global_set_params(void *tls_ctx,
SSL_CTX_clear_options ( ssl_ctx , SSL_OP_NO_TICKET ) ;
# endif /* SSL_OP_NO_TICKET */
# ifdef HAVE_OCSP
SSL_CTX_set_tlsext_status_cb ( ssl_ctx , ocsp_status_cb ) ;
SSL_CTX_set_tlsext_status_arg ( ssl_ctx , ssl_ctx ) ;
os_free ( tls_global - > ocsp_stapling_response ) ;
if ( params - > ocsp_stapling_response )
tls_global - > ocsp_stapling_response =
os_strdup ( params - > ocsp_stapling_response ) ;
else
tls_global - > ocsp_stapling_response = NULL ;
# endif /* HAVE_OCSP */
return 0 ;
}