From bca0872dd5c72135827355c4be1f772cc9641a84 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 22 Dec 2015 17:53:45 +0200 Subject: [PATCH] TLS server: OCSP stapling This adds support for hostapd-as-authentication-server to be build with the internal TLS implementation and OCSP stapling server side support. This is more or less identical to the design used with OpenSSL, i.e., the cached response is read from the ocsp_stapling_response= and sent as a response if the client requests it during the TLS handshake. Signed-off-by: Jouni Malinen --- src/crypto/tls_internal.c | 4 ++ src/tls/tlsv1_cred.c | 1 + src/tls/tlsv1_cred.h | 2 + src/tls/tlsv1_server_i.h | 1 + src/tls/tlsv1_server_read.c | 2 + src/tls/tlsv1_server_write.c | 111 ++++++++++++++++++++++++++++++++++- 6 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 8b90d5652..4b87b304f 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -331,6 +331,10 @@ int tls_global_set_params(void *tls_ctx, return -1; } + if (params->ocsp_stapling_response) + cred->ocsp_stapling_response = + os_strdup(params->ocsp_stapling_response); + return 0; #else /* CONFIG_TLS_INTERNAL_SERVER */ return -1; diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c index 92f97c7f7..732ed4aa1 100644 --- a/src/tls/tlsv1_cred.c +++ b/src/tls/tlsv1_cred.c @@ -36,6 +36,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred) crypto_private_key_free(cred->key); os_free(cred->dh_p); os_free(cred->dh_g); + os_free(cred->ocsp_stapling_response); os_free(cred); } diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h index b4bfe38d5..cbf4d39e4 100644 --- a/src/tls/tlsv1_cred.h +++ b/src/tls/tlsv1_cred.h @@ -24,6 +24,8 @@ struct tlsv1_credentials { size_t dh_p_len; u8 *dh_g; /* generator */ size_t dh_g_len; + + char *ocsp_stapling_response; }; diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h index 96d79b3a8..81439d15e 100644 --- a/src/tls/tlsv1_server_i.h +++ b/src/tls/tlsv1_server_i.h @@ -55,6 +55,7 @@ struct tlsv1_server { void *log_cb_ctx; int use_session_ticket; + unsigned int status_request:1; u8 *dh_secret; size_t dh_secret_len; diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 8347d7acc..5109b6071 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -267,6 +267,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, ext_len); conn->session_ticket_len = ext_len; } + } else if (ext_type == TLS_EXT_STATUS_REQUEST) { + conn->status_request = 1; } pos += ext_len; diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index e7c5e2254..dafe3f970 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -42,7 +42,7 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) static int tls_write_server_hello(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr, *hs_start, *hs_length; + u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start; struct os_time now; size_t rlen; @@ -97,6 +97,20 @@ static int tls_write_server_hello(struct tlsv1_server *conn, /* CompressionMethod compression_method */ *pos++ = TLS_COMPRESSION_NULL; + /* Extension */ + ext_start = pos; + pos += 2; + + if (conn->status_request) { + /* Add a status_request extension with empty extension_data */ + /* ExtensionsType extension_type = status_request(5) */ + WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST); + pos += 2; + /* opaque extension_data<0..2^16-1> length */ + WPA_PUT_BE16(pos, 0); + pos += 2; + } + if (conn->session_ticket && conn->session_ticket_cb) { int res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, @@ -133,6 +147,11 @@ static int tls_write_server_hello(struct tlsv1_server *conn, */ } + if (pos == ext_start + 2) + pos -= 2; /* no extensions */ + else + WPA_PUT_BE16(ext_start, pos - ext_start - 2); + WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); @@ -244,6 +263,85 @@ static int tls_write_server_certificate(struct tlsv1_server *conn, } +static int tls_write_server_certificate_status(struct tlsv1_server *conn, + u8 **msgpos, u8 *end) +{ + u8 *pos, *rhdr, *hs_start, *hs_length; + char *resp; + size_t rlen, len; + + if (!conn->status_request) + return 0; /* Client did not request certificate status */ + if (!conn->cred->ocsp_stapling_response) + return 0; /* No cached OCSP stapling response */ + resp = os_readfile(conn->cred->ocsp_stapling_response, &len); + if (!resp) + return 0; /* No cached OCSP stapling response */ + + pos = *msgpos; + if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + len > + (unsigned int) (end - pos)) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + os_free(resp); + return -1; + } + + tlsv1_server_log(conn, "Send CertificateStatus"); + rhdr = pos; + pos += TLS_RECORD_HEADER_LEN; + + /* opaque fragment[TLSPlaintext.length] */ + + /* Handshake */ + hs_start = pos; + /* HandshakeType msg_type */ + *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS; + /* uint24 length (to be filled) */ + hs_length = pos; + pos += 3; + + /* body - CertificateStatus + * + * struct { + * CertificateStatusType status_type; + * select (status_type) { + * case ocsp: OCSPResponse; + * } response; + * } CertificateStatus; + * + * opaque OCSPResponse<1..2^24-1>; + */ + + /* CertificateStatusType status_type */ + *pos++ = 1; /* ocsp(1) */ + /* uint24 length of OCSPResponse */ + WPA_PUT_BE24(pos, len); + pos += 3; + os_memcpy(pos, resp, len); + os_free(resp); + pos += len; + + WPA_PUT_BE24(hs_length, pos - hs_length - 3); + + if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + pos = rhdr + rlen; + + tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); + + *msgpos = pos; + + return 0; +} + + static int tls_write_server_key_exchange(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { @@ -814,6 +912,16 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) *out_len = 0; msglen = 1000 + tls_server_cert_chain_der_len(conn); + if (conn->status_request && conn->cred->ocsp_stapling_response) { + char *resp; + size_t len; + + resp = os_readfile(conn->cred->ocsp_stapling_response, &len); + if (resp) { + msglen += 10 + len; + os_free(resp); + } + } msg = os_malloc(msglen); if (msg == NULL) @@ -844,6 +952,7 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) /* Full handshake */ if (tls_write_server_certificate(conn, &pos, end) < 0 || + tls_write_server_certificate_status(conn, &pos, end) < 0 || tls_write_server_key_exchange(conn, &pos, end) < 0 || tls_write_server_certificate_request(conn, &pos, end) < 0 || tls_write_server_hello_done(conn, &pos, end) < 0) {