2 * Copyright 2003-2021 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include "internal/cryptlib.h"
11 #include "internal/numbers.h"
13 #include "crypto/asn1.h"
14 #include <openssl/asn1t.h>
15 #include <openssl/conf.h>
16 #include <openssl/x509v3.h>
17 #include <openssl/bn.h>
19 #include "crypto/x509.h"
20 #include "crypto/punycode.h"
23 static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD
*method
,
25 STACK_OF(CONF_VALUE
) *nval
);
26 static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD
*method
, void *a
,
28 static int do_i2r_name_constraints(const X509V3_EXT_METHOD
*method
,
29 STACK_OF(GENERAL_SUBTREE
) *trees
, BIO
*bp
,
30 int ind
, const char *name
);
31 static int print_nc_ipadd(BIO
*bp
, ASN1_OCTET_STRING
*ip
);
33 static int nc_match(GENERAL_NAME
*gen
, NAME_CONSTRAINTS
*nc
);
34 static int nc_match_single(GENERAL_NAME
*sub
, GENERAL_NAME
*gen
);
35 static int nc_dn(const X509_NAME
*sub
, const X509_NAME
*nm
);
36 static int nc_dns(ASN1_IA5STRING
*sub
, ASN1_IA5STRING
*dns
);
37 static int nc_email(ASN1_IA5STRING
*sub
, ASN1_IA5STRING
*eml
);
38 static int nc_email_eai(ASN1_UTF8STRING
*sub
, ASN1_IA5STRING
*eml
);
39 static int nc_uri(ASN1_IA5STRING
*uri
, ASN1_IA5STRING
*base
);
40 static int nc_ip(ASN1_OCTET_STRING
*ip
, ASN1_OCTET_STRING
*base
);
42 const X509V3_EXT_METHOD ossl_v3_name_constraints
= {
43 NID_name_constraints
, 0,
44 ASN1_ITEM_ref(NAME_CONSTRAINTS
),
47 0, v2i_NAME_CONSTRAINTS
,
48 i2r_NAME_CONSTRAINTS
, 0,
52 ASN1_SEQUENCE(GENERAL_SUBTREE
) = {
53 ASN1_SIMPLE(GENERAL_SUBTREE
, base
, GENERAL_NAME
),
54 ASN1_IMP_OPT(GENERAL_SUBTREE
, minimum
, ASN1_INTEGER
, 0),
55 ASN1_IMP_OPT(GENERAL_SUBTREE
, maximum
, ASN1_INTEGER
, 1)
56 } ASN1_SEQUENCE_END(GENERAL_SUBTREE
)
58 ASN1_SEQUENCE(NAME_CONSTRAINTS
) = {
59 ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS
, permittedSubtrees
,
61 ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS
, excludedSubtrees
,
63 } ASN1_SEQUENCE_END(NAME_CONSTRAINTS
)
66 IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE
)
67 IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS
)
70 * We cannot use strncasecmp here because that applies locale specific rules.
71 * For example in Turkish 'I' is not the uppercase character for 'i'. We need to
72 * do a simple ASCII case comparison ignoring the locale (that is why we use
73 * numeric constants below).
75 static int ia5ncasecmp(const char *s1
, const char *s2
, size_t n
)
77 for (; n
> 0; n
--, s1
++, s2
++) {
79 unsigned char c1
= (unsigned char)*s1
, c2
= (unsigned char)*s2
;
81 /* Convert to lower case */
82 if (c1
>= 0x41 /* A */ && c1
<= 0x5A /* Z */)
84 if (c2
>= 0x41 /* A */ && c2
<= 0x5A /* Z */)
95 } else if (*s1
== 0) {
96 /* If we get here we know that *s2 == 0 too */
104 static int ia5casecmp(const char *s1
, const char *s2
)
106 return ia5ncasecmp(s1
, s2
, SIZE_MAX
);
109 static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD
*method
,
110 X509V3_CTX
*ctx
, STACK_OF(CONF_VALUE
) *nval
)
113 CONF_VALUE tval
, *val
;
114 STACK_OF(GENERAL_SUBTREE
) **ptree
= NULL
;
115 NAME_CONSTRAINTS
*ncons
= NULL
;
116 GENERAL_SUBTREE
*sub
= NULL
;
118 ncons
= NAME_CONSTRAINTS_new();
121 for (i
= 0; i
< sk_CONF_VALUE_num(nval
); i
++) {
122 val
= sk_CONF_VALUE_value(nval
, i
);
123 if (strncmp(val
->name
, "permitted", 9) == 0 && val
->name
[9]) {
124 ptree
= &ncons
->permittedSubtrees
;
125 tval
.name
= val
->name
+ 10;
126 } else if (strncmp(val
->name
, "excluded", 8) == 0 && val
->name
[8]) {
127 ptree
= &ncons
->excludedSubtrees
;
128 tval
.name
= val
->name
+ 9;
130 ERR_raise(ERR_LIB_X509V3
, X509V3_R_INVALID_SYNTAX
);
133 tval
.value
= val
->value
;
134 sub
= GENERAL_SUBTREE_new();
137 if (!v2i_GENERAL_NAME_ex(sub
->base
, method
, ctx
, &tval
, 1))
140 *ptree
= sk_GENERAL_SUBTREE_new_null();
141 if (*ptree
== NULL
|| !sk_GENERAL_SUBTREE_push(*ptree
, sub
))
149 ERR_raise(ERR_LIB_X509V3
, ERR_R_MALLOC_FAILURE
);
151 NAME_CONSTRAINTS_free(ncons
);
152 GENERAL_SUBTREE_free(sub
);
157 static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD
*method
, void *a
,
160 NAME_CONSTRAINTS
*ncons
= a
;
161 do_i2r_name_constraints(method
, ncons
->permittedSubtrees
,
162 bp
, ind
, "Permitted");
163 if (ncons
->permittedSubtrees
&& ncons
->excludedSubtrees
)
165 do_i2r_name_constraints(method
, ncons
->excludedSubtrees
,
166 bp
, ind
, "Excluded");
170 static int do_i2r_name_constraints(const X509V3_EXT_METHOD
*method
,
171 STACK_OF(GENERAL_SUBTREE
) *trees
,
172 BIO
*bp
, int ind
, const char *name
)
174 GENERAL_SUBTREE
*tree
;
176 if (sk_GENERAL_SUBTREE_num(trees
) > 0)
177 BIO_printf(bp
, "%*s%s:\n", ind
, "", name
);
178 for (i
= 0; i
< sk_GENERAL_SUBTREE_num(trees
); i
++) {
181 tree
= sk_GENERAL_SUBTREE_value(trees
, i
);
182 BIO_printf(bp
, "%*s", ind
+ 2, "");
183 if (tree
->base
->type
== GEN_IPADD
)
184 print_nc_ipadd(bp
, tree
->base
->d
.ip
);
186 GENERAL_NAME_print(bp
, tree
->base
);
191 static int print_nc_ipadd(BIO
*bp
, ASN1_OCTET_STRING
*ip
)
193 /* ip->length should be 8 or 32 and len1 == len2 == 4 or len1 == len2 == 16 */
194 int len1
= ip
->length
>= 16 ? 16 : ip
->length
>= 4 ? 4 : ip
->length
;
195 int len2
= ip
->length
- len1
;
196 char *ip1
= ossl_ipaddr_to_asc(ip
->data
, len1
);
197 char *ip2
= ossl_ipaddr_to_asc(ip
->data
+ len1
, len2
);
198 int ret
= ip1
!= NULL
&& ip2
!= NULL
199 && BIO_printf(bp
, "IP:%s/%s", ip1
, ip2
) > 0;
206 #define NAME_CHECK_MAX (1 << 20)
208 static int add_lengths(int *out
, int a
, int b
)
210 /* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */
223 * Check a certificate conforms to a specified set of constraints.
225 * X509_V_OK: All constraints obeyed.
226 * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
227 * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
228 * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
229 * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type.
230 * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
231 * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
234 int NAME_CONSTRAINTS_check(X509
*x
, NAME_CONSTRAINTS
*nc
)
236 int r
, i
, name_count
, constraint_count
;
239 nm
= X509_get_subject_name(x
);
242 * Guard against certificates with an excessive number of names or
243 * constraints causing a computationally expensive name constraints check.
245 if (!add_lengths(&name_count
, X509_NAME_entry_count(nm
),
246 sk_GENERAL_NAME_num(x
->altname
))
247 || !add_lengths(&constraint_count
,
248 sk_GENERAL_SUBTREE_num(nc
->permittedSubtrees
),
249 sk_GENERAL_SUBTREE_num(nc
->excludedSubtrees
))
250 || (name_count
> 0 && constraint_count
> NAME_CHECK_MAX
/ name_count
))
251 return X509_V_ERR_UNSPECIFIED
;
253 if (X509_NAME_entry_count(nm
) > 0) {
255 gntmp
.type
= GEN_DIRNAME
;
256 gntmp
.d
.directoryName
= nm
;
258 r
= nc_match(&gntmp
, nc
);
263 gntmp
.type
= GEN_EMAIL
;
265 /* Process any email address attributes in subject name */
268 const X509_NAME_ENTRY
*ne
;
270 i
= X509_NAME_get_index_by_NID(nm
, NID_pkcs9_emailAddress
, i
);
273 ne
= X509_NAME_get_entry(nm
, i
);
274 gntmp
.d
.rfc822Name
= X509_NAME_ENTRY_get_data(ne
);
275 if (gntmp
.d
.rfc822Name
->type
!= V_ASN1_IA5STRING
)
276 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
278 r
= nc_match(&gntmp
, nc
);
286 for (i
= 0; i
< sk_GENERAL_NAME_num(x
->altname
); i
++) {
287 GENERAL_NAME
*gen
= sk_GENERAL_NAME_value(x
->altname
, i
);
288 r
= nc_match(gen
, nc
);
297 static int cn2dnsid(ASN1_STRING
*cn
, unsigned char **dnsid
, size_t *idlen
)
300 unsigned char *utf8_value
;
304 /* Don't leave outputs uninitialized */
309 * Per RFC 6125, DNS-IDs representing internationalized domain names appear
310 * in certificates in A-label encoded form:
312 * https://tools.ietf.org/html/rfc6125#section-6.4.2
314 * The same applies to CNs which are intended to represent DNS names.
315 * However, while in the SAN DNS-IDs are IA5Strings, as CNs they may be
316 * needlessly encoded in 16-bit Unicode. We perform a conversion to UTF-8
317 * to ensure that we get an ASCII representation of any CNs that are
318 * representable as ASCII, but just not encoded as ASCII. The UTF-8 form
319 * may contain some non-ASCII octets, and that's fine, such CNs are not
320 * valid legacy DNS names.
322 * Note, 'int' is the return type of ASN1_STRING_to_UTF8() so that's what
323 * we must use for 'utf8_length'.
325 if ((utf8_length
= ASN1_STRING_to_UTF8(&utf8_value
, cn
)) < 0)
326 return X509_V_ERR_OUT_OF_MEM
;
329 * Some certificates have had names that include a *trailing* NUL byte.
330 * Remove these harmless NUL characters. They would otherwise yield false
331 * alarms with the following embedded NUL check.
333 while (utf8_length
> 0 && utf8_value
[utf8_length
- 1] == '\0')
336 /* Reject *embedded* NULs */
337 if ((size_t)utf8_length
!= strlen((char *)utf8_value
)) {
338 OPENSSL_free(utf8_value
);
339 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
343 * XXX: Deviation from strict DNS name syntax, also check names with '_'
344 * Check DNS name syntax, any '-' or '.' must be internal,
345 * and on either side of each '.' we can't have a '-' or '.'.
347 * If the name has just one label, we don't consider it a DNS name. This
348 * means that "CN=sometld" cannot be precluded by DNS name constraints, but
349 * that is not a problem.
351 for (i
= 0; i
< utf8_length
; ++i
) {
352 unsigned char c
= utf8_value
[i
];
354 if ((c
>= 'a' && c
<= 'z')
355 || (c
>= 'A' && c
<= 'Z')
356 || (c
>= '0' && c
<= '9')
360 /* Dot and hyphen cannot be first or last. */
361 if (i
> 0 && i
< utf8_length
- 1) {
365 * Next to a dot the preceding and following characters must not be
366 * another dot or a hyphen. Otherwise, record that the name is
367 * plausible, since it has two or more labels.
370 && utf8_value
[i
+ 1] != '.'
371 && utf8_value
[i
- 1] != '-'
372 && utf8_value
[i
+ 1] != '-') {
383 *idlen
= (size_t)utf8_length
;
386 OPENSSL_free(utf8_value
);
391 * Check CN against DNS-ID name constraints.
393 int NAME_CONSTRAINTS_check_CN(X509
*x
, NAME_CONSTRAINTS
*nc
)
396 const X509_NAME
*nm
= X509_get_subject_name(x
);
401 stmp
.type
= V_ASN1_IA5STRING
;
402 gntmp
.type
= GEN_DNS
;
403 gntmp
.d
.dNSName
= &stmp
;
405 /* Process any commonName attributes in subject name */
410 unsigned char *idval
;
413 i
= X509_NAME_get_index_by_NID(nm
, NID_commonName
, i
);
416 ne
= X509_NAME_get_entry(nm
, i
);
417 cn
= X509_NAME_ENTRY_get_data(ne
);
419 /* Only process attributes that look like host names */
420 if ((r
= cn2dnsid(cn
, &idval
, &idlen
)) != X509_V_OK
)
427 r
= nc_match(&gntmp
, nc
);
436 * Return nonzero if the GeneralSubtree has valid 'minimum' field
437 * (must be absent or 0) and valid 'maximum' field (must be absent).
439 static int nc_minmax_valid(GENERAL_SUBTREE
*sub
) {
447 bn
= ASN1_INTEGER_to_BN(sub
->minimum
, NULL
);
448 if (bn
== NULL
|| !BN_is_zero(bn
))
456 static int nc_match(GENERAL_NAME
*gen
, NAME_CONSTRAINTS
*nc
)
458 GENERAL_SUBTREE
*sub
;
461 * We need to compare not gen->type field but an "effective" type because
462 * the otherName field may contain EAI email address treated specially
463 * according to RFC 8398, section 6
465 int effective_type
= ((gen
->type
== GEN_OTHERNAME
) &&
466 (OBJ_obj2nid(gen
->d
.otherName
->type_id
) ==
467 NID_id_on_SmtpUTF8Mailbox
)) ? GEN_EMAIL
: gen
->type
;
470 * Permitted subtrees: if any subtrees exist of matching the type at
471 * least one subtree must match.
474 for (i
= 0; i
< sk_GENERAL_SUBTREE_num(nc
->permittedSubtrees
); i
++) {
475 sub
= sk_GENERAL_SUBTREE_value(nc
->permittedSubtrees
, i
);
476 if (effective_type
!= sub
->base
->type
)
478 if (!nc_minmax_valid(sub
))
479 return X509_V_ERR_SUBTREE_MINMAX
;
480 /* If we already have a match don't bother trying any more */
485 r
= nc_match_single(gen
, sub
->base
);
488 else if (r
!= X509_V_ERR_PERMITTED_VIOLATION
)
493 return X509_V_ERR_PERMITTED_VIOLATION
;
495 /* Excluded subtrees: must not match any of these */
497 for (i
= 0; i
< sk_GENERAL_SUBTREE_num(nc
->excludedSubtrees
); i
++) {
498 sub
= sk_GENERAL_SUBTREE_value(nc
->excludedSubtrees
, i
);
499 if (effective_type
!= sub
->base
->type
)
501 if (!nc_minmax_valid(sub
))
502 return X509_V_ERR_SUBTREE_MINMAX
;
504 r
= nc_match_single(gen
, sub
->base
);
506 return X509_V_ERR_EXCLUDED_VIOLATION
;
507 else if (r
!= X509_V_ERR_PERMITTED_VIOLATION
)
516 static int nc_match_single(GENERAL_NAME
*gen
, GENERAL_NAME
*base
)
521 * We are here only when we have SmtpUTF8 name,
522 * so we match the value of othername with base->d.rfc822Name
524 return nc_email_eai(gen
->d
.otherName
->value
->value
.utf8string
,
527 return nc_dn(gen
->d
.directoryName
, base
->d
.directoryName
);
530 return nc_dns(gen
->d
.dNSName
, base
->d
.dNSName
);
533 return nc_email(gen
->d
.rfc822Name
, base
->d
.rfc822Name
);
536 return nc_uri(gen
->d
.uniformResourceIdentifier
,
537 base
->d
.uniformResourceIdentifier
);
540 return nc_ip(gen
->d
.iPAddress
, base
->d
.iPAddress
);
543 return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE
;
549 * directoryName name constraint matching. The canonical encoding of
550 * X509_NAME makes this comparison easy. It is matched if the subtree is a
551 * subset of the name.
554 static int nc_dn(const X509_NAME
*nm
, const X509_NAME
*base
)
556 /* Ensure canonical encodings are up to date. */
557 if (nm
->modified
&& i2d_X509_NAME(nm
, NULL
) < 0)
558 return X509_V_ERR_OUT_OF_MEM
;
559 if (base
->modified
&& i2d_X509_NAME(base
, NULL
) < 0)
560 return X509_V_ERR_OUT_OF_MEM
;
561 if (base
->canon_enclen
> nm
->canon_enclen
)
562 return X509_V_ERR_PERMITTED_VIOLATION
;
563 if (memcmp(base
->canon_enc
, nm
->canon_enc
, base
->canon_enclen
))
564 return X509_V_ERR_PERMITTED_VIOLATION
;
568 static int nc_dns(ASN1_IA5STRING
*dns
, ASN1_IA5STRING
*base
)
570 char *baseptr
= (char *)base
->data
;
571 char *dnsptr
= (char *)dns
->data
;
573 /* Empty matches everything */
574 if (*baseptr
== '\0')
577 * Otherwise can add zero or more components on the left so compare RHS
578 * and if dns is longer and expect '.' as preceding character.
580 if (dns
->length
> base
->length
) {
581 dnsptr
+= dns
->length
- base
->length
;
582 if (*baseptr
!= '.' && dnsptr
[-1] != '.')
583 return X509_V_ERR_PERMITTED_VIOLATION
;
586 if (ia5casecmp(baseptr
, dnsptr
))
587 return X509_V_ERR_PERMITTED_VIOLATION
;
594 * This function implements comparison between ASCII/U-label in eml
595 * and A-label in base according to RFC 8398, section 6.
596 * Convert base to U-label and ASCII-parts of domain names, for base
597 * Octet-to-octet comparison of `eml` and `base` hostname parts
598 * (ASCII-parts should be compared in case-insensitive manner)
600 static int nc_email_eai(ASN1_UTF8STRING
*eml
, ASN1_IA5STRING
*base
)
602 const char *baseptr
= (char *)base
->data
;
603 const char *emlptr
= (char *)eml
->data
;
604 const char *emlat
= strrchr(emlptr
, '@');
607 size_t size
= sizeof(ulabel
) - 1;
610 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
612 memset(ulabel
, 0, sizeof(ulabel
));
613 /* Special case: initial '.' is RHS match */
614 if (*baseptr
== '.') {
617 if (ossl_a2ulabel(baseptr
, ulabel
+ 1, &size
) <= 0)
618 return X509_V_ERR_UNSPECIFIED
;
620 if ((size_t)eml
->length
> size
+ 1) {
621 emlptr
+= eml
->length
- (size
+ 1);
622 if (ia5casecmp(ulabel
, emlptr
) == 0)
625 return X509_V_ERR_PERMITTED_VIOLATION
;
629 if (ossl_a2ulabel(baseptr
, ulabel
, &size
) <= 0)
630 return X509_V_ERR_UNSPECIFIED
;
631 /* Just have hostname left to match: case insensitive */
632 if (ia5casecmp(ulabel
, emlptr
))
633 return X509_V_ERR_PERMITTED_VIOLATION
;
639 static int nc_email(ASN1_IA5STRING
*eml
, ASN1_IA5STRING
*base
)
641 const char *baseptr
= (char *)base
->data
;
642 const char *emlptr
= (char *)eml
->data
;
644 const char *baseat
= strrchr(baseptr
, '@');
645 const char *emlat
= strrchr(emlptr
, '@');
647 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
648 /* Special case: initial '.' is RHS match */
649 if (!baseat
&& (*baseptr
== '.')) {
650 if (eml
->length
> base
->length
) {
651 emlptr
+= eml
->length
- base
->length
;
652 if (ia5casecmp(baseptr
, emlptr
) == 0)
655 return X509_V_ERR_PERMITTED_VIOLATION
;
658 /* If we have anything before '@' match local part */
661 if (baseat
!= baseptr
) {
662 if ((baseat
- baseptr
) != (emlat
- emlptr
))
663 return X509_V_ERR_PERMITTED_VIOLATION
;
664 /* Case sensitive match of local part */
665 if (strncmp(baseptr
, emlptr
, emlat
- emlptr
))
666 return X509_V_ERR_PERMITTED_VIOLATION
;
668 /* Position base after '@' */
669 baseptr
= baseat
+ 1;
672 /* Just have hostname left to match: case insensitive */
673 if (ia5casecmp(baseptr
, emlptr
))
674 return X509_V_ERR_PERMITTED_VIOLATION
;
680 static int nc_uri(ASN1_IA5STRING
*uri
, ASN1_IA5STRING
*base
)
682 const char *baseptr
= (char *)base
->data
;
683 const char *hostptr
= (char *)uri
->data
;
684 const char *p
= strchr(hostptr
, ':');
687 /* Check for foo:// and skip past it */
688 if (p
== NULL
|| p
[1] != '/' || p
[2] != '/')
689 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
692 /* Determine length of hostname part of URI */
694 /* Look for a port indicator as end of hostname first */
696 p
= strchr(hostptr
, ':');
697 /* Otherwise look for trailing slash */
699 p
= strchr(hostptr
, '/');
702 hostlen
= strlen(hostptr
);
704 hostlen
= p
- hostptr
;
707 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
709 /* Special case: initial '.' is RHS match */
710 if (*baseptr
== '.') {
711 if (hostlen
> base
->length
) {
712 p
= hostptr
+ hostlen
- base
->length
;
713 if (ia5ncasecmp(p
, baseptr
, base
->length
) == 0)
716 return X509_V_ERR_PERMITTED_VIOLATION
;
719 if ((base
->length
!= (int)hostlen
)
720 || ia5ncasecmp(hostptr
, baseptr
, hostlen
))
721 return X509_V_ERR_PERMITTED_VIOLATION
;
727 static int nc_ip(ASN1_OCTET_STRING
*ip
, ASN1_OCTET_STRING
*base
)
729 int hostlen
, baselen
, i
;
730 unsigned char *hostptr
, *baseptr
, *maskptr
;
732 hostlen
= ip
->length
;
733 baseptr
= base
->data
;
734 baselen
= base
->length
;
736 /* Invalid if not IPv4 or IPv6 */
737 if (!((hostlen
== 4) || (hostlen
== 16)))
738 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
739 if (!((baselen
== 8) || (baselen
== 32)))
740 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
;
742 /* Do not match IPv4 with IPv6 */
743 if (hostlen
* 2 != baselen
)
744 return X509_V_ERR_PERMITTED_VIOLATION
;
746 maskptr
= base
->data
+ hostlen
;
748 /* Considering possible not aligned base ipAddress */
749 /* Not checking for wrong mask definition: i.e.: 255.0.255.0 */
750 for (i
= 0; i
< hostlen
; i
++)
751 if ((hostptr
[i
] & maskptr
[i
]) != (baseptr
[i
] & maskptr
[i
]))
752 return X509_V_ERR_PERMITTED_VIOLATION
;