static int x509_get_basic_constraints( unsigned char **p, const unsigned char *end, int *ca_istrue, int *max_pathlen ) { int ret; size_t len; /* * BasicConstraints ::= SEQUENCE { * cA BOOLEAN DEFAULT FALSE, * pathLenConstraint INTEGER (0..MAX) OPTIONAL } */ *ca_istrue = 0; /* DEFAULT FALSE */ *max_pathlen = 0; /* endless */ if( ( ret = asn1_get_tag( p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); if( *p == end ) return 0; if( ( ret = asn1_get_bool( p, end, ca_istrue ) ) != 0 ) { if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) ret = asn1_get_int( p, end, ca_istrue ); if( ret != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); if( *ca_istrue != 0 ) *ca_istrue = 1; } if( *p == end ) return 0; if( ( ret = asn1_get_int( p, end, max_pathlen ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); if( *p != end ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); (*max_pathlen)++; return 0; }
/** * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 */ static int x509_v3_basic_constraints(const uint8_t *cert, int offset, X509_CTX *x509_ctx) { int ret = X509_OK; int lenSeq = 0; if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) goto end_contraints; x509_ctx->basic_constraint_present = true; x509_ctx->basic_constraint_is_critical = asn1_is_critical_ext(cert, &offset); /* Assign Defaults in case not specified basic_constraint_cA will already by zero by virtue of the calloc */ x509_ctx->basic_constraint_cA = 0; /* basic_constraint_pathLenConstraint is unlimited by default. 10000 is just a large number (limits.h is not already included) */ x509_ctx->basic_constraint_pathLenConstraint = 10000; if ((asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0) || ((lenSeq = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) < 0)) { ret = X509_NOT_OK; } /* If the Sequence Length is greater than zero, continue with the basic_constraint_cA */ if ((lenSeq>0)&&(asn1_get_bool(cert, &offset, &x509_ctx->basic_constraint_cA) < 0)) { ret = X509_NOT_OK; } /* If the Sequence Length is greater than 3, it has more content than the basic_constraint_cA bool, so grab the pathLenConstraint */ if ((lenSeq>3) && (asn1_get_int(cert, &offset, &x509_ctx->basic_constraint_pathLenConstraint) < 0)) { ret = X509_NOT_OK; } end_contraints: return ret; }
static int x509_get_crt_ext_data(const unsigned char **ext_data, size_t *ext_len, x509_crt *crt, const char *oid) { int ret; size_t len; unsigned char *end_ext_data, *end_ext_octet; unsigned char *p; const unsigned char *end; char oid_str[64]; p = crt->v3_ext.p; end = crt->v3_ext.p + crt->v3_ext.len; ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; if (end != p + len) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH; while (p < end) { /* * Extension ::= SEQUENCE { * extnID OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * extnValue OCTET STRING } */ x509_buf extn_oid = {0, 0, NULL}; int is_critical = 0; /* DEFAULT FALSE */ ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; end_ext_data = p + len; /* Get extension ID */ extn_oid.tag = *p; ret = asn1_get_tag(&p, end, &extn_oid.len, ASN1_OID); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; extn_oid.p = p; p += extn_oid.len; if ((end - p) < 1) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_OUT_OF_DATA; /* Get optional critical */ ret = asn1_get_bool(&p, end_ext_data, &is_critical); if (ret != 0 && (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG)) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; /* Data should be octet string type */ ret = asn1_get_tag(&p, end_ext_data, &len, ASN1_OCTET_STRING); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; end_ext_octet = p + len; if (end_ext_octet != end_ext_data) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH; /* Detect requested extension */ oid_get_numeric_string(oid_str, 64, &extn_oid); if (memcmp(oid, oid_str, sizeof(oid)) == 0) { *ext_data = p; *ext_len = len; return 0; } /* Next */ p = end_ext_octet; } if (p != end) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH; return POLARSSL_ERR_X509_UNKNOWN_OID; }
/* * X.509 v3 extensions (only BasicConstraints are parsed) */ static int x509_get_ext( unsigned char **p, unsigned char *end, x509_buf *ext, int *ca_istrue, int *max_pathlen ) { int ret, len; int is_critical = 1; int is_cacert = 0; unsigned char *end2; if( *p == end ) return( 0 ); ext->tag = **p; if( ( ret = asn1_get_tag( p, end, &ext->len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) ) != 0 ) { if( ret == ERR_ASN1_UNEXPECTED_TAG ) return( 0 ); return( ret ); } ext->p = *p; end = *p + ext->len; /* * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension * * Extension ::= SEQUENCE { * extnID OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * extnValue OCTET STRING } */ if( ( ret = asn1_get_tag( p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( end != *p + len ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ERR_ASN1_LENGTH_MISMATCH ); while( *p < end ) { if( ( ret = asn1_get_tag( p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( memcmp( *p, "\x06\x03\x55\x1D\x13", 5 ) != 0 ) { *p += len; continue; } *p += 5; if( ( ret = asn1_get_bool( p, end, &is_critical ) ) != 0 && ( ret != ERR_ASN1_UNEXPECTED_TAG ) ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( ( ret = asn1_get_tag( p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); /* * BasicConstraints ::= SEQUENCE { * cA BOOLEAN DEFAULT FALSE, * pathLenConstraint INTEGER (0..MAX) OPTIONAL } */ end2 = *p + len; if( ( ret = asn1_get_tag( p, end2, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( *p == end2 ) continue; if( ( ret = asn1_get_bool( p, end2, &is_cacert ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( *p == end2 ) continue; if( ( ret = asn1_get_int( p, end2, max_pathlen ) ) != 0 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ret ); if( *p != end2 ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ERR_ASN1_LENGTH_MISMATCH ); max_pathlen++; } if( *p != end ) return( ERR_X509_CERT_INVALID_EXTENSIONS | ERR_ASN1_LENGTH_MISMATCH ); *ca_istrue = is_critical & is_cacert; return( 0 ); }
/* * X.509 v3 extensions * * TODO: Perform all of the basic constraints tests required by the RFC * TODO: Set values for undetected extensions to a sane default? * */ static int x509_get_crt_ext( unsigned char **p, const unsigned char *end, x509_crt *crt ) { int ret; size_t len; unsigned char *end_ext_data, *end_ext_octet; if( ( ret = x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) { if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( 0 ); return( ret ); } while( *p < end ) { /* * Extension ::= SEQUENCE { * extnID OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * extnValue OCTET STRING } */ x509_buf extn_oid = {0, 0, NULL}; int is_critical = 0; /* DEFAULT FALSE */ int ext_type = 0; if( ( ret = asn1_get_tag( p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); end_ext_data = *p + len; /* Get extension ID */ extn_oid.tag = **p; if( ( ret = asn1_get_tag( p, end, &extn_oid.len, ASN1_OID ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); extn_oid.p = *p; *p += extn_oid.len; if( ( end - *p ) < 1 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_OUT_OF_DATA ); /* Get optional critical */ if( ( ret = asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); /* Data should be octet string type */ if( ( ret = asn1_get_tag( p, end_ext_data, &len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret ); end_ext_octet = *p + len; if( end_ext_octet != end_ext_data ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); /* * Detect supported extensions */ ret = oid_get_x509_ext_type( &extn_oid, &ext_type ); if( ret != 0 ) { /* No parser found, skip extension */ *p = end_ext_octet; #if !defined(POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) if( is_critical ) { /* Data is marked as critical: fail */ return ( POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); } #endif continue; } crt->ext_types |= ext_type; switch( ext_type ) { case EXT_BASIC_CONSTRAINTS: /* Parse basic constraints */ if( ( ret = x509_get_basic_constraints( p, end_ext_octet, &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) return ( ret ); break; case EXT_KEY_USAGE: /* Parse key usage */ if( ( ret = x509_get_key_usage( p, end_ext_octet, &crt->key_usage ) ) != 0 ) return ( ret ); break; case EXT_EXTENDED_KEY_USAGE: /* Parse extended key usage */ if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, &crt->ext_key_usage ) ) != 0 ) return ( ret ); break; case EXT_SUBJECT_ALT_NAME: /* Parse subject alt name */ if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, &crt->subject_alt_names ) ) != 0 ) return ( ret ); break; case EXT_NS_CERT_TYPE: /* Parse netscape certificate type */ if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, &crt->ns_cert_type ) ) != 0 ) return ( ret ); break; default: return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); } } if( *p != end ) return( POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); return( 0 ); }