Add support for certificate policies extension
Add support for certificate policies, as defined in rfc 5280.
Currently support only `anyPolicy` policy.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index f9cbed0..f17c8b2 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -691,6 +691,139 @@
}
/*
+ * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
+ *
+ * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
+ *
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ *
+ * PolicyQualifierInfo ::= SEQUENCE {
+ * policyQualifierId PolicyQualifierId,
+ * qualifier ANY DEFINED BY policyQualifierId }
+ *
+ * -- policyQualifierIds for Internet policy qualifiers
+ *
+ * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
+ * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
+ * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
+ *
+ * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ *
+ * Qualifier ::= CHOICE {
+ * cPSuri CPSuri,
+ * userNotice UserNotice }
+ *
+ * CPSuri ::= IA5String
+ *
+ * UserNotice ::= SEQUENCE {
+ * noticeRef NoticeReference OPTIONAL,
+ * explicitText DisplayText OPTIONAL }
+ *
+ * NoticeReference ::= SEQUENCE {
+ * organization DisplayText,
+ * noticeNumbers SEQUENCE OF INTEGER }
+ *
+ * DisplayText ::= CHOICE {
+ * ia5String IA5String (SIZE (1..200)),
+ * visibleString VisibleString (SIZE (1..200)),
+ * bmpString BMPString (SIZE (1..200)),
+ * utf8String UTF8String (SIZE (1..200)) }
+ *
+ * NOTE: we only parse and use anyPolicy without qualifiers at this point
+ * as defined in RFC 5280.
+ */
+static int x509_get_certificate_policies( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_x509_sequence *certificate_policies )
+{
+ int ret;
+ size_t len;
+ mbedtls_asn1_buf *buf;
+ mbedtls_asn1_sequence *cur = certificate_policies;
+
+ /* Get main sequence tag */
+ ret = mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+ if( ret != 0 )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+ if( *p + len != end )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ /*
+ * Cannot be an empty sequence.
+ */
+ if( len == 0 )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ while( *p < end )
+ {
+ mbedtls_x509_buf policy_oid;
+ const unsigned char *policy_end;
+
+ /*
+ * Get the policy sequence
+ */
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+ policy_end = *p + len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_OID ) ) != 0 )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+ policy_oid.tag = MBEDTLS_ASN1_OID;
+ policy_oid.len = len;
+ policy_oid.p = *p;
+
+ /* Allocate and assign next pointer */
+ if( cur->buf.p != NULL )
+ {
+ if( cur->next != NULL )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
+
+ cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
+
+ if( cur->next == NULL )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+ MBEDTLS_ERR_ASN1_ALLOC_FAILED );
+
+ cur = cur->next;
+ }
+
+ buf = &( cur->buf );
+ buf->tag = policy_oid.tag;
+ buf->p = policy_oid.p;
+ buf->len = policy_oid.len;
+ /*
+ * Skip the optional policy qualifiers,
+ * and set the pointer to the end of the policy.
+ */
+ *p = (unsigned char *)policy_end;
+ }
+
+ /* Set final sequence entry's next pointer to NULL */
+ cur->next = NULL;
+
+ if( *p != end )
+ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
* X.509 v3 extensions
*
*/
@@ -817,6 +950,13 @@
return( ret );
break;
+ case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES:
+ /* Parse certificate policies type */
+ if( ( ret = x509_get_certificate_policies( p, end_ext_octet,
+ &crt->certificate_policies ) ) != 0 )
+ return( ret );
+ break;
+
default:
/*
* If this is a non-critical extension, which the oid layer
@@ -1820,6 +1960,35 @@
return( 0 );
}
+static int x509_info_cert_policies( char **buf, size_t *size,
+ const mbedtls_x509_sequence *certificate_policies )
+{
+ int ret;
+ const char *desc;
+ size_t n = *size;
+ char *p = *buf;
+ const mbedtls_x509_sequence *cur = certificate_policies;
+ const char *sep = "";
+
+ while( cur != NULL )
+ {
+ if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 )
+ desc = "???";
+
+ ret = mbedtls_snprintf( p, n, "%s%s", sep, desc );
+ MBEDTLS_X509_SAFE_SNPRINTF;
+
+ sep = ", ";
+
+ cur = cur->next;
+ }
+
+ *size = n;
+ *buf = p;
+
+ return( 0 );
+}
+
/*
* Return an informational string about the certificate.
*/
@@ -1952,6 +2121,16 @@
return( ret );
}
+ if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES )
+ {
+ ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix );
+ MBEDTLS_X509_SAFE_SNPRINTF;
+
+ if( ( ret = x509_info_cert_policies( &p, &n,
+ &crt->certificate_policies ) ) != 0 )
+ return( ret );
+ }
+
ret = mbedtls_snprintf( p, n, "\n" );
MBEDTLS_X509_SAFE_SNPRINTF;
@@ -3078,6 +3257,16 @@
mbedtls_free( seq_prv );
}
+ seq_cur = cert_cur->certificate_policies.next;
+ while( seq_cur != NULL )
+ {
+ seq_prv = seq_cur;
+ seq_cur = seq_cur->next;
+ mbedtls_platform_zeroize( seq_prv,
+ sizeof( mbedtls_x509_sequence ) );
+ mbedtls_free( seq_prv );
+ }
+
if( cert_cur->raw.p != NULL && cert_cur->own_buffer )
{
mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );