-/* v3_purp.c */
/*
- * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
- * 2001.
- */
-/* ====================================================================
- * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+ * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
*
+ * Licensed under the OpenSSL license (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 <stdio.h>
#include "internal/cryptlib.h"
+#include "internal/numbers.h"
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
+#include "internal/x509_int.h"
+#include "internal/tsan_assist.h"
static void x509v3_cache_extensions(X509 *x);
{
int idx;
const X509_PURPOSE *pt;
- if (!(x->ex_flags & EXFLAG_SET)) {
- CRYPTO_w_lock(CRYPTO_LOCK_X509);
- x509v3_cache_extensions(x);
- CRYPTO_w_unlock(CRYPTO_LOCK_X509);
- }
+
+ x509v3_cache_extensions(x);
+
+ /* Return if side-effect only call */
if (id == -1)
return 1;
idx = X509_PURPOSE_get_by_id(id);
return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
}
-int X509_PURPOSE_get_by_sname(char *sname)
+int X509_PURPOSE_get_by_sname(const char *sname)
{
int i;
X509_PURPOSE *xptmp;
{
X509_PURPOSE tmp;
int idx;
+
if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
return purpose - X509_PURPOSE_MIN;
- tmp.purpose = purpose;
- if (!xptable)
+ if (xptable == NULL)
return -1;
+ tmp.purpose = purpose;
idx = sk_X509_PURPOSE_find(xptable, &tmp);
- if (idx == -1)
+ if (idx < 0)
return -1;
return idx + X509_PURPOSE_COUNT;
}
int X509_PURPOSE_add(int id, int trust, int flags,
int (*ck) (const X509_PURPOSE *, const X509 *, int),
- char *name, char *sname, void *arg)
+ const char *name, const char *sname, void *arg)
{
int idx;
X509_PURPOSE *ptmp;
OPENSSL_free(ptmp->sname);
}
/* dup supplied name */
- ptmp->name = BUF_strdup(name);
- ptmp->sname = BUF_strdup(sname);
+ ptmp->name = OPENSSL_strdup(name);
+ ptmp->sname = OPENSSL_strdup(sname);
if (!ptmp->name || !ptmp->sname) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
- return 0;
+ goto err;
}
/* Keep the dynamic flag of existing entry */
ptmp->flags &= X509_PURPOSE_DYNAMIC;
if (xptable == NULL
&& (xptable = sk_X509_PURPOSE_new(xp_cmp)) == NULL) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
- return 0;
+ goto err;
}
if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
- return 0;
+ goto err;
}
}
return 1;
+ err:
+ if (idx == -1) {
+ OPENSSL_free(ptmp->name);
+ OPENSSL_free(ptmp->sname);
+ OPENSSL_free(ptmp);
+ }
+ return 0;
}
static void xptable_free(X509_PURPOSE *p)
void X509_PURPOSE_cleanup(void)
{
- unsigned int i;
sk_X509_PURPOSE_pop_free(xptable, xptable_free);
- for (i = 0; i < X509_PURPOSE_COUNT; i++)
- xptable_free(xstandard + i);
xptable = NULL;
}
-int X509_PURPOSE_get_id(X509_PURPOSE *xp)
+int X509_PURPOSE_get_id(const X509_PURPOSE *xp)
{
return xp->purpose;
}
-char *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
+char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp)
{
return xp->name;
}
-char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
+char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp)
{
return xp->sname;
}
-int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
+int X509_PURPOSE_get_trust(const X509_PURPOSE *xp)
{
return xp->trust;
}
NID_subject_alt_name, /* 85 */
NID_basic_constraints, /* 87 */
NID_certificate_policies, /* 89 */
+ NID_crl_distribution_points, /* 103 */
NID_ext_key_usage, /* 126 */
+#ifndef OPENSSL_NO_RFC3779
NID_sbgp_ipAddrBlock, /* 290 */
NID_sbgp_autonomousSysNum, /* 291 */
+#endif
NID_policy_constraints, /* 401 */
NID_proxyCertInfo, /* 663 */
NID_name_constraints, /* 666 */
setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
}
+#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
+#define ku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+#define xku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
+#define ns_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
+
static void x509v3_cache_extensions(X509 *x)
{
BASIC_CONSTRAINTS *bs;
ASN1_BIT_STRING *ns;
EXTENDED_KEY_USAGE *extusage;
X509_EXTENSION *ex;
-
int i;
- if (x->ex_flags & EXFLAG_SET)
+
+ /* fast lock-free check, see end of the function for details. */
+ if (tsan_load((TSAN_QUALIFIER int *)&x->ex_cached))
+ return;
+
+ CRYPTO_THREAD_write_lock(x->lock);
+ if (x->ex_flags & EXFLAG_SET) {
+ CRYPTO_THREAD_unlock(x->lock);
return;
+ }
+
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
/* V1 should mean no extensions ... */
if (!X509_get_version(x))
if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
x->ex_flags |= EXFLAG_SI;
/* If SKID matches AKID also indicate self signed */
- if (X509_check_akid(x, x->akid) == X509_V_OK)
+ if (X509_check_akid(x, x->akid) == X509_V_OK &&
+ !ku_reject(x, KU_KEY_CERT_SIGN))
x->ex_flags |= EXFLAG_SS;
}
x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
x->ex_flags |= EXFLAG_INVALID;
setup_crldp(x);
+#ifndef OPENSSL_NO_RFC3779
x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
NULL, NULL);
+#endif
for (i = 0; i < X509_get_ext_count(x); i++) {
ex = X509_get_ext(x, i);
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
break;
}
}
+ x509_init_sig_info(x);
x->ex_flags |= EXFLAG_SET;
+ CRYPTO_THREAD_unlock(x->lock);
+ /*
+ * It has to be placed after memory barrier, which is implied by unlock.
+ * Worst thing that can happen is that another thread proceeds to lock
+ * and checks x->ex_flags & EXFLAGS_SET. See beginning of the function.
+ */
+ tsan_store((TSAN_QUALIFIER int *)&x->ex_cached, 1);
}
/*-
* 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
*/
-#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
-#define ku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
-#define xku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
-#define ns_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
-
static int check_ca(const X509 *x)
{
/* keyUsage if present should allow cert signing */
}
}
+void X509_set_proxy_flag(X509 *x)
+{
+ x->ex_flags |= EXFLAG_PROXY;
+}
+
+void X509_set_proxy_pathlen(X509 *x, long l)
+{
+ x->ex_pcpathlen = l;
+}
+
int X509_check_ca(X509 *x)
{
- if (!(x->ex_flags & EXFLAG_SET)) {
- CRYPTO_w_lock(CRYPTO_LOCK_X509);
- x509v3_cache_extensions(x);
- CRYPTO_w_unlock(CRYPTO_LOCK_X509);
- }
+ x509v3_cache_extensions(x);
return check_ca(x);
}
return 0;
/* Extended Key Usage MUST be critical */
- i_ext = X509_get_ext_by_NID((X509 *)x, NID_ext_key_usage, -1);
+ i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
if (i_ext >= 0) {
X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext);
if (!X509_EXTENSION_get_critical(ext))
if (X509_NAME_cmp(X509_get_subject_name(issuer),
X509_get_issuer_name(subject)))
return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+
x509v3_cache_extensions(issuer);
x509v3_cache_extensions(subject);
}
return X509_V_OK;
}
+
+uint32_t X509_get_extension_flags(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, -1);
+ return x->ex_flags;
+}
+
+uint32_t X509_get_key_usage(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, -1);
+ if (x->ex_flags & EXFLAG_KUSAGE)
+ return x->ex_kusage;
+ return UINT32_MAX;
+}
+
+uint32_t X509_get_extended_key_usage(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, -1);
+ if (x->ex_flags & EXFLAG_XKUSAGE)
+ return x->ex_xkusage;
+ return UINT32_MAX;
+}
+
+const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, -1);
+ return x->skid;
+}
+
+const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, -1);
+ return (x->akid != NULL ? x->akid->keyid : NULL);
+}
+
+long X509_get_pathlen(X509 *x)
+{
+ /* Called for side effect of caching extensions */
+ if (X509_check_purpose(x, -1, -1) != 1
+ || (x->ex_flags & EXFLAG_BCONS) == 0)
+ return -1;
+ return x->ex_pathlen;
+}
+
+long X509_get_proxy_pathlen(X509 *x)
+{
+ /* Called for side effect of caching extensions */
+ if (X509_check_purpose(x, -1, -1) != 1
+ || (x->ex_flags & EXFLAG_PROXY) == 0)
+ return -1;
+ return x->ex_pcpathlen;
+}