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=<file> and
sent as a response if the client requests it during the TLS handshake.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2015-12-22 17:53:45 +02:00 committed by Jouni Malinen
parent 8adce07a73
commit bca0872dd5
6 changed files with 120 additions and 1 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

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