Add partial support for URI SubjectAltNames
Only exact matching without normalization is supported.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
diff --git a/ChangeLog.d/basic-uri-verification.txt b/ChangeLog.d/basic-uri-verification.txt
new file mode 100644
index 0000000..aa039ea
--- /dev/null
+++ b/ChangeLog.d/basic-uri-verification.txt
@@ -0,0 +1,4 @@
+Features
+ * X.509 hostname verification now partially supports URI Subject Alternate
+ Names. Only exact matching, without any normalization procedures
+ described in 7.4 of RFC5280, will result in a positive URI verification.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index e1b4aa2..6675bf8 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -641,8 +641,12 @@
* \param cn The expected Common Name. This will be checked to be
* present in the certificate's subjectAltNames extension or,
* if this extension is absent, as a CN component in its
- * Subject name. DNS names and IP addresses are supported. This
- * may be \c NULL if the CN need not be verified.
+ * Subject name. DNS names and IP addresses are fully
+ * supported, while the URI subtype is partially supported:
+ * only exact matching, without any normalization procedures
+ * described in 7.4 of RFC5280, will result in a positive
+ * URI verification.
+ * This may be \c NULL if the CN need not be verified.
* \param flags The address at which to store the result of the verification.
* If the verification couldn't be completed, the flag value is
* set to (uint32_t) -1.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 6d62e44..abba05b 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -2904,6 +2904,21 @@
return -1;
}
+static int x509_crt_check_san_uri(const mbedtls_x509_sequence *san,
+ const char *cn, size_t cn_len)
+{
+ for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) {
+ const unsigned char san_type = (unsigned char) cur->buf.tag &
+ MBEDTLS_ASN1_TAG_VALUE_MASK;
+ if (san_type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER &&
+ cur->buf.len == cn_len && memcmp(cur->buf.p, cn, cn_len) == 0) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
/*
* Check for SAN match, see RFC 5280 Section 4.2.1.6
*/
@@ -2911,23 +2926,38 @@
const char *cn, size_t cn_len)
{
int san_ip = 0;
+ int san_uri = 0;
+ /* Prioritize DNS name over other subtypes due to popularity */
for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) {
switch ((unsigned char) cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) {
- case MBEDTLS_X509_SAN_DNS_NAME: /* dNSName */
+ case MBEDTLS_X509_SAN_DNS_NAME:
if (x509_crt_check_cn(&cur->buf, cn, cn_len) == 0) {
return 0;
}
break;
- case MBEDTLS_X509_SAN_IP_ADDRESS: /* iPAddress */
+ case MBEDTLS_X509_SAN_IP_ADDRESS:
san_ip = 1;
break;
+ case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
+ san_uri = 1;
+ break;
/* (We may handle other types here later.) */
default: /* Unrecognized type */
break;
}
}
+ if (san_ip) {
+ if (x509_crt_check_san_ip(san, cn, cn_len) == 0) {
+ return 0;
+ }
+ }
+ if (san_uri) {
+ if (x509_crt_check_san_uri(san, cn, cn_len) == 0) {
+ return 0;
+ }
+ }
- return san_ip ? x509_crt_check_san_ip(san, cn, cn_len) : -1;
+ return -1;
}
/*
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 55ed0c5..0193e07 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1043,6 +1043,22 @@
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
x509_verify:"data_files/server5-tricky-ip-san.crt":"data_files/server5-tricky-ip-san.crt":"data_files/crl_sha256.pem":"6162\:6364\:\:6F6D":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+X509 CRT verification: matching URI in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/rsa_single_san_uri.crt.der":"data_files/rsa_single_san_uri.crt.der":"data_files/crl_sha256.pem":"urn\:example.com\:5ff40f78-9210-494f-8206-c2c082f0609c":0:0:"":"NULL"
+
+X509 CRT verification: URI with trailing data in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/rsa_single_san_uri.crt.der":"data_files/rsa_single_san_uri.crt.der":"data_files/crl_sha256.pem":"urn\:example.com\:5ff40f78-9210-494f-8206-c2c082f0609cz":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+
+X509 CRT verification: URI with preceding data in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/rsa_single_san_uri.crt.der":"data_files/rsa_single_san_uri.crt.der":"data_files/crl_sha256.pem":"zurn\:example.com\:5ff40f78-9210-494f-8206-c2c082f0609c":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+
+X509 CRT verification: URI with bad data in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/rsa_single_san_uri.crt.der":"data_files/rsa_single_san_uri.crt.der":"data_files/crl_sha256.pem":"bad\:example.com\:5ff40f78-9210-494f-8206-c2c082f0609c":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+
X509 CRT parse CN: IPv4 valid address
x509_crt_parse_cn_inet_pton:"10.10.10.10":"0A0A0A0A":4