mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-17 18:34:03 -05:00
TLS server: OCSP stapling with ocsp_multi option (RFC 6961)
This allows hostapd with the internal TLS server implementation to support the extended OCSP stapling mechanism with multiple responses (ocsp_stapling_response_multi). Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
5addb0df59
commit
8ea6a27003
@ -334,6 +334,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
if (params->ocsp_stapling_response)
|
||||
cred->ocsp_stapling_response =
|
||||
os_strdup(params->ocsp_stapling_response);
|
||||
if (params->ocsp_stapling_response_multi)
|
||||
cred->ocsp_stapling_response_multi =
|
||||
os_strdup(params->ocsp_stapling_response_multi);
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
|
@ -170,6 +170,7 @@ enum {
|
||||
#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
|
||||
#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
|
||||
#define TLS_EXT_SIGNATURE_ALGORITHMS 13 /* RFC 5246 */
|
||||
#define TLS_EXT_STATUS_REQUEST_V2 17 /* RFC 6961 */
|
||||
#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */
|
||||
|
||||
#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
|
||||
|
@ -37,6 +37,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
|
||||
os_free(cred->dh_p);
|
||||
os_free(cred->dh_g);
|
||||
os_free(cred->ocsp_stapling_response);
|
||||
os_free(cred->ocsp_stapling_response_multi);
|
||||
os_free(cred);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ struct tlsv1_credentials {
|
||||
size_t dh_g_len;
|
||||
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
};
|
||||
|
||||
|
||||
|
@ -56,6 +56,8 @@ struct tlsv1_server {
|
||||
|
||||
int use_session_ticket;
|
||||
unsigned int status_request:1;
|
||||
unsigned int status_request_v2:1;
|
||||
unsigned int status_request_multi:1;
|
||||
|
||||
u8 *dh_secret;
|
||||
size_t dh_secret_len;
|
||||
|
@ -46,6 +46,78 @@ static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
|
||||
}
|
||||
|
||||
|
||||
static void tls_process_status_request_item(struct tlsv1_server *conn,
|
||||
const u8 *req, size_t req_len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 status_type;
|
||||
|
||||
pos = req;
|
||||
end = req + req_len;
|
||||
|
||||
/*
|
||||
* RFC 6961, 2.2:
|
||||
* struct {
|
||||
* CertificateStatusType status_type;
|
||||
* uint16 request_length;
|
||||
* select (status_type) {
|
||||
* case ocsp: OCSPStatusRequest;
|
||||
* case ocsp_multi: OCSPStatusRequest;
|
||||
* } request;
|
||||
* } CertificateStatusRequestItemV2;
|
||||
*
|
||||
* enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
|
||||
*/
|
||||
|
||||
if (end - pos < 1)
|
||||
return; /* Truncated data */
|
||||
|
||||
status_type = *pos++;
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatusType %u", status_type);
|
||||
if (status_type != 1 && status_type != 2)
|
||||
return; /* Unsupported status type */
|
||||
/*
|
||||
* For now, only OCSP stapling is supported, so ignore the specific
|
||||
* request, if any.
|
||||
*/
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: OCSPStatusRequest", pos, end - pos);
|
||||
|
||||
if (status_type == 2)
|
||||
conn->status_request_multi = 1;
|
||||
}
|
||||
|
||||
|
||||
static void tls_process_status_request_v2(struct tlsv1_server *conn,
|
||||
const u8 *ext, size_t ext_len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
|
||||
conn->status_request_v2 = 1;
|
||||
|
||||
pos = ext;
|
||||
end = ext + ext_len;
|
||||
|
||||
/*
|
||||
* RFC 6961, 2.2:
|
||||
* struct {
|
||||
* CertificateStatusRequestItemV2
|
||||
* certificate_status_req_list<1..2^16-1>;
|
||||
* } CertificateStatusRequestListV2;
|
||||
*/
|
||||
|
||||
while (end - pos >= 2) {
|
||||
u16 len;
|
||||
|
||||
len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (len > end - pos)
|
||||
break; /* Truncated data */
|
||||
tls_process_status_request_item(conn, pos, len);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
|
||||
const u8 *in_data, size_t *in_len)
|
||||
{
|
||||
@ -269,6 +341,9 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
|
||||
}
|
||||
} else if (ext_type == TLS_EXT_STATUS_REQUEST) {
|
||||
conn->status_request = 1;
|
||||
} else if (ext_type == TLS_EXT_STATUS_REQUEST_V2) {
|
||||
tls_process_status_request_v2(conn, pos,
|
||||
ext_len);
|
||||
}
|
||||
|
||||
pos += ext_len;
|
||||
|
@ -111,6 +111,18 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if (conn->status_request_v2) {
|
||||
/*
|
||||
Add a status_request_v2 extension with empty extension_data
|
||||
*/
|
||||
/* ExtensionsType extension_type = status_request_v2(17) */
|
||||
WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
|
||||
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,
|
||||
@ -264,30 +276,31 @@ 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 **msgpos, u8 *end,
|
||||
int ocsp_multi,
|
||||
char *ocsp_resp,
|
||||
size_t ocsp_resp_len)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
char *resp;
|
||||
size_t rlen, len;
|
||||
size_t rlen;
|
||||
|
||||
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 */
|
||||
if (!ocsp_resp) {
|
||||
/*
|
||||
* Client did not request certificate status or there is no
|
||||
* matching response cached.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = *msgpos;
|
||||
if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + len >
|
||||
if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_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");
|
||||
tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
@ -307,20 +320,27 @@ static int tls_write_server_certificate_status(struct tlsv1_server *conn,
|
||||
* CertificateStatusType status_type;
|
||||
* select (status_type) {
|
||||
* case ocsp: OCSPResponse;
|
||||
* case ocsp_multi: OCSPResponseList;
|
||||
* } response;
|
||||
* } CertificateStatus;
|
||||
*
|
||||
* opaque OCSPResponse<1..2^24-1>;
|
||||
*
|
||||
* struct {
|
||||
* OCSPResponse ocsp_response_list<1..2^24-1>;
|
||||
* } OCSPResponseList;
|
||||
*/
|
||||
|
||||
/* CertificateStatusType status_type */
|
||||
*pos++ = 1; /* ocsp(1) */
|
||||
if (ocsp_multi)
|
||||
*pos++ = 2; /* ocsp_multi(2) */
|
||||
else
|
||||
*pos++ = 1; /* ocsp(1) */
|
||||
/* uint24 length of OCSPResponse */
|
||||
WPA_PUT_BE24(pos, len);
|
||||
WPA_PUT_BE24(pos, ocsp_resp_len);
|
||||
pos += 3;
|
||||
os_memcpy(pos, resp, len);
|
||||
os_free(resp);
|
||||
pos += len;
|
||||
os_memcpy(pos, ocsp_resp, ocsp_resp_len);
|
||||
pos += ocsp_resp_len;
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
@ -908,34 +928,46 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
|
||||
{
|
||||
u8 *msg, *end, *pos;
|
||||
size_t msglen;
|
||||
int ocsp_multi = 0;
|
||||
char *ocsp_resp = NULL;
|
||||
size_t ocsp_resp_len = 0;
|
||||
|
||||
*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);
|
||||
}
|
||||
if (conn->status_request_multi &&
|
||||
conn->cred->ocsp_stapling_response_multi) {
|
||||
ocsp_resp = os_readfile(
|
||||
conn->cred->ocsp_stapling_response_multi,
|
||||
&ocsp_resp_len);
|
||||
ocsp_multi = 1;
|
||||
} else if ((conn->status_request || conn->status_request_v2) &&
|
||||
conn->cred->ocsp_stapling_response) {
|
||||
ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
|
||||
&ocsp_resp_len);
|
||||
}
|
||||
if (!ocsp_resp)
|
||||
ocsp_resp_len = 0;
|
||||
|
||||
msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
|
||||
|
||||
msg = os_malloc(msglen);
|
||||
if (msg == NULL)
|
||||
if (msg == NULL) {
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = msg;
|
||||
end = msg + msglen;
|
||||
|
||||
if (tls_write_server_hello(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conn->use_session_ticket) {
|
||||
os_free(ocsp_resp);
|
||||
|
||||
/* Abbreviated handshake using session ticket; RFC 4507 */
|
||||
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
|
||||
tls_write_server_finished(conn, &pos, end) < 0) {
|
||||
@ -952,13 +984,16 @@ 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_certificate_status(conn, &pos, end, ocsp_multi,
|
||||
ocsp_resp, ocsp_resp_len) < 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) {
|
||||
os_free(msg);
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
os_free(ocsp_resp);
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user