1160814Ssimon/* v3_ncons.c */
2296341Sdelphij/*
3296341Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4160814Ssimon * project.
5160814Ssimon */
6160814Ssimon/* ====================================================================
7160814Ssimon * Copyright (c) 2003 The OpenSSL Project.  All rights reserved.
8160814Ssimon *
9160814Ssimon * Redistribution and use in source and binary forms, with or without
10160814Ssimon * modification, are permitted provided that the following conditions
11160814Ssimon * are met:
12160814Ssimon *
13160814Ssimon * 1. Redistributions of source code must retain the above copyright
14296341Sdelphij *    notice, this list of conditions and the following disclaimer.
15160814Ssimon *
16160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17160814Ssimon *    notice, this list of conditions and the following disclaimer in
18160814Ssimon *    the documentation and/or other materials provided with the
19160814Ssimon *    distribution.
20160814Ssimon *
21160814Ssimon * 3. All advertising materials mentioning features or use of this
22160814Ssimon *    software must display the following acknowledgment:
23160814Ssimon *    "This product includes software developed by the OpenSSL Project
24160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25160814Ssimon *
26160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27160814Ssimon *    endorse or promote products derived from this software without
28160814Ssimon *    prior written permission. For written permission, please contact
29160814Ssimon *    licensing@OpenSSL.org.
30160814Ssimon *
31160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
33160814Ssimon *    permission of the OpenSSL Project.
34160814Ssimon *
35160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
36160814Ssimon *    acknowledgment:
37160814Ssimon *    "This product includes software developed by the OpenSSL Project
38160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39160814Ssimon *
40160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52160814Ssimon * ====================================================================
53160814Ssimon *
54160814Ssimon * This product includes cryptographic software written by Eric Young
55160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
56160814Ssimon * Hudson (tjh@cryptsoft.com).
57160814Ssimon *
58160814Ssimon */
59160814Ssimon
60160814Ssimon#include <stdio.h>
61160814Ssimon#include "cryptlib.h"
62160814Ssimon#include <openssl/asn1t.h>
63160814Ssimon#include <openssl/conf.h>
64160814Ssimon#include <openssl/x509v3.h>
65160814Ssimon
66238405Sjkimstatic void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
67296341Sdelphij                                  X509V3_CTX *ctx,
68296341Sdelphij                                  STACK_OF(CONF_VALUE) *nval);
69296341Sdelphijstatic int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
70296341Sdelphij                                BIO *bp, int ind);
71238405Sjkimstatic int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
72296341Sdelphij                                   STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp,
73296341Sdelphij                                   int ind, char *name);
74160814Ssimonstatic int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
75160814Ssimon
76238405Sjkimstatic int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
77238405Sjkimstatic int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
78238405Sjkimstatic int nc_dn(X509_NAME *sub, X509_NAME *nm);
79238405Sjkimstatic int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
80238405Sjkimstatic int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
81238405Sjkimstatic int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
82238405Sjkim
83167612Ssimonconst X509V3_EXT_METHOD v3_name_constraints = {
84296341Sdelphij    NID_name_constraints, 0,
85296341Sdelphij    ASN1_ITEM_ref(NAME_CONSTRAINTS),
86296341Sdelphij    0, 0, 0, 0,
87296341Sdelphij    0, 0,
88296341Sdelphij    0, v2i_NAME_CONSTRAINTS,
89296341Sdelphij    i2r_NAME_CONSTRAINTS, 0,
90296341Sdelphij    NULL
91160814Ssimon};
92160814Ssimon
93160814SsimonASN1_SEQUENCE(GENERAL_SUBTREE) = {
94296341Sdelphij        ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME),
95296341Sdelphij        ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0),
96296341Sdelphij        ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1)
97160814Ssimon} ASN1_SEQUENCE_END(GENERAL_SUBTREE)
98160814Ssimon
99160814SsimonASN1_SEQUENCE(NAME_CONSTRAINTS) = {
100296341Sdelphij        ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees,
101296341Sdelphij                                                        GENERAL_SUBTREE, 0),
102296341Sdelphij        ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees,
103296341Sdelphij                                                        GENERAL_SUBTREE, 1),
104160814Ssimon} ASN1_SEQUENCE_END(NAME_CONSTRAINTS)
105160814Ssimon
106296341Sdelphij
107160814SsimonIMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
108160814SsimonIMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
109160814Ssimon
110238405Sjkimstatic void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
111296341Sdelphij                                  X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
112296341Sdelphij{
113296341Sdelphij    int i;
114296341Sdelphij    CONF_VALUE tval, *val;
115296341Sdelphij    STACK_OF(GENERAL_SUBTREE) **ptree = NULL;
116296341Sdelphij    NAME_CONSTRAINTS *ncons = NULL;
117296341Sdelphij    GENERAL_SUBTREE *sub = NULL;
118296341Sdelphij    ncons = NAME_CONSTRAINTS_new();
119296341Sdelphij    if (!ncons)
120296341Sdelphij        goto memerr;
121296341Sdelphij    for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
122296341Sdelphij        val = sk_CONF_VALUE_value(nval, i);
123296341Sdelphij        if (!strncmp(val->name, "permitted", 9) && val->name[9]) {
124296341Sdelphij            ptree = &ncons->permittedSubtrees;
125296341Sdelphij            tval.name = val->name + 10;
126296341Sdelphij        } else if (!strncmp(val->name, "excluded", 8) && val->name[8]) {
127296341Sdelphij            ptree = &ncons->excludedSubtrees;
128296341Sdelphij            tval.name = val->name + 9;
129296341Sdelphij        } else {
130296341Sdelphij            X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX);
131296341Sdelphij            goto err;
132296341Sdelphij        }
133296341Sdelphij        tval.value = val->value;
134296341Sdelphij        sub = GENERAL_SUBTREE_new();
135296341Sdelphij        if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1))
136296341Sdelphij            goto err;
137296341Sdelphij        if (!*ptree)
138296341Sdelphij            *ptree = sk_GENERAL_SUBTREE_new_null();
139296341Sdelphij        if (!*ptree || !sk_GENERAL_SUBTREE_push(*ptree, sub))
140296341Sdelphij            goto memerr;
141296341Sdelphij        sub = NULL;
142296341Sdelphij    }
143160814Ssimon
144296341Sdelphij    return ncons;
145160814Ssimon
146296341Sdelphij memerr:
147296341Sdelphij    X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
148296341Sdelphij err:
149296341Sdelphij    if (ncons)
150296341Sdelphij        NAME_CONSTRAINTS_free(ncons);
151296341Sdelphij    if (sub)
152296341Sdelphij        GENERAL_SUBTREE_free(sub);
153160814Ssimon
154296341Sdelphij    return NULL;
155296341Sdelphij}
156160814Ssimon
157238405Sjkimstatic int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
158296341Sdelphij                                BIO *bp, int ind)
159296341Sdelphij{
160296341Sdelphij    NAME_CONSTRAINTS *ncons = a;
161296341Sdelphij    do_i2r_name_constraints(method, ncons->permittedSubtrees,
162296341Sdelphij                            bp, ind, "Permitted");
163296341Sdelphij    do_i2r_name_constraints(method, ncons->excludedSubtrees,
164296341Sdelphij                            bp, ind, "Excluded");
165296341Sdelphij    return 1;
166296341Sdelphij}
167160814Ssimon
168238405Sjkimstatic int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
169296341Sdelphij                                   STACK_OF(GENERAL_SUBTREE) *trees,
170296341Sdelphij                                   BIO *bp, int ind, char *name)
171296341Sdelphij{
172296341Sdelphij    GENERAL_SUBTREE *tree;
173296341Sdelphij    int i;
174296341Sdelphij    if (sk_GENERAL_SUBTREE_num(trees) > 0)
175296341Sdelphij        BIO_printf(bp, "%*s%s:\n", ind, "", name);
176296341Sdelphij    for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
177296341Sdelphij        tree = sk_GENERAL_SUBTREE_value(trees, i);
178296341Sdelphij        BIO_printf(bp, "%*s", ind + 2, "");
179296341Sdelphij        if (tree->base->type == GEN_IPADD)
180296341Sdelphij            print_nc_ipadd(bp, tree->base->d.ip);
181296341Sdelphij        else
182296341Sdelphij            GENERAL_NAME_print(bp, tree->base);
183296341Sdelphij        BIO_puts(bp, "\n");
184296341Sdelphij    }
185296341Sdelphij    return 1;
186296341Sdelphij}
187160814Ssimon
188160814Ssimonstatic int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
189296341Sdelphij{
190296341Sdelphij    int i, len;
191296341Sdelphij    unsigned char *p;
192296341Sdelphij    p = ip->data;
193296341Sdelphij    len = ip->length;
194296341Sdelphij    BIO_puts(bp, "IP:");
195296341Sdelphij    if (len == 8) {
196296341Sdelphij        BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d",
197296341Sdelphij                   p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
198296341Sdelphij    } else if (len == 32) {
199296341Sdelphij        for (i = 0; i < 16; i++) {
200296341Sdelphij            BIO_printf(bp, "%X", p[0] << 8 | p[1]);
201296341Sdelphij            p += 2;
202296341Sdelphij            if (i == 7)
203296341Sdelphij                BIO_puts(bp, "/");
204296341Sdelphij            else if (i != 15)
205296341Sdelphij                BIO_puts(bp, ":");
206296341Sdelphij        }
207296341Sdelphij    } else
208296341Sdelphij        BIO_printf(bp, "IP Address:<invalid>");
209296341Sdelphij    return 1;
210296341Sdelphij}
211160814Ssimon
212296341Sdelphij/*-
213296341Sdelphij * Check a certificate conforms to a specified set of constraints.
214238405Sjkim * Return values:
215238405Sjkim *  X509_V_OK: All constraints obeyed.
216238405Sjkim *  X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
217238405Sjkim *  X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
218238405Sjkim *  X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
219238405Sjkim *  X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:  Unsupported constraint type.
220238405Sjkim *  X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
221238405Sjkim *  X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
222238405Sjkim */
223238405Sjkim
224238405Sjkimint NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
225296341Sdelphij{
226296341Sdelphij    int r, i;
227296341Sdelphij    X509_NAME *nm;
228238405Sjkim
229296341Sdelphij    nm = X509_get_subject_name(x);
230238405Sjkim
231296341Sdelphij    if (X509_NAME_entry_count(nm) > 0) {
232296341Sdelphij        GENERAL_NAME gntmp;
233296341Sdelphij        gntmp.type = GEN_DIRNAME;
234296341Sdelphij        gntmp.d.directoryName = nm;
235238405Sjkim
236296341Sdelphij        r = nc_match(&gntmp, nc);
237238405Sjkim
238296341Sdelphij        if (r != X509_V_OK)
239296341Sdelphij            return r;
240238405Sjkim
241296341Sdelphij        gntmp.type = GEN_EMAIL;
242238405Sjkim
243296341Sdelphij        /* Process any email address attributes in subject name */
244238405Sjkim
245296341Sdelphij        for (i = -1;;) {
246296341Sdelphij            X509_NAME_ENTRY *ne;
247296341Sdelphij            i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i);
248296341Sdelphij            if (i == -1)
249296341Sdelphij                break;
250296341Sdelphij            ne = X509_NAME_get_entry(nm, i);
251296341Sdelphij            gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
252296341Sdelphij            if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING)
253296341Sdelphij                return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
254238405Sjkim
255296341Sdelphij            r = nc_match(&gntmp, nc);
256238405Sjkim
257296341Sdelphij            if (r != X509_V_OK)
258296341Sdelphij                return r;
259296341Sdelphij        }
260238405Sjkim
261296341Sdelphij    }
262238405Sjkim
263296341Sdelphij    for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) {
264296341Sdelphij        GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i);
265296341Sdelphij        r = nc_match(gen, nc);
266296341Sdelphij        if (r != X509_V_OK)
267296341Sdelphij            return r;
268296341Sdelphij    }
269238405Sjkim
270296341Sdelphij    return X509_V_OK;
271238405Sjkim
272296341Sdelphij}
273238405Sjkim
274238405Sjkimstatic int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
275296341Sdelphij{
276296341Sdelphij    GENERAL_SUBTREE *sub;
277296341Sdelphij    int i, r, match = 0;
278238405Sjkim
279296341Sdelphij    /*
280296341Sdelphij     * Permitted subtrees: if any subtrees exist of matching the type at
281296341Sdelphij     * least one subtree must match.
282296341Sdelphij     */
283238405Sjkim
284296341Sdelphij    for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
285296341Sdelphij        sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
286296341Sdelphij        if (gen->type != sub->base->type)
287296341Sdelphij            continue;
288296341Sdelphij        if (sub->minimum || sub->maximum)
289296341Sdelphij            return X509_V_ERR_SUBTREE_MINMAX;
290296341Sdelphij        /* If we already have a match don't bother trying any more */
291296341Sdelphij        if (match == 2)
292296341Sdelphij            continue;
293296341Sdelphij        if (match == 0)
294296341Sdelphij            match = 1;
295296341Sdelphij        r = nc_match_single(gen, sub->base);
296296341Sdelphij        if (r == X509_V_OK)
297296341Sdelphij            match = 2;
298296341Sdelphij        else if (r != X509_V_ERR_PERMITTED_VIOLATION)
299296341Sdelphij            return r;
300296341Sdelphij    }
301238405Sjkim
302296341Sdelphij    if (match == 1)
303296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
304238405Sjkim
305296341Sdelphij    /* Excluded subtrees: must not match any of these */
306238405Sjkim
307296341Sdelphij    for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
308296341Sdelphij        sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
309296341Sdelphij        if (gen->type != sub->base->type)
310296341Sdelphij            continue;
311296341Sdelphij        if (sub->minimum || sub->maximum)
312296341Sdelphij            return X509_V_ERR_SUBTREE_MINMAX;
313238405Sjkim
314296341Sdelphij        r = nc_match_single(gen, sub->base);
315296341Sdelphij        if (r == X509_V_OK)
316296341Sdelphij            return X509_V_ERR_EXCLUDED_VIOLATION;
317296341Sdelphij        else if (r != X509_V_ERR_PERMITTED_VIOLATION)
318296341Sdelphij            return r;
319238405Sjkim
320296341Sdelphij    }
321238405Sjkim
322296341Sdelphij    return X509_V_OK;
323238405Sjkim
324296341Sdelphij}
325238405Sjkim
326238405Sjkimstatic int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base)
327296341Sdelphij{
328296341Sdelphij    switch (base->type) {
329296341Sdelphij    case GEN_DIRNAME:
330296341Sdelphij        return nc_dn(gen->d.directoryName, base->d.directoryName);
331238405Sjkim
332296341Sdelphij    case GEN_DNS:
333296341Sdelphij        return nc_dns(gen->d.dNSName, base->d.dNSName);
334238405Sjkim
335296341Sdelphij    case GEN_EMAIL:
336296341Sdelphij        return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
337238405Sjkim
338296341Sdelphij    case GEN_URI:
339296341Sdelphij        return nc_uri(gen->d.uniformResourceIdentifier,
340296341Sdelphij                      base->d.uniformResourceIdentifier);
341238405Sjkim
342296341Sdelphij    default:
343296341Sdelphij        return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
344296341Sdelphij    }
345238405Sjkim
346296341Sdelphij}
347238405Sjkim
348296341Sdelphij/*
349296341Sdelphij * directoryName name constraint matching. The canonical encoding of
350296341Sdelphij * X509_NAME makes this comparison easy. It is matched if the subtree is a
351296341Sdelphij * subset of the name.
352238405Sjkim */
353238405Sjkim
354238405Sjkimstatic int nc_dn(X509_NAME *nm, X509_NAME *base)
355296341Sdelphij{
356296341Sdelphij    /* Ensure canonical encodings are up to date.  */
357296341Sdelphij    if (nm->modified && i2d_X509_NAME(nm, NULL) < 0)
358296341Sdelphij        return X509_V_ERR_OUT_OF_MEM;
359296341Sdelphij    if (base->modified && i2d_X509_NAME(base, NULL) < 0)
360296341Sdelphij        return X509_V_ERR_OUT_OF_MEM;
361296341Sdelphij    if (base->canon_enclen > nm->canon_enclen)
362296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
363296341Sdelphij    if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen))
364296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
365296341Sdelphij    return X509_V_OK;
366296341Sdelphij}
367238405Sjkim
368238405Sjkimstatic int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
369296341Sdelphij{
370296341Sdelphij    char *baseptr = (char *)base->data;
371296341Sdelphij    char *dnsptr = (char *)dns->data;
372296341Sdelphij    /* Empty matches everything */
373296341Sdelphij    if (!*baseptr)
374296341Sdelphij        return X509_V_OK;
375296341Sdelphij    /*
376296341Sdelphij     * Otherwise can add zero or more components on the left so compare RHS
377296341Sdelphij     * and if dns is longer and expect '.' as preceding character.
378296341Sdelphij     */
379296341Sdelphij    if (dns->length > base->length) {
380296341Sdelphij        dnsptr += dns->length - base->length;
381296341Sdelphij        if (*baseptr != '.' && dnsptr[-1] != '.')
382296341Sdelphij            return X509_V_ERR_PERMITTED_VIOLATION;
383296341Sdelphij    }
384238405Sjkim
385296341Sdelphij    if (strcasecmp(baseptr, dnsptr))
386296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
387238405Sjkim
388296341Sdelphij    return X509_V_OK;
389238405Sjkim
390296341Sdelphij}
391238405Sjkim
392238405Sjkimstatic int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
393296341Sdelphij{
394296341Sdelphij    const char *baseptr = (char *)base->data;
395296341Sdelphij    const char *emlptr = (char *)eml->data;
396238405Sjkim
397296341Sdelphij    const char *baseat = strchr(baseptr, '@');
398296341Sdelphij    const char *emlat = strchr(emlptr, '@');
399296341Sdelphij    if (!emlat)
400296341Sdelphij        return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
401296341Sdelphij    /* Special case: inital '.' is RHS match */
402296341Sdelphij    if (!baseat && (*baseptr == '.')) {
403296341Sdelphij        if (eml->length > base->length) {
404296341Sdelphij            emlptr += eml->length - base->length;
405296341Sdelphij            if (!strcasecmp(baseptr, emlptr))
406296341Sdelphij                return X509_V_OK;
407296341Sdelphij        }
408296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
409296341Sdelphij    }
410238405Sjkim
411296341Sdelphij    /* If we have anything before '@' match local part */
412238405Sjkim
413296341Sdelphij    if (baseat) {
414296341Sdelphij        if (baseat != baseptr) {
415296341Sdelphij            if ((baseat - baseptr) != (emlat - emlptr))
416296341Sdelphij                return X509_V_ERR_PERMITTED_VIOLATION;
417296341Sdelphij            /* Case sensitive match of local part */
418296341Sdelphij            if (strncmp(baseptr, emlptr, emlat - emlptr))
419296341Sdelphij                return X509_V_ERR_PERMITTED_VIOLATION;
420296341Sdelphij        }
421296341Sdelphij        /* Position base after '@' */
422296341Sdelphij        baseptr = baseat + 1;
423296341Sdelphij    }
424296341Sdelphij    emlptr = emlat + 1;
425296341Sdelphij    /* Just have hostname left to match: case insensitive */
426296341Sdelphij    if (strcasecmp(baseptr, emlptr))
427296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
428238405Sjkim
429296341Sdelphij    return X509_V_OK;
430238405Sjkim
431296341Sdelphij}
432238405Sjkim
433238405Sjkimstatic int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
434296341Sdelphij{
435296341Sdelphij    const char *baseptr = (char *)base->data;
436296341Sdelphij    const char *hostptr = (char *)uri->data;
437296341Sdelphij    const char *p = strchr(hostptr, ':');
438296341Sdelphij    int hostlen;
439296341Sdelphij    /* Check for foo:// and skip past it */
440296341Sdelphij    if (!p || (p[1] != '/') || (p[2] != '/'))
441296341Sdelphij        return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
442296341Sdelphij    hostptr = p + 3;
443238405Sjkim
444296341Sdelphij    /* Determine length of hostname part of URI */
445238405Sjkim
446296341Sdelphij    /* Look for a port indicator as end of hostname first */
447238405Sjkim
448296341Sdelphij    p = strchr(hostptr, ':');
449296341Sdelphij    /* Otherwise look for trailing slash */
450296341Sdelphij    if (!p)
451296341Sdelphij        p = strchr(hostptr, '/');
452238405Sjkim
453296341Sdelphij    if (!p)
454296341Sdelphij        hostlen = strlen(hostptr);
455296341Sdelphij    else
456296341Sdelphij        hostlen = p - hostptr;
457238405Sjkim
458296341Sdelphij    if (hostlen == 0)
459296341Sdelphij        return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
460238405Sjkim
461296341Sdelphij    /* Special case: inital '.' is RHS match */
462296341Sdelphij    if (*baseptr == '.') {
463296341Sdelphij        if (hostlen > base->length) {
464296341Sdelphij            p = hostptr + hostlen - base->length;
465296341Sdelphij            if (!strncasecmp(p, baseptr, base->length))
466296341Sdelphij                return X509_V_OK;
467296341Sdelphij        }
468296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
469296341Sdelphij    }
470238405Sjkim
471296341Sdelphij    if ((base->length != (int)hostlen)
472296341Sdelphij        || strncasecmp(hostptr, baseptr, hostlen))
473296341Sdelphij        return X509_V_ERR_PERMITTED_VIOLATION;
474238405Sjkim
475296341Sdelphij    return X509_V_OK;
476238405Sjkim
477296341Sdelphij}
478