TLS: Add support for extKeyUsage X.509v3 extension
If the server/client certificate includes the extKeyUsage extension, verify that the listed key purposes include either the anyExtendedKeyUsage wildcard or id-kp-serverAuth/id-kp-clientAuth, respectively. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
404597e630
commit
1adf262144
4 changed files with 134 additions and 1 deletions
|
@ -548,6 +548,19 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conn->cred && !conn->cred->server_cert_only && chain &&
|
||||||
|
(chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
|
||||||
|
!(chain->ext_key_usage &
|
||||||
|
(X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
|
||||||
|
tls_cert_chain_failure_event(
|
||||||
|
conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
|
||||||
|
"certificate not allowed for server authentication");
|
||||||
|
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||||
|
TLS_ALERT_BAD_CERTIFICATE);
|
||||||
|
x509_certificate_chain_free(chain);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
x509_certificate_chain_free(chain);
|
x509_certificate_chain_free(chain);
|
||||||
|
|
||||||
*in_len = end - in_data;
|
*in_len = end - in_data;
|
||||||
|
|
|
@ -471,6 +471,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chain && (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
|
||||||
|
!(chain->ext_key_usage &
|
||||||
|
(X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_CLIENT_AUTH))) {
|
||||||
|
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||||
|
TLS_ALERT_BAD_CERTIFICATE);
|
||||||
|
x509_certificate_chain_free(chain);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
x509_certificate_chain_free(chain);
|
x509_certificate_chain_free(chain);
|
||||||
|
|
||||||
*in_len = end - in_data;
|
*in_len = end - in_data;
|
||||||
|
|
106
src/tls/x509v3.c
106
src/tls/x509v3.c
|
@ -720,6 +720,15 @@ static int x509_id_ce_oid(struct asn1_oid *oid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
|
||||||
|
{
|
||||||
|
return oid->len == 6 &&
|
||||||
|
x509_id_ce_oid(oid) &&
|
||||||
|
oid->oid[3] == 37 /* extKeyUsage */ &&
|
||||||
|
oid->oid[4] == 0 /* anyExtendedKeyUsage */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int x509_parse_ext_key_usage(struct x509_certificate *cert,
|
static int x509_parse_ext_key_usage(struct x509_certificate *cert,
|
||||||
const u8 *pos, size_t len)
|
const u8 *pos, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -1073,6 +1082,100 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_id_pkix_oid(struct asn1_oid *oid)
|
||||||
|
{
|
||||||
|
return oid->len >= 7 &&
|
||||||
|
oid->oid[0] == 1 /* iso */ &&
|
||||||
|
oid->oid[1] == 3 /* identified-organization */ &&
|
||||||
|
oid->oid[2] == 6 /* dod */ &&
|
||||||
|
oid->oid[3] == 1 /* internet */ &&
|
||||||
|
oid->oid[4] == 5 /* security */ &&
|
||||||
|
oid->oid[5] == 5 /* mechanisms */ &&
|
||||||
|
oid->oid[6] == 7 /* id-pkix */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_id_kp_oid(struct asn1_oid *oid)
|
||||||
|
{
|
||||||
|
/* id-kp */
|
||||||
|
return oid->len >= 8 &&
|
||||||
|
x509_id_pkix_oid(oid) &&
|
||||||
|
oid->oid[7] == 3 /* id-kp */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
|
||||||
|
{
|
||||||
|
/* id-kp */
|
||||||
|
return oid->len == 9 &&
|
||||||
|
x509_id_kp_oid(oid) &&
|
||||||
|
oid->oid[8] == 1 /* id-kp-serverAuth */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
|
||||||
|
{
|
||||||
|
/* id-kp */
|
||||||
|
return oid->len == 9 &&
|
||||||
|
x509_id_kp_oid(oid) &&
|
||||||
|
oid->oid[8] == 2 /* id-kp-clientAuth */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
|
||||||
|
const u8 *pos, size_t len)
|
||||||
|
{
|
||||||
|
struct asn1_hdr hdr;
|
||||||
|
const u8 *end;
|
||||||
|
struct asn1_oid oid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
|
||||||
|
*
|
||||||
|
* KeyPurposeId ::= OBJECT IDENTIFIER
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (asn1_get_next(pos, len, &hdr) < 0 ||
|
||||||
|
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||||
|
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||||
|
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
|
||||||
|
"(ExtKeyUsageSyntax) - found class %d tag 0x%x",
|
||||||
|
hdr.class, hdr.tag);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (hdr.length > pos + len - hdr.payload)
|
||||||
|
return -1;
|
||||||
|
pos = hdr.payload;
|
||||||
|
end = pos + hdr.length;
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
char buf[80];
|
||||||
|
|
||||||
|
if (asn1_get_oid(pos, end - pos, &oid, &pos))
|
||||||
|
return -1;
|
||||||
|
if (x509_any_ext_key_usage_oid(&oid)) {
|
||||||
|
os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
|
||||||
|
cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
|
||||||
|
} else if (x509_id_kp_server_auth_oid(&oid)) {
|
||||||
|
os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
|
||||||
|
cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
|
||||||
|
} else if (x509_id_kp_client_auth_oid(&oid)) {
|
||||||
|
os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
|
||||||
|
cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
|
||||||
|
} else {
|
||||||
|
asn1_oid_to_str(&oid, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int x509_parse_extension_data(struct x509_certificate *cert,
|
static int x509_parse_extension_data(struct x509_certificate *cert,
|
||||||
struct asn1_oid *oid,
|
struct asn1_oid *oid,
|
||||||
const u8 *pos, size_t len)
|
const u8 *pos, size_t len)
|
||||||
|
@ -1084,7 +1187,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
|
||||||
* certificate policies (section 4.2.1.5)
|
* certificate policies (section 4.2.1.5)
|
||||||
* name constraints (section 4.2.1.11)
|
* name constraints (section 4.2.1.11)
|
||||||
* policy constraints (section 4.2.1.12)
|
* policy constraints (section 4.2.1.12)
|
||||||
* extended key usage (section 4.2.1.13)
|
|
||||||
* inhibit any-policy (section 4.2.1.15)
|
* inhibit any-policy (section 4.2.1.15)
|
||||||
*/
|
*/
|
||||||
switch (oid->oid[3]) {
|
switch (oid->oid[3]) {
|
||||||
|
@ -1096,6 +1198,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
|
||||||
return x509_parse_ext_issuer_alt_name(cert, pos, len);
|
return x509_parse_ext_issuer_alt_name(cert, pos, len);
|
||||||
case 19: /* id-ce-basicConstraints */
|
case 19: /* id-ce-basicConstraints */
|
||||||
return x509_parse_ext_basic_constraints(cert, pos, len);
|
return x509_parse_ext_basic_constraints(cert, pos, len);
|
||||||
|
case 37: /* id-ce-extKeyUsage */
|
||||||
|
return x509_parse_ext_ext_key_usage(cert, pos, len);
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ struct x509_certificate {
|
||||||
#define X509_EXT_KEY_USAGE (1 << 2)
|
#define X509_EXT_KEY_USAGE (1 << 2)
|
||||||
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
|
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
|
||||||
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
|
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
|
||||||
|
#define X509_EXT_EXT_KEY_USAGE (1 << 5)
|
||||||
|
|
||||||
/* BasicConstraints */
|
/* BasicConstraints */
|
||||||
int ca; /* cA */
|
int ca; /* cA */
|
||||||
|
@ -85,6 +86,12 @@ struct x509_certificate {
|
||||||
#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
|
#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
|
||||||
#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8)
|
#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8)
|
||||||
|
|
||||||
|
/* ExtKeyUsage */
|
||||||
|
unsigned long ext_key_usage;
|
||||||
|
#define X509_EXT_KEY_USAGE_ANY (1 << 0)
|
||||||
|
#define X509_EXT_KEY_USAGE_SERVER_AUTH (1 << 1)
|
||||||
|
#define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The DER format certificate follows struct x509_certificate. These
|
* The DER format certificate follows struct x509_certificate. These
|
||||||
* pointers point to that buffer.
|
* pointers point to that buffer.
|
||||||
|
|
Loading…
Reference in a new issue