mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-29 02:38:22 -05:00
TLS client: Multi-OCSP check to cover intermediate CAs
This extends multi-OCSP support to verify status for intermediate CAs in the server certificate chain. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
d6b536f7e5
commit
0764dd6849
@ -200,12 +200,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
|||||||
if (conn->client == NULL)
|
if (conn->client == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
|
|
||||||
wpa_printf(MSG_INFO,
|
|
||||||
"TLS: ocsp=3 not supported");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
|
if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
|
||||||
wpa_printf(MSG_INFO,
|
wpa_printf(MSG_INFO,
|
||||||
"TLS: tls_ext_cert_check=1 not supported");
|
"TLS: tls_ext_cert_check=1 not supported");
|
||||||
|
@ -316,6 +316,7 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
|
|||||||
|
|
||||||
static enum tls_ocsp_result
|
static enum tls_ocsp_result
|
||||||
tls_process_ocsp_responses(struct tlsv1_client *conn,
|
tls_process_ocsp_responses(struct tlsv1_client *conn,
|
||||||
|
struct x509_certificate *cert,
|
||||||
struct x509_certificate *issuer, const u8 *resp,
|
struct x509_certificate *issuer, const u8 *resp,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
@ -335,8 +336,7 @@ tls_process_ocsp_responses(struct tlsv1_client *conn,
|
|||||||
hdr.class, hdr.tag);
|
hdr.class, hdr.tag);
|
||||||
return TLS_OCSP_INVALID;
|
return TLS_OCSP_INVALID;
|
||||||
}
|
}
|
||||||
if (tls_process_ocsp_single_response(conn, conn->server_cert,
|
if (tls_process_ocsp_single_response(conn, cert, issuer,
|
||||||
issuer,
|
|
||||||
hdr.payload, hdr.length,
|
hdr.payload, hdr.length,
|
||||||
&res) == 0)
|
&res) == 0)
|
||||||
return res;
|
return res;
|
||||||
@ -350,8 +350,9 @@ tls_process_ocsp_responses(struct tlsv1_client *conn,
|
|||||||
|
|
||||||
|
|
||||||
static enum tls_ocsp_result
|
static enum tls_ocsp_result
|
||||||
tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
|
tls_process_basic_ocsp_response(struct tlsv1_client *conn,
|
||||||
size_t len)
|
struct x509_certificate *srv_cert,
|
||||||
|
const u8 *resp, size_t len)
|
||||||
{
|
{
|
||||||
struct asn1_hdr hdr;
|
struct asn1_hdr hdr;
|
||||||
const u8 *pos, *end;
|
const u8 *pos, *end;
|
||||||
@ -365,6 +366,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
|
|||||||
struct x509_name name; /* used if key_hash == NULL */
|
struct x509_name name; /* used if key_hash == NULL */
|
||||||
char buf[100];
|
char buf[100];
|
||||||
os_time_t produced_at;
|
os_time_t produced_at;
|
||||||
|
enum tls_ocsp_result res;
|
||||||
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
|
wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
|
||||||
|
|
||||||
@ -594,20 +596,20 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
|
|||||||
/* Ignore for now. */
|
/* Ignore for now. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conn->server_cert) {
|
if (!srv_cert) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"OCSP: Server certificate not known - cannot check OCSP response");
|
"OCSP: Server certificate not known - cannot check OCSP response");
|
||||||
goto no_resp;
|
goto no_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->server_cert->next) {
|
if (srv_cert->next) {
|
||||||
/* Issuer has already been verified in the chain */
|
/* Issuer has already been verified in the chain */
|
||||||
issuer = conn->server_cert->next;
|
issuer = srv_cert->next;
|
||||||
} else {
|
} else {
|
||||||
/* Find issuer from the set of trusted certificates */
|
/* Find issuer from the set of trusted certificates */
|
||||||
for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
|
for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
|
||||||
issuer; issuer = issuer->next) {
|
issuer; issuer = issuer->next) {
|
||||||
if (x509_name_compare(&conn->server_cert->issuer,
|
if (x509_name_compare(&srv_cert->issuer,
|
||||||
&issuer->subject) == 0)
|
&issuer->subject) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -625,7 +627,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
|
|||||||
} else {
|
} else {
|
||||||
for (signer = certs; signer; signer = signer->next) {
|
for (signer = certs; signer; signer = signer->next) {
|
||||||
if (!ocsp_responder_id_match(signer, &name, key_hash) ||
|
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 ||
|
&issuer->subject) != 0 ||
|
||||||
!(signer->ext_key_usage &
|
!(signer->ext_key_usage &
|
||||||
X509_EXT_KEY_USAGE_OCSP) ||
|
X509_EXT_KEY_USAGE_OCSP) ||
|
||||||
@ -654,8 +656,13 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
|
|||||||
return TLS_OCSP_INVALID;
|
return TLS_OCSP_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tls_process_ocsp_responses(conn, issuer, responses,
|
res = tls_process_ocsp_responses(conn, srv_cert, issuer,
|
||||||
responses_len);
|
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:
|
no_resp:
|
||||||
x509_free_name(&name);
|
x509_free_name(&name);
|
||||||
@ -677,6 +684,9 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
|
|||||||
u8 resp_status;
|
u8 resp_status;
|
||||||
struct asn1_oid oid;
|
struct asn1_oid oid;
|
||||||
char obuf[80];
|
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);
|
wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
|
||||||
|
|
||||||
@ -769,5 +779,25 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
|
|||||||
return TLS_OCSP_INVALID;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -822,6 +822,8 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
|
|||||||
size_t left, len;
|
size_t left, len;
|
||||||
u8 type, status_type;
|
u8 type, status_type;
|
||||||
enum tls_ocsp_result res;
|
enum tls_ocsp_result res;
|
||||||
|
struct x509_certificate *cert;
|
||||||
|
int depth;
|
||||||
|
|
||||||
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
|
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
@ -955,13 +957,39 @@ done:
|
|||||||
if (res == TLS_OCSP_REVOKED) {
|
if (res == TLS_OCSP_REVOKED) {
|
||||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||||
TLS_ALERT_CERTIFICATE_REVOKED);
|
TLS_ALERT_CERTIFICATE_REVOKED);
|
||||||
if (conn->server_cert)
|
for (cert = conn->server_cert, depth = 0; cert;
|
||||||
tls_cert_chain_failure_event(
|
cert = cert->next, depth++) {
|
||||||
conn, 0, conn->server_cert, TLS_FAIL_REVOKED,
|
if (cert->ocsp_revoked) {
|
||||||
"certificate revoked");
|
tls_cert_chain_failure_event(
|
||||||
|
conn, depth, cert, TLS_FAIL_REVOKED,
|
||||||
|
"certificate revoked");
|
||||||
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
|
||||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||||
res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
|
res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
|
||||||
|
@ -2038,6 +2038,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
|
|||||||
os_get_time(&now);
|
os_get_time(&now);
|
||||||
|
|
||||||
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
|
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
|
||||||
|
cert->issuer_trusted = 0;
|
||||||
x509_name_string(&cert->subject, buf, sizeof(buf));
|
x509_name_string(&cert->subject, buf, sizeof(buf));
|
||||||
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
|
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
|
||||||
|
|
||||||
@ -2123,6 +2124,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
|
|||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
|
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
|
||||||
"found to complete the chain");
|
"found to complete the chain");
|
||||||
|
cert->issuer_trusted = 1;
|
||||||
chain_trusted = 1;
|
chain_trusted = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,11 @@ struct x509_certificate {
|
|||||||
size_t cert_len;
|
size_t cert_len;
|
||||||
const u8 *tbs_cert_start;
|
const u8 *tbs_cert_start;
|
||||||
size_t tbs_cert_len;
|
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 {
|
enum {
|
||||||
|
Loading…
Reference in New Issue
Block a user