/*
* Copyright 2003-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "internal/safe_math.h"
#include <stdio.h>
#include "crypto/asn1.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/http.h>
#include <openssl/x509v3.h>
#include <openssl/bn.h>
#include "crypto/x509.h"
#include "crypto/punycode.h"
#include "ext_dat.h"
OSSL_SAFE_MATH_SIGNED(int, int)
static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
BIO *bp, int ind);
static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp,
int ind, const char *name);
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
static int nc_match_single(int effective_type, GENERAL_NAME *gen,
GENERAL_NAME *base);
static int nc_dn(const X509_NAME *sub, const X509_NAME *nm);
static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
static int nc_email_eai(ASN1_TYPE *emltype, ASN1_IA5STRING *base);
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base);
const X509V3_EXT_METHOD ossl_v3_name_constraints = {
NID_name_constraints, 0,
ASN1_ITEM_ref(NAME_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
0, v2i_NAME_CONSTRAINTS,
i2r_NAME_CONSTRAINTS, 0,
NULL
};
const X509V3_EXT_METHOD ossl_v3_holder_name_constraints = {
NID_holder_name_constraints, 0,
ASN1_ITEM_ref(NAME_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
0, v2i_NAME_CONSTRAINTS,
i2r_NAME_CONSTRAINTS, 0,
NULL
};
const X509V3_EXT_METHOD ossl_v3_delegated_name_constraints = {
NID_delegated_name_constraints, 0,
ASN1_ITEM_ref(NAME_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
0, v2i_NAME_CONSTRAINTS,
i2r_NAME_CONSTRAINTS, 0,
NULL
};
ASN1_SEQUENCE(GENERAL_SUBTREE) = {
ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME),
ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0),
ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1)
} ASN1_SEQUENCE_END(GENERAL_SUBTREE)
ASN1_SEQUENCE(NAME_CONSTRAINTS) = {
ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees,
GENERAL_SUBTREE, 0),
ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees,
GENERAL_SUBTREE, 1),
} ASN1_SEQUENCE_END(NAME_CONSTRAINTS)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
#define IA5_OFFSET_LEN(ia5base, offset) \
((ia5base)->length - ((unsigned char *)(offset) - (ia5base)->data))
/* Like memchr but for ASN1_IA5STRING. Additionally you can specify the
* starting point to search from
*/
# define ia5memchr(str, start, c) memchr(start, c, IA5_OFFSET_LEN(str, start))
/* Like memrrchr but for ASN1_IA5STRING */
static char *ia5memrchr(ASN1_IA5STRING *str, int c)
{
int i;
for (i = str->length; i > 0 && str->data[i - 1] != c; i--);
if (i == 0)
return NULL;
return (char *)&str->data[i - 1];
}
/*
* We cannot use strncasecmp here because that applies locale specific rules. It
* also doesn't work with ASN1_STRINGs that may have embedded NUL characters.
* For example in Turkish 'I' is not the uppercase character for 'i'. We need to
* do a simple ASCII case comparison ignoring the locale (that is why we use
|