Cumulative patch from commit 324ade51e168f28430f4429849becd0f08d507c0 (DO NOT MERGE)
324ade5 TLS: Make tls_cert_chain_failure_event() more robust
c6231b5 TLS: Remove storing of never-read value
15a6813 Remove unnecessary cleanup assignment in SHA1Final()
ef3866a nl80211: Don't call linux_iface_up() for a dedicated P2P Device
c2ed779 mesh: Document Mesh Peering Management element structure in more detail
b2817cd mesh: Check PMKID in AMPE Action frames
6c33eed mesh: Fix PMKID to match the standard
ede7770 wpa_supplicant: Do not wait for monitor on P2P Device interface
1c94570 Do not wait for monitor to attach if no control interface
f98674a Clone default LIBS value to LIBS_* for other tools
7d2f674 Add "GET_CAPABILITY acs" to allow ACS build option to be detected
d990971 wpa_supplicant: Enable Automatic Channel Selection support for AP mode
96bc508 Handle survey event properly in wpa_supplicant
d39f796 EAP-TNC peer: Remove dead code related to fragmentation
662512e P2PS: Remove dead code
abbbaa4 TNC: Print received IF-TNCCS message as debug ASCII hexdump
d745f02 EAP-TNC peer: Allow fragment_size to be configured
a67e7e5 RADIUS: Add EACCES to list of recognized send() errno values
5bd9be4 Fix RADIUS Called-Station-Id to not escape SSID
0764dd6 TLS client: Multi-OCSP check to cover intermediate CAs
d6b536f Add ocsp=3 configuration parameter for multi-OCSP
0268383 TLS: Move variable declaration to the beginning of the block
b567775 TLS client: OCSP stapling with ocsp_multi option (RFC 6961)
8ea6a27 TLS server: OCSP stapling with ocsp_multi option (RFC 6961)
5addb0d Server configuration for OCSP stapling with ocsp_multi (RFC 6961)
bca0872 TLS server: OCSP stapling
9532bd2 GnuTLS: OCSP stapling on the server side
6241766 Use wpa_msg() for the "RSN: PMKID mismatch" message
e161451 EAP-EKE: Merge identical error return paths
13cb0a6 EAP-EKE: Reject too long Prot() data when building a frame
0ab0de8 Document previously missing key_mgmt values
Change-Id: I9ac7d0da03d8baf4542e276ab20cb56e44bfa33c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cf9b2ce..88074f2 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -471,6 +471,7 @@
os_free(conf->private_key);
os_free(conf->private_key_passwd);
os_free(conf->ocsp_stapling_response);
+ os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ff9dcb0..44bcccc 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -341,6 +341,7 @@
int check_crl;
unsigned int tls_session_lifetime;
char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
u8 *pac_opaque_encr_key;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index c9111f6..cdb49cd 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -173,6 +173,8 @@
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
+ params.ocsp_stapling_response_multi =
+ hapd->conf->ocsp_stapling_response_multi;
if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index fd07201..aad0d81 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -549,8 +549,8 @@
#ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res)
{
int ret, i;
@@ -945,6 +945,8 @@
ieee802_1x_receive(hapd, src, data, data_len);
}
+#endif /* HOSTAPD */
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
@@ -1019,10 +1021,9 @@
}
-static void hostapd_event_get_survey(struct hostapd_data *hapd,
- struct survey_results *survey_results)
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results)
{
- struct hostapd_iface *iface = hapd->iface;
struct freq_survey *survey, *tmp;
struct hostapd_channel_data *chan;
@@ -1054,6 +1055,7 @@
}
+#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@ -1261,7 +1263,7 @@
data->connect_failed_reason.code);
break;
case EVENT_SURVEY:
- hostapd_event_get_survey(hapd, &data->survey_results);
+ hostapd_event_get_survey(hapd->iface, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8161a59..7b59f80 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -493,6 +493,11 @@
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2);
+struct survey_results;
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f566603..e3b3d94 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -475,6 +475,7 @@
{
char buf[128];
struct hostapd_radius_attr *attr;
+ int len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
@@ -506,15 +507,15 @@
return -1;
}
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
- buf[sizeof(buf) - 1] = '\0';
+ len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
+ MAC2STR(hapd->own_addr));
+ os_memcpy(&buf[len], hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+ len += hapd->conf->ssid.ssid_len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CALLED_STATION_ID) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
+ (u8 *) buf, len)) {
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
return -1;
}
diff --git a/src/common/sae.c b/src/common/sae.c
index b962ea2..6c00a7e 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -816,6 +816,7 @@
os_memset(keyseed, 0, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
os_memset(keys, 0, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
diff --git a/src/common/sae.h b/src/common/sae.h
index c07026c..a4270bc 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -45,6 +45,7 @@
enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
u16 send_confirm;
u8 pmk[SAE_PMK_LEN];
+ u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
int sync;
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index f6658e6..ffcba66 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -297,7 +297,6 @@
255);
}
/* Wipe variables */
- i = 0;
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index bca94d6..453b4de 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -96,6 +96,7 @@
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
#define TLS_CONN_EXT_CERT_CHECK BIT(9)
+#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -140,6 +141,9 @@
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
+ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
+ * response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
+ * ocsp_multi is not enabled
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -180,6 +184,7 @@
unsigned int flags;
const char *ocsp_stapling_response;
+ const char *ocsp_stapling_response_multi;
};
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index b1bec4a..c4cd3c1 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -37,6 +37,8 @@
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
+
+ char *ocsp_stapling_response;
};
struct tls_connection {
@@ -133,6 +135,7 @@
if (global->params_set)
gnutls_certificate_free_credentials(global->xcred);
os_free(global->session_data);
+ os_free(global->ocsp_stapling_response);
os_free(global);
}
@@ -347,6 +350,12 @@
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: ocsp=3 not supported");
+ return -1;
+ }
+
if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
wpa_printf(MSG_INFO,
"GnuTLS: tls_ext_cert_check=1 not supported");
@@ -602,6 +611,44 @@
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
+ gnutls_datum_t *resp)
+{
+ struct tls_global *global = ptr;
+ char *cached;
+ size_t len;
+
+ if (!global->ocsp_stapling_response) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ cached = os_readfile(global->ocsp_stapling_response, &len);
+ if (!cached) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - could not read response file (%s)",
+ global->ocsp_stapling_response);
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - send cached response");
+ resp->data = gnutls_malloc(len);
+ if (!resp->data) {
+ os_free(resp);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ os_memcpy(resp->data, cached, len);
+ resp->size = len;
+ os_free(cached);
+
+ return GNUTLS_E_SUCCESS;
+}
+#endif /* 3.1.3 */
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
@@ -696,6 +743,17 @@
}
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ os_free(global->ocsp_stapling_response);
+ if (params->ocsp_stapling_response)
+ global->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ else
+ global->ocsp_stapling_response = NULL;
+ gnutls_certificate_set_ocsp_status_request_function(
+ global->xcred, server_ocsp_status_req, global);
+#endif /* 3.1.3 */
+
global->params_set = 1;
return 0;
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 8b90d56..01a7c97 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -331,6 +331,13 @@
return -1;
}
+ 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 */
return -1;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 1d75ba7..62277c4 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -3890,6 +3890,12 @@
if (conn == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ocsp=3 not supported");
+ return -1;
+ }
+
/*
* If the engine isn't explicitly configured, and any of the
* cert/key fields are actually PKCS#11 URIs, then automatically
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ed5e4a8..cdd1504 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1735,9 +1735,6 @@
if (nl80211_init_bss(bss))
goto failed;
- if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
- drv->start_iface_up = 1;
-
if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
@@ -2240,6 +2237,11 @@
if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
bss->static_ap = 1;
+ if (first &&
+ nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
+ linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
+ drv->start_iface_up = 1;
+
if (wpa_driver_nl80211_capa(drv))
return -1;
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
index 4dfdb3f..6217468 100644
--- a/src/eap_common/eap_eke_common.c
+++ b/src/eap_common/eap_eke_common.c
@@ -44,9 +44,7 @@
int dhlen;
dhlen = eap_eke_dh_len(dhgroup);
- if (dhlen < 0)
- return -1;
- if (encr != EAP_EKE_ENCR_AES128_CBC)
+ if (dhlen < 0 || encr != EAP_EKE_ENCR_AES128_CBC)
return -1;
return AES_BLOCK_SIZE + dhlen;
}
@@ -166,14 +164,11 @@
size_t pub_len, i;
generator = eap_eke_dh_generator(group);
- if (generator < 0 || generator > 255)
+ dh = eap_eke_dh_group(group);
+ if (generator < 0 || generator > 255 || !dh)
return -1;
gen = generator;
- dh = eap_eke_dh_group(group);
- if (dh == NULL)
- return -1;
-
/* x = random number 2 .. p-1 */
if (random_get_bytes(ret_priv, dh->prime_len))
return -1;
@@ -411,11 +406,8 @@
size_t len;
const struct dh_group *dh;
- if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
- return -1;
-
dh = eap_eke_dh_group(sess->dhgroup);
- if (dh == NULL)
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC || !dh)
return -1;
/* Decrypt peer DHComponent */
@@ -635,6 +627,7 @@
if (*prot_len < block_size + data_len + pad + icv_len) {
wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+ return -1;
}
pos = prot;
@@ -653,10 +646,8 @@
pos += pad;
}
- if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
- return -1;
-
- if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+ if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0 ||
+ eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
return -1;
pos += icv_len;
@@ -684,9 +675,8 @@
else
return -1;
- if (prot_len < 2 * block_size + icv_len)
- return -1;
- if ((prot_len - icv_len) % block_size)
+ if (prot_len < 2 * block_size + icv_len ||
+ (prot_len - icv_len) % block_size)
return -1;
if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
@@ -737,22 +727,14 @@
sess->mac = mac;
sess->prf_len = eap_eke_prf_len(prf);
- if (sess->prf_len < 0)
- return -1;
sess->nonce_len = eap_eke_nonce_len(prf);
- if (sess->nonce_len < 0)
- return -1;
sess->auth_len = eap_eke_auth_len(prf);
- if (sess->auth_len < 0)
- return -1;
sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
- if (sess->dhcomp_len < 0)
- return -1;
sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
- if (sess->pnonce_len < 0)
- return -1;
sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
- if (sess->pnonce_ps_len < 0)
+ if (sess->prf_len < 0 || sess->nonce_len < 0 || sess->auth_len < 0 ||
+ sess->dhcomp_len < 0 || sess->pnonce_len < 0 ||
+ sess->pnonce_ps_len < 0)
return -1;
return 0;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index c270832..406c162 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -196,8 +196,10 @@
if (config->ocsp)
params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp == 2)
+ if (config->ocsp >= 2)
params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 25b9f12..e4294bb 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eap_i.h"
+#include "eap_config.h"
#include "tncc.h"
@@ -35,12 +36,16 @@
static void * eap_tnc_init(struct eap_sm *sm)
{
struct eap_tnc_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
data->state = WAIT_START;
- data->fragment_size = 1300;
+ if (config && config->fragment_size)
+ data->fragment_size = config->fragment_size;
+ else
+ data->fragment_size = 1300;
data->tncc = tncc_init();
if (data->tncc == NULL) {
os_free(data);
@@ -345,11 +350,6 @@
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = TRUE;
- if (data->out_buf) {
- data->state = PROC_MSG;
- return eap_tnc_build_msg(data, ret, id);
- }
-
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
EAP_CODE_RESPONSE, eap_get_id(reqData));
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index 7ca956e..9965513 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -694,6 +694,8 @@
enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
int recommendation_msg = 0;
+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
+ msg, len);
buf = dup_binstr(msg, len);
if (buf == NULL)
return TNCCS_PROCESS_ERROR;
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 0bcdb45..b24bbf8 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -308,7 +308,7 @@
int _errno = errno;
wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
- _errno == EBADF || _errno == ENETUNREACH) {
+ _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 669f658..64ef933 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -270,7 +270,7 @@
* much we can do here without knowing what
* exactly caused the server to misbehave.
*/
- wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: PMKID mismatch - authentication server may have derived different MSK?!");
return -1;
}
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index cc404c1..9bc0d21 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -111,7 +111,6 @@
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
- pos += conn->rl.iv_size;
} else {
/*
* Use IV field to set the mask value for TLS v1.1. A fixed
diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c
index 2d5cdb9..1d7b68c 100644
--- a/src/tls/tlsv1_client_ocsp.c
+++ b/src/tls/tlsv1_client_ocsp.c
@@ -316,6 +316,7 @@
static enum tls_ocsp_result
tls_process_ocsp_responses(struct tlsv1_client *conn,
+ struct x509_certificate *cert,
struct x509_certificate *issuer, const u8 *resp,
size_t len)
{
@@ -335,8 +336,7 @@
hdr.class, hdr.tag);
return TLS_OCSP_INVALID;
}
- if (tls_process_ocsp_single_response(conn, conn->server_cert,
- issuer,
+ if (tls_process_ocsp_single_response(conn, cert, issuer,
hdr.payload, hdr.length,
&res) == 0)
return res;
@@ -350,8 +350,9 @@
static enum tls_ocsp_result
-tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
- size_t len)
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+ struct x509_certificate *srv_cert,
+ const u8 *resp, size_t len)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
@@ -365,6 +366,7 @@
struct x509_name name; /* used if key_hash == NULL */
char buf[100];
os_time_t produced_at;
+ enum tls_ocsp_result res;
wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
@@ -594,20 +596,20 @@
/* Ignore for now. */
}
- if (!conn->server_cert) {
+ if (!srv_cert) {
wpa_printf(MSG_DEBUG,
"OCSP: Server certificate not known - cannot check OCSP response");
goto no_resp;
}
- if (conn->server_cert->next) {
+ if (srv_cert->next) {
/* Issuer has already been verified in the chain */
- issuer = conn->server_cert->next;
+ issuer = srv_cert->next;
} else {
/* Find issuer from the set of trusted certificates */
for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
issuer; issuer = issuer->next) {
- if (x509_name_compare(&conn->server_cert->issuer,
+ if (x509_name_compare(&srv_cert->issuer,
&issuer->subject) == 0)
break;
}
@@ -625,7 +627,7 @@
} else {
for (signer = certs; signer; signer = signer->next) {
if (!ocsp_responder_id_match(signer, &name, key_hash) ||
- x509_name_compare(&conn->server_cert->issuer,
+ x509_name_compare(&srv_cert->issuer,
&issuer->subject) != 0 ||
!(signer->ext_key_usage &
X509_EXT_KEY_USAGE_OCSP) ||
@@ -654,8 +656,13 @@
return TLS_OCSP_INVALID;
}
- return tls_process_ocsp_responses(conn, issuer, responses,
- responses_len);
+ res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+ responses, responses_len);
+ if (res == TLS_OCSP_REVOKED)
+ srv_cert->ocsp_revoked = 1;
+ else if (res == TLS_OCSP_GOOD)
+ srv_cert->ocsp_good = 1;
+ return res;
no_resp:
x509_free_name(&name);
@@ -677,6 +684,9 @@
u8 resp_status;
struct asn1_oid oid;
char obuf[80];
+ struct x509_certificate *cert;
+ enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+ enum tls_ocsp_result res_first = res;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
@@ -769,5 +779,25 @@
return TLS_OCSP_INVALID;
}
- return tls_process_basic_ocsp_response(conn, hdr.payload, hdr.length);
+ cert = conn->server_cert;
+ while (cert) {
+ if (!cert->ocsp_good && !cert->ocsp_revoked) {
+ char sbuf[128];
+
+ x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Trying to find certificate status for %s",
+ sbuf);
+
+ res = tls_process_basic_ocsp_response(conn, cert,
+ hdr.payload,
+ hdr.length);
+ if (cert == conn->server_cert)
+ res_first = res;
+ }
+ if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+ break;
+ cert = cert->next;
+ }
+ return res == TLS_OCSP_REVOKED ? res : res_first;
}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index ff12452..244c3cb 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -326,7 +326,7 @@
union tls_event_data ev;
char subject[128];
- if (!conn->event_cb)
+ if (!conn->event_cb || !cert)
return;
os_memset(&ev, 0, sizeof(ev));
@@ -790,14 +790,40 @@
}
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ u32 ocsp_resp_len;
+
+ /* opaque OCSPResponse<1..2^24-1>; */
+ if (end - pos < 3) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+ ocsp_resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < ocsp_resp_len) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+
+ return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type, status_type;
- u32 ocsp_resp_len;
enum tls_ocsp_result res;
+ struct x509_certificate *cert;
+ int depth;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG,
@@ -850,6 +876,7 @@
* CertificateStatusType status_type;
* select (status_type) {
* case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
* } response;
* } CertificateStatus;
*/
@@ -862,32 +889,110 @@
wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
status_type);
- if (status_type != 1 /* ocsp */) {
+ if (status_type == 1 /* ocsp */) {
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos, end - pos);
+ } else if (status_type == 2 /* ocsp_multi */) {
+ int good = 0, revoked = 0;
+ u32 resp_len;
+
+ res = TLS_OCSP_NO_RESPONSE;
+
+ /*
+ * opaque OCSPResponse<0..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList");
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < resp_len) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList(len=%u)",
+ resp_len);
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ end = pos + resp_len;
+
+ while (end - pos >= 3) {
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (resp_len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+ resp_len, (int) (end - pos));
+ res = TLS_OCSP_INVALID;
+ break;
+ }
+ if (!resp_len)
+ continue; /* Skip an empty response */
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos - 3, resp_len + 3);
+ if (res == TLS_OCSP_REVOKED)
+ revoked++;
+ else if (res == TLS_OCSP_GOOD)
+ good++;
+ pos += resp_len;
+ }
+
+ if (revoked)
+ res = TLS_OCSP_REVOKED;
+ else if (good)
+ res = TLS_OCSP_GOOD;
+ } else {
wpa_printf(MSG_DEBUG,
"TLSv1: Ignore unsupported CertificateStatus");
goto skip;
}
- /* opaque OCSPResponse<1..2^24-1>; */
- if (end - pos < 3) {
- wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- ocsp_resp_len = WPA_GET_BE24(pos);
- pos += 3;
- if (end - pos < ocsp_resp_len) {
- wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+done:
+ if (res == TLS_OCSP_REVOKED) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_CERTIFICATE_REVOKED);
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (cert->ocsp_revoked) {
+ tls_cert_chain_failure_event(
+ conn, depth, cert, TLS_FAIL_REVOKED,
+ "certificate revoked");
+ }
+ }
return -1;
}
- res = tls_process_ocsp_response(conn, pos, ocsp_resp_len);
- switch (res) {
- case TLS_OCSP_NO_RESPONSE:
- if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
- goto skip;
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ /*
+ * Verify that each certificate on the chain that is not part
+ * of the trusted certificates has a good status. If not,
+ * terminate handshake.
+ */
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (!cert->ocsp_good) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ tls_cert_chain_failure_event(
+ conn, depth, cert,
+ TLS_FAIL_UNSPECIFIED,
+ "bad certificate status response");
+ return -1;
+ }
+ if (cert->issuer_trusted)
+ break;
+ }
+ }
+
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
if (conn->server_cert)
tls_cert_chain_failure_event(
@@ -895,28 +1000,8 @@
TLS_FAIL_UNSPECIFIED,
"bad certificate status response");
return -1;
- case TLS_OCSP_INVALID:
- if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
- goto skip; /* ignore - process as if no response */
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- if (conn->server_cert)
- tls_cert_chain_failure_event(
- conn, 0, conn->server_cert,
- TLS_FAIL_UNSPECIFIED,
- "bad certificate status response");
- return -1;
- case TLS_OCSP_GOOD:
- wpa_printf(MSG_DEBUG, "TLSv1: OCSP response good");
- break;
- case TLS_OCSP_REVOKED:
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_CERTIFICATE_REVOKED);
- if (conn->server_cert)
- tls_cert_chain_failure_event(
- conn, 0, conn->server_cert, TLS_FAIL_REVOKED,
- "certificate revoked");
- return -1;
}
+
conn->ocsp_resp_received = 1;
skip:
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 8e8cb5e..04d895e 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -192,6 +192,46 @@
pos += 2;
WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
pos += 2;
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request_v2 extension for OCSP stapling");
+ /* 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, 7);
+ pos += 2;
+
+ /*
+ * 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;
+ *
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ /* certificate_status_req_list<1..2^16-1> */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /* CertificateStatusRequestItemV2 */
+ *pos++ = 2; /* status_type = ocsp_multi(2) */
+ /* OCSPStatusRequest as shown above for v1 */
+ WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+ pos += 2;
+ WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+ pos += 2;
}
if (pos == ext_start + 2)
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 @@
#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 92f97c7..52c1ae0 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -36,6 +36,8 @@
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->ocsp_stapling_response_multi);
os_free(cred);
}
diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h
index b4bfe38..716e93c 100644
--- a/src/tls/tlsv1_cred.h
+++ b/src/tls/tlsv1_cred.h
@@ -24,6 +24,9 @@
size_t dh_p_len;
u8 *dh_g; /* generator */
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 96d79b3..29c6678 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -55,6 +55,9 @@
void *log_cb_ctx;
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 8347d7a..4aa8a01 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -46,6 +46,78 @@
}
+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)
{
@@ -267,6 +339,11 @@
ext_len);
conn->session_ticket_len = ext_len;
}
+ } 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 e7c5e22..bdc6c11 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -42,7 +42,7 @@
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,32 @@
/* 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->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,
@@ -133,6 +159,11 @@
*/
}
+ 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 +275,93 @@
}
+static int tls_write_server_certificate_status(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end,
+ int ocsp_multi,
+ char *ocsp_resp,
+ size_t ocsp_resp_len)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+
+ 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 + ocsp_resp_len >
+ (unsigned int) (end - pos)) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
+ 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;
+ * 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 */
+ if (ocsp_multi)
+ *pos++ = 2; /* ocsp_multi(2) */
+ else
+ *pos++ = 1; /* ocsp(1) */
+ /* uint24 length of OCSPResponse */
+ WPA_PUT_BE24(pos, ocsp_resp_len);
+ pos += 3;
+ os_memcpy(pos, ocsp_resp, ocsp_resp_len);
+ pos += ocsp_resp_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)
{
@@ -810,24 +928,46 @@
{
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_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) {
@@ -844,12 +984,16 @@
/* Full handshake */
if (tls_write_server_certificate(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;
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 5521390..75f222c 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -1339,6 +1339,7 @@
size_t left;
char sbuf[128];
unsigned long value;
+ const u8 *subject_dn;
/* tbsCertificate TBSCertificate ::= SEQUENCE */
if (asn1_get_next(buf, len, &hdr) < 0 ||
@@ -1436,7 +1437,6 @@
return -1;
/* subject Name */
- const u8 *subject_dn;
subject_dn = pos;
if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
return -1;
@@ -2038,6 +2038,7 @@
os_get_time(&now);
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+ cert->issuer_trusted = 0;
x509_name_string(&cert->subject, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
@@ -2123,6 +2124,7 @@
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
"found to complete the chain");
+ cert->issuer_trusted = 1;
chain_trusted = 1;
}
}
diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h
index dcdb4a3..7df8e2a 100644
--- a/src/tls/x509v3.h
+++ b/src/tls/x509v3.h
@@ -106,6 +106,11 @@
size_t cert_len;
const u8 *tbs_cert_start;
size_t tbs_cert_len;
+
+ /* Meta data used for certificate validation */
+ unsigned int ocsp_good:1;
+ unsigned int ocsp_revoked:1;
+ unsigned int issuer_trusted:1;
};
enum {