Commit 5bd5dcd4 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Add nameConstraints commonName checking.



New hostname checking function asn1_valid_host()

Check commonName entries against nameConstraints: any CN components in
EE certificate which look like hostnames are checked against
nameConstraints.

Note that RFC5280 et al only require checking subject alt name against
DNS name constraints.

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
parent 1d03b7b8
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <string.h>
#include "internal/cryptlib.h"
#include "internal/asn1_int.h"
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/asn1.h>
@@ -592,3 +593,53 @@ int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
    *out = stmp.data;
    return stmp.length;
}

/* Return 1 if host is a valid hostname and 0 otherwise */
int asn1_valid_host(const ASN1_STRING *host)
{
    int hostlen = host->length;
    const unsigned char *hostptr = host->data;
    int type = host->type;
    int i;
    char width = -1;
    unsigned short chflags = 0, prevchflags;

    if (type > 0 && type < 31)
        width = tag2nbyte[type];
    if (width == -1 || hostlen == 0)
        return 0;
    /* Treat UTF8String as width 1 as any MSB set is invalid */
    if (width == 0)
        width = 1;
    for (i = 0 ; i < hostlen; i+= width) {
        prevchflags = chflags;
        /* Value must be <= 0x7F: check upper bytes are all zeroes */
        if (width == 4) {
            if (*hostptr++ != 0 || *hostptr++ != 0 || *hostptr++ != 0)
                return 0;
        } else if (width == 2) {
            if (*hostptr++ != 0)
                return 0;
        }
        if (*hostptr > 0x7f)
            return 0;
        chflags = char_type[*hostptr++];
        if (!(chflags & (CHARTYPE_HOST_ANY | CHARTYPE_HOST_WILD))) {
            /* Nothing else allowed at start or end of string */
            if (i == 0 || i == hostlen - 1)
                return 0;
            /* Otherwise invalid if not dot or hyphen */
            if (!(chflags & (CHARTYPE_HOST_DOT | CHARTYPE_HOST_HYPHEN)))
                return 0;
            /*
             * If previous is dot or hyphen then illegal unless both
             * are hyphens: as .- -. .. are all illegal
             */
            if (prevchflags & (CHARTYPE_HOST_DOT | CHARTYPE_HOST_HYPHEN)
                && ((prevchflags & CHARTYPE_HOST_DOT)
                    || (chflags & CHARTYPE_HOST_DOT)))
                return 0;
        }
    }
    return 1;
}
+16 −8
Original line number Diff line number Diff line
@@ -10,17 +10,25 @@
 * https://www.openssl.org/source/license.html
 */

#define CHARTYPE_HOST_ANY 4096
#define CHARTYPE_HOST_DOT 8192
#define CHARTYPE_HOST_HYPHEN 16384
#define CHARTYPE_HOST_WILD 32768

/*
 * Mask of various character properties
 */

static const unsigned short char_type[] = {
    1026,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    120,  0,  1, 40,  0,  0,  0, 16, 1040, 1040, 1024, 25, 25, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  9,  9, 16,  9, 16,
     0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  0, 1025,  0,  0,  0,
     0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  0,  0,  0,  0,  2
    1026,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,  120,    0,    1,   40,
       0,    0,    0,   16, 1040, 1040, 33792,   25,   25, 16400, 8208,   16,
    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,   16,    9,
       9,   16,    9,   16,    0, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
    4112, 4112, 4112, 4112, 4112, 4112, 4112,    0, 1025,    0,    0,    0,
       0, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
    4112, 4112, 4112,    0,    0,    0,    0,    2
};
+15 −6
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ my $PSTRING_CHAR = 0x10; # Valid PrintableString character
my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character
my $RFC2253_LAST_ESC = 0x40;  # Escaped with \ if last character
my $RFC2254_ESC = 0x400;	# Character escaped \XX
my $HOST_ANY = 0x1000;      # Valid hostname character anywhere in label
my $HOST_DOT = 0x2000;  # Dot: hostname label separator
my $HOST_HYPHEN = 0x4000; # Hyphen: not valid at start or end.
my $HOST_WILD = 0x8000; # Wildcard character

for($i = 0; $i < 128; $i++) {
	# Set the RFC2253 escape characters (control)
@@ -34,7 +38,7 @@ for($i = 0; $i < 128; $i++) {
	if(		   ( ( $i >= ord("a")) && ( $i <= ord("z")) )
			|| (  ( $i >= ord("A")) && ( $i <= ord("Z")) )
			|| (  ( $i >= ord("0")) && ( $i <= ord("9")) )  ) {
		$arr[$i] |= $PSTRING_CHAR;
		$arr[$i] |= $PSTRING_CHAR | $HOST_ANY;
	}
}

@@ -58,7 +62,7 @@ $arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC;
$arr[0] |= $RFC2254_ESC;
$arr[ord("(")] |= $RFC2254_ESC;
$arr[ord(")")] |= $RFC2254_ESC;
$arr[ord("*")] |= $RFC2254_ESC;
$arr[ord("*")] |= $RFC2254_ESC | $HOST_WILD;
$arr[ord("\\")] |= $RFC2254_ESC;

# Remaining PrintableString characters
@@ -69,8 +73,8 @@ $arr[ord("(")] |= $PSTRING_CHAR;
$arr[ord(")")] |= $PSTRING_CHAR;
$arr[ord("+")] |= $PSTRING_CHAR;
$arr[ord(",")] |= $PSTRING_CHAR;
$arr[ord("-")] |= $PSTRING_CHAR;
$arr[ord(".")] |= $PSTRING_CHAR;
$arr[ord("-")] |= $PSTRING_CHAR | $HOST_HYPHEN;
$arr[ord(".")] |= $PSTRING_CHAR | $HOST_DOT;
$arr[ord("/")] |= $PSTRING_CHAR;
$arr[ord(":")] |= $PSTRING_CHAR;
$arr[ord("=")] |= $PSTRING_CHAR;
@@ -91,6 +95,11 @@ print <<EOF;
 * https://www.openssl.org/source/license.html
 */

#define CHARTYPE_HOST_ANY $HOST_ANY
#define CHARTYPE_HOST_DOT $HOST_DOT
#define CHARTYPE_HOST_HYPHEN $HOST_HYPHEN
#define CHARTYPE_HOST_WILD $HOST_WILD

/*
 * Mask of various character properties
 */
@@ -100,8 +109,8 @@ EOF

print "   ";
for($i = 0; $i < 128; $i++) {
	print("\n   ") if($i && (($i % 16) == 0));
	printf(" %2d", $arr[$i]);
	print("\n   ") if($i && (($i % 12) == 0));
	printf(" %4d", $arr[$i]);
	print(",") if ($i != 127);
}
print("\n};\n");
+2 −0
Original line number Diff line number Diff line
@@ -89,3 +89,5 @@ struct asn1_pctx_st {
    unsigned long oid_flags;
    unsigned long str_flags;
} /* ASN1_PCTX */ ;

int asn1_valid_host(const ASN1_STRING *host);
+4 −0
Original line number Diff line number Diff line
@@ -651,6 +651,10 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
            if (nc) {
                int rv = NAME_CONSTRAINTS_check(x, nc);

                /* If EE certificate check commonName too */
                if (rv == X509_V_OK && i == 0)
                    rv = NAME_CONSTRAINTS_check_CN(x, nc);

                switch (rv) {
                case X509_V_OK:
                    break;
Loading