aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2015-12-22 17:37:12 (GMT)
committerJouni Malinen <j@w1.fi>2015-12-22 18:44:52 (GMT)
commit8ea6a270030ab67bfc1551904c07ec296bbf9b91 (patch)
tree722f305c51e7cd155b32ac766d7164eeb534af26 /src/tls
parent5addb0df596d50c7b00f5b2acee4611124b60f89 (diff)
downloadhostap-8ea6a270030ab67bfc1551904c07ec296bbf9b91.zip
hostap-8ea6a270030ab67bfc1551904c07ec296bbf9b91.tar.gz
hostap-8ea6a270030ab67bfc1551904c07ec296bbf9b91.tar.bz2
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>
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/tlsv1_common.h1
-rw-r--r--src/tls/tlsv1_cred.c1
-rw-r--r--src/tls/tlsv1_cred.h1
-rw-r--r--src/tls/tlsv1_server_i.h2
-rw-r--r--src/tls/tlsv1_server_read.c75
-rw-r--r--src/tls/tlsv1_server_write.c95
6 files changed, 145 insertions, 30 deletions
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index 7a252fe..e30b15a 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -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 */
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index 732ed4a..52c1ae0 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -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);
}
diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h
index cbf4d39..716e93c 100644
--- a/src/tls/tlsv1_cred.h
+++ b/src/tls/tlsv1_cred.h
@@ -26,6 +26,7 @@ struct tlsv1_credentials {
size_t dh_g_len;
char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
};
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 81439d1..29c6678 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -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;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 5109b60..4aa8a01 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -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;
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index dafe3f9..bdc6c11 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -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;