155714Skris/* v3_lib.c */
2296465Sdelphij/*
3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4296465Sdelphij * 1999.
555714Skris */
655714Skris/* ====================================================================
755714Skris * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
855714Skris *
955714Skris * Redistribution and use in source and binary forms, with or without
1055714Skris * modification, are permitted provided that the following conditions
1155714Skris * are met:
1255714Skris *
1355714Skris * 1. Redistributions of source code must retain the above copyright
14296465Sdelphij *    notice, this list of conditions and the following disclaimer.
1555714Skris *
1655714Skris * 2. Redistributions in binary form must reproduce the above copyright
1755714Skris *    notice, this list of conditions and the following disclaimer in
1855714Skris *    the documentation and/or other materials provided with the
1955714Skris *    distribution.
2055714Skris *
2155714Skris * 3. All advertising materials mentioning features or use of this
2255714Skris *    software must display the following acknowledgment:
2355714Skris *    "This product includes software developed by the OpenSSL Project
2455714Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2555714Skris *
2655714Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2755714Skris *    endorse or promote products derived from this software without
2855714Skris *    prior written permission. For written permission, please contact
2955714Skris *    licensing@OpenSSL.org.
3055714Skris *
3155714Skris * 5. Products derived from this software may not be called "OpenSSL"
3255714Skris *    nor may "OpenSSL" appear in their names without prior written
3355714Skris *    permission of the OpenSSL Project.
3455714Skris *
3555714Skris * 6. Redistributions of any form whatsoever must retain the following
3655714Skris *    acknowledgment:
3755714Skris *    "This product includes software developed by the OpenSSL Project
3855714Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3955714Skris *
4055714Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4155714Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4255714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4355714Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4455714Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4555714Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4655714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4755714Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4955714Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5055714Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5155714Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5255714Skris * ====================================================================
5355714Skris *
5455714Skris * This product includes cryptographic software written by Eric Young
5555714Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5655714Skris * Hudson (tjh@cryptsoft.com).
5755714Skris *
5855714Skris */
5955714Skris/* X509 v3 extension utilities */
6055714Skris
6155714Skris#include <stdio.h>
6255714Skris#include "cryptlib.h"
6355714Skris#include <openssl/conf.h>
6455714Skris#include <openssl/x509v3.h>
6555714Skris
6659191Skris#include "ext_dat.h"
6759191Skris
6868651Skrisstatic STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
6955714Skris
70296465Sdelphijstatic int ext_cmp(const X509V3_EXT_METHOD *const *a,
71296465Sdelphij                   const X509V3_EXT_METHOD *const *b);
7255714Skrisstatic void ext_list_free(X509V3_EXT_METHOD *ext);
7355714Skris
7455714Skrisint X509V3_EXT_add(X509V3_EXT_METHOD *ext)
7555714Skris{
76296465Sdelphij    if (!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp))) {
77296465Sdelphij        X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE);
78296465Sdelphij        return 0;
79296465Sdelphij    }
80296465Sdelphij    if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
81296465Sdelphij        X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE);
82296465Sdelphij        return 0;
83296465Sdelphij    }
84296465Sdelphij    return 1;
8555714Skris}
8655714Skris
87296465Sdelphijstatic int ext_cmp(const X509V3_EXT_METHOD *const *a,
88296465Sdelphij                   const X509V3_EXT_METHOD *const *b)
8955714Skris{
90296465Sdelphij    return ((*a)->ext_nid - (*b)->ext_nid);
9155714Skris}
9255714Skris
9355714SkrisX509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
9455714Skris{
95296465Sdelphij    X509V3_EXT_METHOD tmp, *t = &tmp, **ret;
96296465Sdelphij    int idx;
97296465Sdelphij    if (nid < 0)
98296465Sdelphij        return NULL;
99296465Sdelphij    tmp.ext_nid = nid;
100296465Sdelphij    ret = (X509V3_EXT_METHOD **)OBJ_bsearch((char *)&t,
101296465Sdelphij                                            (char *)standard_exts,
102296465Sdelphij                                            STANDARD_EXTENSION_COUNT,
103296465Sdelphij                                            sizeof(X509V3_EXT_METHOD *),
104296465Sdelphij                                            (int (*)
105296465Sdelphij                                             (const void *,
106296465Sdelphij                                              const void *))ext_cmp);
107296465Sdelphij    if (ret)
108296465Sdelphij        return *ret;
109296465Sdelphij    if (!ext_list)
110296465Sdelphij        return NULL;
111296465Sdelphij    idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
112296465Sdelphij    if (idx == -1)
113296465Sdelphij        return NULL;
114296465Sdelphij    return sk_X509V3_EXT_METHOD_value(ext_list, idx);
11555714Skris}
11655714Skris
11755714SkrisX509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
11855714Skris{
119296465Sdelphij    int nid;
120296465Sdelphij    if ((nid = OBJ_obj2nid(ext->object)) == NID_undef)
121296465Sdelphij        return NULL;
122296465Sdelphij    return X509V3_EXT_get_nid(nid);
12355714Skris}
12455714Skris
12555714Skrisint X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
12655714Skris{
127296465Sdelphij    for (; extlist->ext_nid != -1; extlist++)
128296465Sdelphij        if (!X509V3_EXT_add(extlist))
129296465Sdelphij            return 0;
130296465Sdelphij    return 1;
13155714Skris}
13255714Skris
13355714Skrisint X509V3_EXT_add_alias(int nid_to, int nid_from)
13455714Skris{
135296465Sdelphij    X509V3_EXT_METHOD *ext, *tmpext;
136296465Sdelphij    if (!(ext = X509V3_EXT_get_nid(nid_from))) {
137296465Sdelphij        X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS,
138296465Sdelphij                  X509V3_R_EXTENSION_NOT_FOUND);
139296465Sdelphij        return 0;
140296465Sdelphij    }
141296465Sdelphij    if (!
142296465Sdelphij        (tmpext =
143296465Sdelphij         (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) {
144296465Sdelphij        X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE);
145296465Sdelphij        return 0;
146296465Sdelphij    }
147296465Sdelphij    *tmpext = *ext;
148296465Sdelphij    tmpext->ext_nid = nid_to;
149296465Sdelphij    tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
150296465Sdelphij    return X509V3_EXT_add(tmpext);
15155714Skris}
15255714Skris
15355714Skrisvoid X509V3_EXT_cleanup(void)
15455714Skris{
155296465Sdelphij    sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
156296465Sdelphij    ext_list = NULL;
15755714Skris}
15855714Skris
15955714Skrisstatic void ext_list_free(X509V3_EXT_METHOD *ext)
16055714Skris{
161296465Sdelphij    if (ext->ext_flags & X509V3_EXT_DYNAMIC)
162296465Sdelphij        OPENSSL_free(ext);
16355714Skris}
16455714Skris
165296465Sdelphij/*
166296465Sdelphij * Legacy function: we don't need to add standard extensions any more because
167296465Sdelphij * they are now kept in ext_dat.h.
16859191Skris */
16955714Skris
17055714Skrisint X509V3_add_standard_extensions(void)
17155714Skris{
172296465Sdelphij    return 1;
17355714Skris}
17455714Skris
17555714Skris/* Return an extension internal structure */
17655714Skris
17755714Skrisvoid *X509V3_EXT_d2i(X509_EXTENSION *ext)
17855714Skris{
179296465Sdelphij    X509V3_EXT_METHOD *method;
180296465Sdelphij    const unsigned char *p;
181160814Ssimon
182296465Sdelphij    if (!(method = X509V3_EXT_get(ext)))
183296465Sdelphij        return NULL;
184296465Sdelphij    p = ext->value->data;
185296465Sdelphij    if (method->it)
186296465Sdelphij        return ASN1_item_d2i(NULL, &p, ext->value->length,
187296465Sdelphij                             ASN1_ITEM_ptr(method->it));
188296465Sdelphij    return method->d2i(NULL, &p, ext->value->length);
18955714Skris}
19055714Skris
191296465Sdelphij/*-
192296465Sdelphij * Get critical flag and decoded version of extension from a NID.
19359191Skris * The "idx" variable returns the last found extension and can
19459191Skris * be used to retrieve multiple extensions of the same NID.
19559191Skris * However multiple extensions with the same NID is usually
19659191Skris * due to a badly encoded certificate so if idx is NULL we
19759191Skris * choke if multiple extensions exist.
19859191Skris * The "crit" variable is set to the critical value.
19959191Skris * The return value is the decoded extension or NULL on
20059191Skris * error. The actual error can have several different causes,
20159191Skris * the value of *crit reflects the cause:
20259191Skris * >= 0, extension found but not decoded (reflects critical value).
20359191Skris * -1 extension not found.
20459191Skris * -2 extension occurs more than once.
20559191Skris */
20659191Skris
207296465Sdelphijvoid *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit,
208296465Sdelphij                     int *idx)
20959191Skris{
210296465Sdelphij    int lastpos, i;
211296465Sdelphij    X509_EXTENSION *ex, *found_ex = NULL;
212296465Sdelphij    if (!x) {
213296465Sdelphij        if (idx)
214296465Sdelphij            *idx = -1;
215296465Sdelphij        if (crit)
216296465Sdelphij            *crit = -1;
217296465Sdelphij        return NULL;
218296465Sdelphij    }
219296465Sdelphij    if (idx)
220296465Sdelphij        lastpos = *idx + 1;
221296465Sdelphij    else
222296465Sdelphij        lastpos = 0;
223296465Sdelphij    if (lastpos < 0)
224296465Sdelphij        lastpos = 0;
225296465Sdelphij    for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) {
226296465Sdelphij        ex = sk_X509_EXTENSION_value(x, i);
227296465Sdelphij        if (OBJ_obj2nid(ex->object) == nid) {
228296465Sdelphij            if (idx) {
229296465Sdelphij                *idx = i;
230296465Sdelphij                found_ex = ex;
231296465Sdelphij                break;
232296465Sdelphij            } else if (found_ex) {
233296465Sdelphij                /* Found more than one */
234296465Sdelphij                if (crit)
235296465Sdelphij                    *crit = -2;
236296465Sdelphij                return NULL;
237296465Sdelphij            }
238296465Sdelphij            found_ex = ex;
239296465Sdelphij        }
240296465Sdelphij    }
241296465Sdelphij    if (found_ex) {
242296465Sdelphij        /* Found it */
243296465Sdelphij        if (crit)
244296465Sdelphij            *crit = X509_EXTENSION_get_critical(found_ex);
245296465Sdelphij        return X509V3_EXT_d2i(found_ex);
246296465Sdelphij    }
24768651Skris
248296465Sdelphij    /* Extension not found */
249296465Sdelphij    if (idx)
250296465Sdelphij        *idx = -1;
251296465Sdelphij    if (crit)
252296465Sdelphij        *crit = -1;
253296465Sdelphij    return NULL;
25459191Skris}
25568651Skris
256296465Sdelphij/*
257296465Sdelphij * This function is a general extension append, replace and delete utility.
258109998Smarkm * The precise operation is governed by the 'flags' value. The 'crit' and
259109998Smarkm * 'value' arguments (if relevant) are the extensions internal structure.
260109998Smarkm */
261109998Smarkm
262109998Smarkmint X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
263296465Sdelphij                    int crit, unsigned long flags)
264109998Smarkm{
265296465Sdelphij    int extidx = -1;
266296465Sdelphij    int errcode;
267296465Sdelphij    X509_EXTENSION *ext, *extmp;
268296465Sdelphij    unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
269109998Smarkm
270296465Sdelphij    /*
271296465Sdelphij     * If appending we don't care if it exists, otherwise look for existing
272296465Sdelphij     * extension.
273296465Sdelphij     */
274296465Sdelphij    if (ext_op != X509V3_ADD_APPEND)
275296465Sdelphij        extidx = X509v3_get_ext_by_NID(*x, nid, -1);
276109998Smarkm
277296465Sdelphij    /* See if extension exists */
278296465Sdelphij    if (extidx >= 0) {
279296465Sdelphij        /* If keep existing, nothing to do */
280296465Sdelphij        if (ext_op == X509V3_ADD_KEEP_EXISTING)
281296465Sdelphij            return 1;
282296465Sdelphij        /* If default then its an error */
283296465Sdelphij        if (ext_op == X509V3_ADD_DEFAULT) {
284296465Sdelphij            errcode = X509V3_R_EXTENSION_EXISTS;
285296465Sdelphij            goto err;
286296465Sdelphij        }
287296465Sdelphij        /* If delete, just delete it */
288296465Sdelphij        if (ext_op == X509V3_ADD_DELETE) {
289296465Sdelphij            if (!sk_X509_EXTENSION_delete(*x, extidx))
290296465Sdelphij                return -1;
291296465Sdelphij            return 1;
292296465Sdelphij        }
293296465Sdelphij    } else {
294296465Sdelphij        /*
295296465Sdelphij         * If replace existing or delete, error since extension must exist
296296465Sdelphij         */
297296465Sdelphij        if ((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
298296465Sdelphij            (ext_op == X509V3_ADD_DELETE)) {
299296465Sdelphij            errcode = X509V3_R_EXTENSION_NOT_FOUND;
300296465Sdelphij            goto err;
301296465Sdelphij        }
302296465Sdelphij    }
303109998Smarkm
304296465Sdelphij    /*
305296465Sdelphij     * If we get this far then we have to create an extension: could have
306296465Sdelphij     * some flags for alternative encoding schemes...
307296465Sdelphij     */
308109998Smarkm
309296465Sdelphij    ext = X509V3_EXT_i2d(nid, crit, value);
310109998Smarkm
311296465Sdelphij    if (!ext) {
312296465Sdelphij        X509V3err(X509V3_F_X509V3_ADD1_I2D,
313296465Sdelphij                  X509V3_R_ERROR_CREATING_EXTENSION);
314296465Sdelphij        return 0;
315296465Sdelphij    }
316109998Smarkm
317296465Sdelphij    /* If extension exists replace it.. */
318296465Sdelphij    if (extidx >= 0) {
319296465Sdelphij        extmp = sk_X509_EXTENSION_value(*x, extidx);
320296465Sdelphij        X509_EXTENSION_free(extmp);
321296465Sdelphij        if (!sk_X509_EXTENSION_set(*x, extidx, ext))
322296465Sdelphij            return -1;
323296465Sdelphij        return 1;
324296465Sdelphij    }
325109998Smarkm
326296465Sdelphij    if (!*x && !(*x = sk_X509_EXTENSION_new_null()))
327296465Sdelphij        return -1;
328296465Sdelphij    if (!sk_X509_EXTENSION_push(*x, ext))
329296465Sdelphij        return -1;
330109998Smarkm
331296465Sdelphij    return 1;
332109998Smarkm
333296465Sdelphij err:
334296465Sdelphij    if (!(flags & X509V3_ADD_SILENT))
335296465Sdelphij        X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode);
336296465Sdelphij    return 0;
337109998Smarkm}
338109998Smarkm
33968651SkrisIMPLEMENT_STACK_OF(X509V3_EXT_METHOD)
340