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) {