aboutsummaryrefslogtreecommitdiff
path: root/crypto/x509
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/x509')
-rw-r--r--crypto/x509/build.info17
-rw-r--r--crypto/x509/by_dir.c107
-rw-r--r--crypto/x509/by_file.c110
-rw-r--r--crypto/x509/by_store.c298
-rw-r--r--crypto/x509/ext_dat.h27
-rw-r--r--crypto/x509/pcy_cache.c225
-rw-r--r--crypto/x509/pcy_data.c82
-rw-r--r--crypto/x509/pcy_lib.c108
-rw-r--r--crypto/x509/pcy_local.h171
-rw-r--r--crypto/x509/pcy_map.c79
-rw-r--r--crypto/x509/pcy_node.c161
-rw-r--r--crypto/x509/pcy_tree.c723
-rw-r--r--crypto/x509/standard_exts.h80
-rw-r--r--crypto/x509/t_crl.c8
-rw-r--r--crypto/x509/t_req.c30
-rw-r--r--crypto/x509/t_x509.c198
-rw-r--r--crypto/x509/v3_addr.c1361
-rw-r--r--crypto/x509/v3_admis.c353
-rw-r--r--crypto/x509/v3_admis.h38
-rw-r--r--crypto/x509/v3_akeya.c23
-rw-r--r--crypto/x509/v3_akid.c218
-rw-r--r--crypto/x509/v3_asid.c910
-rw-r--r--crypto/x509/v3_bcons.c85
-rw-r--r--crypto/x509/v3_bitst.c91
-rw-r--r--crypto/x509/v3_conf.c584
-rw-r--r--crypto/x509/v3_cpols.c500
-rw-r--r--crypto/x509/v3_crld.c513
-rw-r--r--crypto/x509/v3_enum.c53
-rw-r--r--crypto/x509/v3_extku.c102
-rw-r--r--crypto/x509/v3_genn.c241
-rw-r--r--crypto/x509/v3_ia5.c64
-rw-r--r--crypto/x509/v3_info.c156
-rw-r--r--crypto/x509/v3_int.c43
-rw-r--r--crypto/x509/v3_ist.c152
-rw-r--r--crypto/x509/v3_lib.c308
-rw-r--r--crypto/x509/v3_ncons.c834
-rw-r--r--crypto/x509/v3_pci.c321
-rw-r--r--crypto/x509/v3_pcia.c64
-rw-r--r--crypto/x509/v3_pcons.c91
-rw-r--r--crypto/x509/v3_pku.c52
-rw-r--r--crypto/x509/v3_pmaps.c110
-rw-r--r--crypto/x509/v3_prn.c216
-rw-r--r--crypto/x509/v3_purp.c1066
-rw-r--r--crypto/x509/v3_san.c699
-rw-r--r--crypto/x509/v3_skid.c111
-rw-r--r--crypto/x509/v3_sxnet.c252
-rw-r--r--crypto/x509/v3_tlsf.c140
-rw-r--r--crypto/x509/v3_utf8.c68
-rw-r--r--crypto/x509/v3_utl.c1386
-rw-r--r--crypto/x509/v3err.c147
-rw-r--r--crypto/x509/x509_att.c135
-rw-r--r--crypto/x509/x509_cmp.c251
-rw-r--r--crypto/x509/x509_d2.c96
-rw-r--r--crypto/x509/x509_def.c2
-rw-r--r--crypto/x509/x509_err.c120
-rw-r--r--crypto/x509/x509_ext.c2
-rw-r--r--crypto/x509/x509_local.h34
-rw-r--r--crypto/x509/x509_lu.c287
-rw-r--r--crypto/x509/x509_meth.c8
-rw-r--r--crypto/x509/x509_obj.c36
-rw-r--r--crypto/x509/x509_r2x.c8
-rw-r--r--crypto/x509/x509_req.c73
-rw-r--r--crypto/x509/x509_set.c99
-rw-r--r--crypto/x509/x509_trust.c (renamed from crypto/x509/x509_trs.c)30
-rw-r--r--crypto/x509/x509_txt.c71
-rw-r--r--crypto/x509/x509_v3.c18
-rw-r--r--crypto/x509/x509_vfy.c1645
-rw-r--r--crypto/x509/x509_vpm.c152
-rw-r--r--crypto/x509/x509cset.c12
-rw-r--r--crypto/x509/x509name.c37
-rw-r--r--crypto/x509/x509rset.c6
-rw-r--r--crypto/x509/x509spki.c13
-rw-r--r--crypto/x509/x509type.c6
-rw-r--r--crypto/x509/x_all.c432
-rw-r--r--crypto/x509/x_attrib.c4
-rw-r--r--crypto/x509/x_crl.c73
-rw-r--r--crypto/x509/x_exten.c2
-rw-r--r--crypto/x509/x_name.c66
-rw-r--r--crypto/x509/x_pubkey.c930
-rw-r--r--crypto/x509/x_req.c111
-rw-r--r--crypto/x509/x_x509.c93
-rw-r--r--crypto/x509/x_x509a.c15
82 files changed, 16883 insertions, 1760 deletions
diff --git a/crypto/x509/build.info b/crypto/x509/build.info
index afd0b6134e52..8820f983bb3d 100644
--- a/crypto/x509/build.info
+++ b/crypto/x509/build.info
@@ -4,7 +4,18 @@ SOURCE[../../libcrypto]=\
x509_obj.c x509_req.c x509spki.c x509_vfy.c \
x509_set.c x509cset.c x509rset.c x509_err.c \
x509name.c x509_v3.c x509_ext.c x509_att.c \
- x509type.c x509_meth.c x509_lu.c x_all.c x509_txt.c \
- x509_trs.c by_file.c by_dir.c x509_vpm.c \
+ x509_meth.c x509_lu.c x_all.c x509_txt.c \
+ x509_trust.c by_file.c by_dir.c by_store.c x509_vpm.c \
x_crl.c t_crl.c x_req.c t_req.c x_x509.c t_x509.c \
- x_pubkey.c x_x509a.c x_attrib.c x_exten.c x_name.c
+ x_pubkey.c x_x509a.c x_attrib.c x_exten.c x_name.c \
+ v3_bcons.c v3_bitst.c v3_conf.c v3_extku.c v3_ia5.c v3_utf8.c v3_lib.c \
+ v3_prn.c v3_utl.c v3err.c v3_genn.c v3_san.c v3_skid.c v3_akid.c \
+ v3_pku.c v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c \
+ v3_info.c v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c \
+ v3_pcia.c v3_pci.c v3_ist.c \
+ pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
+ v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c
+
+IF[{- !$disabled{'deprecated-3.0'} -}]
+ SOURCE[../../libcrypto]=x509type.c
+ENDIF
diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c
index 46a861e90de0..ad871966aa6e 100644
--- a/crypto/x509/by_dir.c
+++ b/crypto/x509/by_dir.c
@@ -1,12 +1,21 @@
/*
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
*/
+#if defined (__TANDEM) && defined (_SPT_MODEL_)
+ /*
+ * These definitions have to come first in SPT due to scoping of the
+ * declarations in c99 associated with SPT use of stat.
+ */
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+
#include "e_os.h"
#include "internal/cryptlib.h"
#include <stdio.h>
@@ -40,23 +49,29 @@ typedef struct lookup_dir_st {
} BY_DIR;
static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
- char **ret);
+ char **retp);
+
static int new_dir(X509_LOOKUP *lu);
static void free_dir(X509_LOOKUP *lu);
static int add_cert_dir(BY_DIR *ctx, const char *dir, int type);
static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
- X509_NAME *name, X509_OBJECT *ret);
+ const X509_NAME *name, X509_OBJECT *ret);
+static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret,
+ OSSL_LIB_CTX *libctx, const char *propq);
static X509_LOOKUP_METHOD x509_dir_lookup = {
"Load certs from files in a directory",
- new_dir, /* new_item */
- free_dir, /* free */
- NULL, /* init */
- NULL, /* shutdown */
- dir_ctrl, /* ctrl */
- get_cert_by_subject, /* get_by_subject */
- NULL, /* get_by_issuer_serial */
- NULL, /* get_by_fingerprint */
- NULL, /* get_by_alias */
+ new_dir, /* new_item */
+ free_dir, /* free */
+ NULL, /* init */
+ NULL, /* shutdown */
+ dir_ctrl, /* ctrl */
+ get_cert_by_subject, /* get_by_subject */
+ NULL, /* get_by_issuer_serial */
+ NULL, /* get_by_fingerprint */
+ NULL, /* get_by_alias */
+ get_cert_by_subject_ex, /* get_by_subject_ex */
+ NULL, /* ctrl_ex */
};
X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void)
@@ -81,7 +96,7 @@ static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
ret = add_cert_dir(ld, X509_get_default_cert_dir(),
X509_FILETYPE_PEM);
if (!ret) {
- X509err(X509_F_DIR_CTRL, X509_R_LOADING_CERT_DIR);
+ ERR_raise(ERR_LIB_X509, X509_R_LOADING_CERT_DIR);
}
} else
ret = add_cert_dir(ld, argp, (int)argl);
@@ -95,19 +110,19 @@ static int new_dir(X509_LOOKUP *lu)
BY_DIR *a = OPENSSL_malloc(sizeof(*a));
if (a == NULL) {
- X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
if ((a->buffer = BUF_MEM_new()) == NULL) {
- X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
a->dirs = NULL;
a->lock = CRYPTO_THREAD_lock_new();
if (a->lock == NULL) {
BUF_MEM_free(a->buffer);
- X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
lu->method_data = a;
@@ -156,8 +171,8 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
size_t len;
const char *s, *ss, *p;
- if (dir == NULL || !*dir) {
- X509err(X509_F_ADD_CERT_DIR, X509_R_INVALID_DIRECTORY);
+ if (dir == NULL || *dir == '\0') {
+ ERR_raise(ERR_LIB_X509, X509_R_INVALID_DIRECTORY);
return 0;
}
@@ -182,13 +197,13 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
if (ctx->dirs == NULL) {
ctx->dirs = sk_BY_DIR_ENTRY_new_null();
if (!ctx->dirs) {
- X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
}
ent = OPENSSL_malloc(sizeof(*ent));
if (ent == NULL) {
- X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
ent->dir_type = type;
@@ -200,7 +215,7 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
}
if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
by_dir_entry_free(ent);
- X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
}
@@ -208,8 +223,9 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
return 1;
}
-static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
- X509_NAME *name, X509_OBJECT *ret)
+static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret,
+ OSSL_LIB_CTX *libctx, const char *propq)
{
BY_DIR *ctx;
union {
@@ -228,26 +244,26 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
stmp.type = type;
if (type == X509_LU_X509) {
- data.st_x509.cert_info.subject = name;
+ data.st_x509.cert_info.subject = (X509_NAME *)name; /* won't modify it */
stmp.data.x509 = &data.st_x509;
- postfix = "";
} else if (type == X509_LU_CRL) {
- data.crl.crl.issuer = name;
+ data.crl.crl.issuer = (X509_NAME *)name; /* won't modify it */
stmp.data.crl = &data.crl;
postfix = "r";
} else {
- X509err(X509_F_GET_CERT_BY_SUBJECT, X509_R_WRONG_LOOKUP_TYPE);
+ ERR_raise(ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE);
goto finish;
}
if ((b = BUF_MEM_new()) == NULL) {
- X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
goto finish;
}
ctx = (BY_DIR *)xl->method_data;
-
- h = X509_NAME_hash(name);
+ h = X509_NAME_hash_ex(name, libctx, propq, &i);
+ if (i == 0)
+ goto finish;
for (i = 0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) {
BY_DIR_ENTRY *ent;
int idx;
@@ -256,12 +272,13 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
j = strlen(ent->dir) + 1 + 8 + 6 + 1 + 1;
if (!BUF_MEM_grow(b, j)) {
- X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto finish;
}
if (type == X509_LU_CRL && ent->hashes) {
htmp.hash = h;
- CRYPTO_THREAD_read_lock(ctx->lock);
+ if (!CRYPTO_THREAD_read_lock(ctx->lock))
+ goto finish;
idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
if (idx >= 0) {
hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
@@ -277,6 +294,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
}
for (;;) {
char c = '/';
+
#ifdef OPENSSL_SYS_VMS
c = ent->dir[strlen(ent->dir) - 1];
if (c != ':' && c != '>' && c != ']') {
@@ -290,7 +308,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
} else {
c = '\0';
}
-#endif
+
if (c == '\0') {
/*
* This is special. When c == '\0', no directory separator
@@ -298,7 +316,9 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
*/
BIO_snprintf(b->data, b->max,
"%s%08lx.%s%d", ent->dir, h, postfix, k);
- } else {
+ } else
+#endif
+ {
BIO_snprintf(b->data, b->max,
"%s%c%08lx.%s%d", ent->dir, c, h, postfix, k);
}
@@ -314,7 +334,8 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
#endif
/* found one. */
if (type == X509_LU_X509) {
- if ((X509_load_cert_file(xl, b->data, ent->dir_type)) == 0)
+ if ((X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx,
+ propq)) == 0)
break;
} else if (type == X509_LU_CRL) {
if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0)
@@ -327,7 +348,8 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
/*
* we have added it to the cache so now pull it out again
*/
- X509_STORE_lock(xl->store_ctx);
+ if (!X509_STORE_lock(xl->store_ctx))
+ goto finish;
j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp);
tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j);
X509_STORE_unlock(xl->store_ctx);
@@ -339,7 +361,8 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
* simple case where no CRL is present for a hash.
*/
if (type == X509_LU_CRL && k > 0) {
- CRYPTO_THREAD_write_lock(ctx->lock);
+ if (!CRYPTO_THREAD_write_lock(ctx->lock))
+ goto finish;
/*
* Look for entry again in case another thread added an entry
* first.
@@ -353,7 +376,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
hent = OPENSSL_malloc(sizeof(*hent));
if (hent == NULL) {
CRYPTO_THREAD_unlock(ctx->lock);
- X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
ok = 0;
goto finish;
}
@@ -362,7 +385,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
CRYPTO_THREAD_unlock(ctx->lock);
OPENSSL_free(hent);
- X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
ok = 0;
goto finish;
}
@@ -398,3 +421,9 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
BUF_MEM_free(b);
return ok;
}
+
+static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret)
+{
+ return get_cert_by_subject_ex(xl, type, name, ret, NULL, NULL);
+}
diff --git a/crypto/x509/by_file.c b/crypto/x509/by_file.c
index 237b362e2746..37d73ca84c54 100644
--- a/crypto/x509/by_file.c
+++ b/crypto/x509/by_file.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -19,6 +19,11 @@
static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
long argl, char **ret);
+static int by_file_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argc,
+ long argl, char **ret, OSSL_LIB_CTX *libctx,
+ const char *propq);
+
+
static X509_LOOKUP_METHOD x509_file_lookup = {
"Load file into cache",
NULL, /* new_item */
@@ -30,6 +35,8 @@ static X509_LOOKUP_METHOD x509_file_lookup = {
NULL, /* get_by_issuer_serial */
NULL, /* get_by_fingerprint */
NULL, /* get_by_alias */
+ NULL, /* get_by_subject_ex */
+ by_file_ctrl_ex, /* ctrl_ex */
};
X509_LOOKUP_METHOD *X509_LOOKUP_file(void)
@@ -37,8 +44,9 @@ X509_LOOKUP_METHOD *X509_LOOKUP_file(void)
return &x509_file_lookup;
}
-static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp,
- long argl, char **ret)
+static int by_file_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argp,
+ long argl, char **ret, OSSL_LIB_CTX *libctx,
+ const char *propq)
{
int ok = 0;
const char *file;
@@ -48,30 +56,38 @@ static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp,
if (argl == X509_FILETYPE_DEFAULT) {
file = ossl_safe_getenv(X509_get_default_cert_file_env());
if (file)
- ok = (X509_load_cert_crl_file(ctx, file,
- X509_FILETYPE_PEM) != 0);
+ ok = (X509_load_cert_crl_file_ex(ctx, file, X509_FILETYPE_PEM,
+ libctx, propq) != 0);
else
- ok = (X509_load_cert_crl_file
- (ctx, X509_get_default_cert_file(),
- X509_FILETYPE_PEM) != 0);
+ ok = (X509_load_cert_crl_file_ex(
+ ctx, X509_get_default_cert_file(),
+ X509_FILETYPE_PEM, libctx, propq) != 0);
if (!ok) {
- X509err(X509_F_BY_FILE_CTRL, X509_R_LOADING_DEFAULTS);
+ ERR_raise(ERR_LIB_X509, X509_R_LOADING_DEFAULTS);
}
} else {
if (argl == X509_FILETYPE_PEM)
- ok = (X509_load_cert_crl_file(ctx, argp,
- X509_FILETYPE_PEM) != 0);
+ ok = (X509_load_cert_crl_file_ex(ctx, argp, X509_FILETYPE_PEM,
+ libctx, propq) != 0);
else
- ok = (X509_load_cert_file(ctx, argp, (int)argl) != 0);
+ ok = (X509_load_cert_file_ex(ctx, argp, (int)argl, libctx,
+ propq) != 0);
}
break;
}
return ok;
}
-int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
+static int by_file_ctrl(X509_LOOKUP *ctx, int cmd,
+ const char *argp, long argl, char **ret)
+{
+ return by_file_ctrl_ex(ctx, cmd, argp, argl, ret, NULL, NULL);
+}
+
+int X509_load_cert_file_ex(X509_LOOKUP *ctx, const char *file, int type,
+ OSSL_LIB_CTX *libctx, const char *propq)
{
int ret = 0;
BIO *in = NULL;
@@ -81,23 +97,34 @@ int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
in = BIO_new(BIO_s_file());
if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) {
- X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_SYS_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ if (type != X509_FILETYPE_PEM && type != X509_FILETYPE_ASN1) {
+ ERR_raise(ERR_LIB_X509, X509_R_BAD_X509_FILETYPE);
+ goto err;
+ }
+ x = X509_new_ex(libctx, propq);
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if (type == X509_FILETYPE_PEM) {
for (;;) {
- x = PEM_read_bio_X509_AUX(in, NULL, NULL, "");
- if (x == NULL) {
+ ERR_set_mark();
+ if (PEM_read_bio_X509_AUX(in, &x, NULL, "") == NULL) {
if ((ERR_GET_REASON(ERR_peek_last_error()) ==
PEM_R_NO_START_LINE) && (count > 0)) {
- ERR_clear_error();
+ ERR_pop_to_mark();
break;
} else {
- X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_PEM_LIB);
+ ERR_clear_last_mark();
goto err;
}
}
+ ERR_clear_last_mark();
i = X509_STORE_add_cert(ctx->store_ctx, x);
if (!i)
goto err;
@@ -107,27 +134,28 @@ int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
}
ret = count;
} else if (type == X509_FILETYPE_ASN1) {
- x = d2i_X509_bio(in, NULL);
- if (x == NULL) {
- X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_ASN1_LIB);
+ if (d2i_X509_bio(in, &x) == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
goto err;
}
i = X509_STORE_add_cert(ctx->store_ctx, x);
if (!i)
goto err;
ret = i;
- } else {
- X509err(X509_F_X509_LOAD_CERT_FILE, X509_R_BAD_X509_FILETYPE);
- goto err;
}
if (ret == 0)
- X509err(X509_F_X509_LOAD_CERT_FILE, X509_R_NO_CERTIFICATE_FOUND);
+ ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND);
err:
X509_free(x);
BIO_free(in);
return ret;
}
+int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
+{
+ return X509_load_cert_file_ex(ctx, file, type, NULL, NULL);
+}
+
int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
{
int ret = 0;
@@ -138,7 +166,7 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
in = BIO_new(BIO_s_file());
if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) {
- X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_SYS_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_SYS_LIB);
goto err;
}
@@ -151,7 +179,7 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
ERR_clear_error();
break;
} else {
- X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_PEM_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB);
goto err;
}
}
@@ -166,7 +194,7 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
} else if (type == X509_FILETYPE_ASN1) {
x = d2i_X509_CRL_bio(in, NULL);
if (x == NULL) {
- X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_ASN1_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
goto err;
}
i = X509_STORE_add_crl(ctx->store_ctx, x);
@@ -174,18 +202,19 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
goto err;
ret = i;
} else {
- X509err(X509_F_X509_LOAD_CRL_FILE, X509_R_BAD_X509_FILETYPE);
+ ERR_raise(ERR_LIB_X509, X509_R_BAD_X509_FILETYPE);
goto err;
}
if (ret == 0)
- X509err(X509_F_X509_LOAD_CRL_FILE, X509_R_NO_CRL_FOUND);
+ ERR_raise(ERR_LIB_X509, X509_R_NO_CRL_FOUND);
err:
X509_CRL_free(x);
BIO_free(in);
return ret;
}
-int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
+int X509_load_cert_crl_file_ex(X509_LOOKUP *ctx, const char *file, int type,
+ OSSL_LIB_CTX *libctx, const char *propq)
{
STACK_OF(X509_INFO) *inf;
X509_INFO *itmp;
@@ -193,16 +222,16 @@ int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
int i, count = 0;
if (type != X509_FILETYPE_PEM)
- return X509_load_cert_file(ctx, file, type);
+ return X509_load_cert_file_ex(ctx, file, type, libctx, propq);
in = BIO_new_file(file, "r");
if (!in) {
- X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_SYS_LIB);
return 0;
}
- inf = PEM_X509_INFO_read_bio(in, NULL, NULL, "");
+ inf = PEM_X509_INFO_read_bio_ex(in, NULL, NULL, "", libctx, propq);
BIO_free(in);
if (!inf) {
- X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_PEM_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB);
return 0;
}
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
@@ -219,9 +248,14 @@ int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
}
}
if (count == 0)
- X509err(X509_F_X509_LOAD_CERT_CRL_FILE,
- X509_R_NO_CERTIFICATE_OR_CRL_FOUND);
+ ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND);
err:
sk_X509_INFO_pop_free(inf, X509_INFO_free);
return count;
}
+
+int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
+{
+ return X509_load_cert_crl_file_ex(ctx, file, type, NULL, NULL);
+}
+
diff --git a/crypto/x509/by_store.c b/crypto/x509/by_store.c
new file mode 100644
index 000000000000..e486fb0a9d94
--- /dev/null
+++ b/crypto/x509/by_store.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2018-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 <openssl/safestack.h>
+#include <openssl/store.h>
+#include "internal/cryptlib.h"
+#include "crypto/x509.h"
+#include "x509_local.h"
+
+typedef struct cached_store_st {
+ char *uri;
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ OSSL_STORE_CTX *ctx;
+} CACHED_STORE;
+
+DEFINE_STACK_OF(CACHED_STORE)
+
+/* Generic object loader, given expected type and criterion */
+static int cache_objects(X509_LOOKUP *lctx, CACHED_STORE *store,
+ const OSSL_STORE_SEARCH *criterion, int depth)
+{
+ int ok = 0;
+ OSSL_STORE_CTX *ctx = store->ctx;
+ X509_STORE *xstore = X509_LOOKUP_get_store(lctx);
+
+ if (ctx == NULL
+ && (ctx = OSSL_STORE_open_ex(store->uri, store->libctx, store->propq,
+ NULL, NULL, NULL, NULL, NULL)) == NULL)
+ return 0;
+ store->ctx = ctx;
+
+ /*
+ * We try to set the criterion, but don't care if it was valid or not.
+ * For a OSSL_STORE, it merely serves as an optimization, the expectation
+ * being that if the criterion couldn't be used, we will get *everything*
+ * from the container that the URI represents rather than the subset that
+ * the criterion indicates, so the biggest harm is that we cache more
+ * objects certs and CRLs than we may expect, but that's ok.
+ *
+ * Specifically for OpenSSL's own file: scheme, the only workable
+ * criterion is the BY_NAME one, which it can only apply on directories,
+ * but it's possible that the URI is a single file rather than a directory,
+ * and in that case, the BY_NAME criterion is pointless.
+ *
+ * We could very simply not apply any criterion at all here, and just let
+ * the code that selects certs and CRLs from the cached objects do its job,
+ * but it's a nice optimization when it can be applied (such as on an
+ * actual directory with a thousand CA certs).
+ */
+ if (criterion != NULL)
+ OSSL_STORE_find(ctx, criterion);
+
+ for (;;) {
+ OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
+ int infotype;
+
+ /* NULL means error or "end of file". Either way, we break. */
+ if (info == NULL)
+ break;
+
+ infotype = OSSL_STORE_INFO_get_type(info);
+ ok = 0;
+
+ if (infotype == OSSL_STORE_INFO_NAME) {
+ /*
+ * This is an entry in the "directory" represented by the current
+ * uri. if |depth| allows, dive into it.
+ */
+ if (depth > 0) {
+ CACHED_STORE substore;
+
+ substore.uri = (char *)OSSL_STORE_INFO_get0_NAME(info);
+ substore.libctx = store->libctx;
+ substore.propq = store->propq;
+ substore.ctx = NULL;
+ ok = cache_objects(lctx, &substore, criterion, depth - 1);
+ }
+ } else {
+ /*
+ * We know that X509_STORE_add_{cert|crl} increments the object's
+ * refcount, so we can safely use OSSL_STORE_INFO_get0_{cert,crl}
+ * to get them.
+ */
+ switch (infotype) {
+ case OSSL_STORE_INFO_CERT:
+ ok = X509_STORE_add_cert(xstore,
+ OSSL_STORE_INFO_get0_CERT(info));
+ break;
+ case OSSL_STORE_INFO_CRL:
+ ok = X509_STORE_add_crl(xstore,
+ OSSL_STORE_INFO_get0_CRL(info));
+ break;
+ }
+ }
+
+ OSSL_STORE_INFO_free(info);
+ if (!ok)
+ break;
+ }
+ OSSL_STORE_close(ctx);
+ store->ctx = NULL;
+
+ return ok;
+}
+
+
+static void free_store(CACHED_STORE *store)
+{
+ if (store != NULL) {
+ OSSL_STORE_close(store->ctx);
+ OPENSSL_free(store->uri);
+ OPENSSL_free(store->propq);
+ OPENSSL_free(store);
+ }
+}
+
+static void by_store_free(X509_LOOKUP *ctx)
+{
+ STACK_OF(CACHED_STORE) *stores = X509_LOOKUP_get_method_data(ctx);
+ sk_CACHED_STORE_pop_free(stores, free_store);
+}
+
+static int by_store_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argp,
+ long argl, char **retp, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ /*
+ * In some cases below, failing to use the defaults shouldn't result in
+ * an error. |use_default| is used as the return code in those cases.
+ */
+ int use_default = argp == NULL;
+
+ switch (cmd) {
+ case X509_L_ADD_STORE:
+ /* If no URI is given, use the default cert dir as default URI */
+ if (argp == NULL)
+ argp = ossl_safe_getenv(X509_get_default_cert_dir_env());
+ if (argp == NULL)
+ argp = X509_get_default_cert_dir();
+
+ {
+ STACK_OF(CACHED_STORE) *stores = X509_LOOKUP_get_method_data(ctx);
+ CACHED_STORE *store = OPENSSL_zalloc(sizeof(*store));
+
+ if (store == NULL) {
+ return 0;
+ }
+
+ store->uri = OPENSSL_strdup(argp);
+ store->libctx = libctx;
+ if (propq != NULL)
+ store->propq = OPENSSL_strdup(propq);
+ store->ctx = OSSL_STORE_open_ex(argp, libctx, propq, NULL, NULL,
+ NULL, NULL, NULL);
+ if (store->ctx == NULL
+ || (propq != NULL && store->propq == NULL)
+ || store->uri == NULL) {
+ free_store(store);
+ return use_default;
+ }
+
+ if (stores == NULL) {
+ stores = sk_CACHED_STORE_new_null();
+ if (stores != NULL)
+ X509_LOOKUP_set_method_data(ctx, stores);
+ }
+ if (stores == NULL || sk_CACHED_STORE_push(stores, store) <= 0) {
+ free_store(store);
+ return 0;
+ }
+ return 1;
+ }
+ case X509_L_LOAD_STORE: {
+ /* This is a shortcut for quick loading of specific containers */
+ CACHED_STORE store;
+
+ store.uri = (char *)argp;
+ store.libctx = libctx;
+ store.propq = (char *)propq;
+ store.ctx = NULL;
+ return cache_objects(ctx, &store, NULL, 0);
+ }
+ default:
+ /* Unsupported command */
+ return 0;
+ }
+
+ return 0;
+}
+
+static int by_store_ctrl(X509_LOOKUP *ctx, int cmd,
+ const char *argp, long argl, char **retp)
+{
+ return by_store_ctrl_ex(ctx, cmd, argp, argl, retp, NULL, NULL);
+}
+
+static int by_store(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
+ const OSSL_STORE_SEARCH *criterion, X509_OBJECT *ret)
+{
+ STACK_OF(CACHED_STORE) *stores = X509_LOOKUP_get_method_data(ctx);
+ int i;
+ int ok = 0;
+
+ for (i = 0; i < sk_CACHED_STORE_num(stores); i++) {
+ ok = cache_objects(ctx, sk_CACHED_STORE_value(stores, i), criterion,
+ 1 /* depth */);
+
+ if (ok)
+ break;
+ }
+ return ok;
+}
+
+static int by_store_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret)
+{
+ OSSL_STORE_SEARCH *criterion =
+ OSSL_STORE_SEARCH_by_name((X509_NAME *)name); /* won't modify it */
+ int ok = by_store(ctx, type, criterion, ret);
+ STACK_OF(X509_OBJECT) *store_objects =
+ X509_STORE_get0_objects(X509_LOOKUP_get_store(ctx));
+ X509_OBJECT *tmp = NULL;
+
+ OSSL_STORE_SEARCH_free(criterion);
+
+ if (ok)
+ tmp = X509_OBJECT_retrieve_by_subject(store_objects, type, name);
+
+ ok = 0;
+ if (tmp != NULL) {
+ /*
+ * This could also be done like this:
+ *
+ * if (tmp != NULL) {
+ * *ret = *tmp;
+ * ok = 1;
+ * }
+ *
+ * However, we want to exercise the documented API to the max, so
+ * we do it the hard way.
+ *
+ * To be noted is that X509_OBJECT_set1_* increment the refcount,
+ * but so does X509_STORE_CTX_get_by_subject upon return of this
+ * function, so we must ensure the refcount is decremented
+ * before we return, or we will get a refcount leak. We cannot do
+ * this with X509_OBJECT_free(), though, as that will free a bit
+ * too much.
+ */
+ switch (type) {
+ case X509_LU_X509:
+ ok = X509_OBJECT_set1_X509(ret, tmp->data.x509);
+ if (ok)
+ X509_free(tmp->data.x509);
+ break;
+ case X509_LU_CRL:
+ ok = X509_OBJECT_set1_X509_CRL(ret, tmp->data.crl);
+ if (ok)
+ X509_CRL_free(tmp->data.crl);
+ break;
+ case X509_LU_NONE:
+ break;
+ }
+ }
+ return ok;
+}
+
+/*
+ * We lack the implementations for get_by_issuer_serial, get_by_fingerprint
+ * and get_by_alias. There's simply not enough support in the X509_LOOKUP
+ * or X509_STORE APIs.
+ */
+
+static X509_LOOKUP_METHOD x509_store_lookup = {
+ "Load certs from STORE URIs",
+ NULL, /* new_item */
+ by_store_free, /* free */
+ NULL, /* init */
+ NULL, /* shutdown */
+ by_store_ctrl, /* ctrl */
+ by_store_subject, /* get_by_subject */
+ NULL, /* get_by_issuer_serial */
+ NULL, /* get_by_fingerprint */
+ NULL, /* get_by_alias */
+ NULL, /* get_by_subject_ex */
+ by_store_ctrl_ex
+};
+
+X509_LOOKUP_METHOD *X509_LOOKUP_store(void)
+{
+ return &x509_store_lookup;
+}
diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h
new file mode 100644
index 000000000000..a0a7f88ccd8a
--- /dev/null
+++ b/crypto/x509/ext_dat.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999-2021 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
+ */
+
+int ossl_v3_name_cmp(const char *name, const char *cmp);
+
+extern const X509V3_EXT_METHOD ossl_v3_bcons, ossl_v3_nscert, ossl_v3_key_usage, ossl_v3_ext_ku;
+extern const X509V3_EXT_METHOD ossl_v3_pkey_usage_period, ossl_v3_sxnet, ossl_v3_info, ossl_v3_sinfo;
+extern const X509V3_EXT_METHOD ossl_v3_ns_ia5_list[8], ossl_v3_alt[3], ossl_v3_skey_id, ossl_v3_akey_id;
+extern const X509V3_EXT_METHOD ossl_v3_crl_num, ossl_v3_crl_reason, ossl_v3_crl_invdate;
+extern const X509V3_EXT_METHOD ossl_v3_delta_crl, ossl_v3_cpols, ossl_v3_crld, ossl_v3_freshest_crl;
+extern const X509V3_EXT_METHOD ossl_v3_ocsp_nonce, ossl_v3_ocsp_accresp, ossl_v3_ocsp_acutoff;
+extern const X509V3_EXT_METHOD ossl_v3_ocsp_crlid, ossl_v3_ocsp_nocheck, ossl_v3_ocsp_serviceloc;
+extern const X509V3_EXT_METHOD ossl_v3_crl_hold, ossl_v3_pci;
+extern const X509V3_EXT_METHOD ossl_v3_policy_mappings, ossl_v3_policy_constraints;
+extern const X509V3_EXT_METHOD ossl_v3_name_constraints, ossl_v3_inhibit_anyp, ossl_v3_idp;
+extern const X509V3_EXT_METHOD ossl_v3_addr, ossl_v3_asid;
+extern const X509V3_EXT_METHOD ossl_v3_ct_scts[3];
+extern const X509V3_EXT_METHOD ossl_v3_tls_feature;
+extern const X509V3_EXT_METHOD ossl_v3_ext_admission;
+extern const X509V3_EXT_METHOD ossl_v3_utf8_list[1];
+extern const X509V3_EXT_METHOD ossl_v3_issuer_sign_tool;
diff --git a/crypto/x509/pcy_cache.c b/crypto/x509/pcy_cache.c
new file mode 100644
index 000000000000..1339f994aee1
--- /dev/null
+++ b/crypto/x509/pcy_cache.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2004-2021 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 <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+
+#include "pcy_local.h"
+
+static int policy_data_cmp(const X509_POLICY_DATA *const *a,
+ const X509_POLICY_DATA *const *b);
+static int policy_cache_set_int(long *out, ASN1_INTEGER *value);
+
+/*
+ * Set cache entry according to CertificatePolicies extension. Note: this
+ * destroys the passed CERTIFICATEPOLICIES structure.
+ */
+
+static int policy_cache_create(X509 *x,
+ CERTIFICATEPOLICIES *policies, int crit)
+{
+ int i, num, ret = 0;
+ X509_POLICY_CACHE *cache = x->policy_cache;
+ X509_POLICY_DATA *data = NULL;
+ POLICYINFO *policy;
+
+ if ((num = sk_POLICYINFO_num(policies)) <= 0)
+ goto bad_policy;
+ cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp);
+ if (cache->data == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto just_cleanup;
+ }
+ for (i = 0; i < num; i++) {
+ policy = sk_POLICYINFO_value(policies, i);
+ data = ossl_policy_data_new(policy, NULL, crit);
+ if (data == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto just_cleanup;
+ }
+ /*
+ * Duplicate policy OIDs are illegal: reject if matches found.
+ */
+ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
+ if (cache->anyPolicy) {
+ ret = -1;
+ goto bad_policy;
+ }
+ cache->anyPolicy = data;
+ } else if (sk_X509_POLICY_DATA_find(cache->data, data) >=0 ) {
+ ret = -1;
+ goto bad_policy;
+ } else if (!sk_X509_POLICY_DATA_push(cache->data, data)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto bad_policy;
+ }
+ data = NULL;
+ }
+ ret = 1;
+
+ bad_policy:
+ if (ret == -1)
+ x->ex_flags |= EXFLAG_INVALID_POLICY;
+ ossl_policy_data_free(data);
+ just_cleanup:
+ sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
+ if (ret <= 0) {
+ sk_X509_POLICY_DATA_pop_free(cache->data, ossl_policy_data_free);
+ cache->data = NULL;
+ }
+ return ret;
+}
+
+static int policy_cache_new(X509 *x)
+{
+ X509_POLICY_CACHE *cache;
+ ASN1_INTEGER *ext_any = NULL;
+ POLICY_CONSTRAINTS *ext_pcons = NULL;
+ CERTIFICATEPOLICIES *ext_cpols = NULL;
+ POLICY_MAPPINGS *ext_pmaps = NULL;
+ int i;
+
+ if (x->policy_cache != NULL)
+ return 1;
+ cache = OPENSSL_malloc(sizeof(*cache));
+ if (cache == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ cache->anyPolicy = NULL;
+ cache->data = NULL;
+ cache->any_skip = -1;
+ cache->explicit_skip = -1;
+ cache->map_skip = -1;
+
+ x->policy_cache = cache;
+
+ /*
+ * Handle requireExplicitPolicy *first*. Need to process this even if we
+ * don't have any policies.
+ */
+ ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL);
+
+ if (!ext_pcons) {
+ if (i != -1)
+ goto bad_cache;
+ } else {
+ if (!ext_pcons->requireExplicitPolicy
+ && !ext_pcons->inhibitPolicyMapping)
+ goto bad_cache;
+ if (!policy_cache_set_int(&cache->explicit_skip,
+ ext_pcons->requireExplicitPolicy))
+ goto bad_cache;
+ if (!policy_cache_set_int(&cache->map_skip,
+ ext_pcons->inhibitPolicyMapping))
+ goto bad_cache;
+ }
+
+ /* Process CertificatePolicies */
+
+ ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL);
+ /*
+ * If no CertificatePolicies extension or problem decoding then there is
+ * no point continuing because the valid policies will be NULL.
+ */
+ if (!ext_cpols) {
+ /* If not absent some problem with extension */
+ if (i != -1)
+ goto bad_cache;
+ return 1;
+ }
+
+ i = policy_cache_create(x, ext_cpols, i);
+
+ /* NB: ext_cpols freed by policy_cache_set_policies */
+
+ if (i <= 0)
+ return i;
+
+ ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL);
+
+ if (!ext_pmaps) {
+ /* If not absent some problem with extension */
+ if (i != -1)
+ goto bad_cache;
+ } else {
+ i = ossl_policy_cache_set_mapping(x, ext_pmaps);
+ if (i <= 0)
+ goto bad_cache;
+ }
+
+ ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL);
+
+ if (!ext_any) {
+ if (i != -1)
+ goto bad_cache;
+ } else if (!policy_cache_set_int(&cache->any_skip, ext_any))
+ goto bad_cache;
+ goto just_cleanup;
+
+ bad_cache:
+ x->ex_flags |= EXFLAG_INVALID_POLICY;
+
+ just_cleanup:
+ POLICY_CONSTRAINTS_free(ext_pcons);
+ ASN1_INTEGER_free(ext_any);
+ return 1;
+
+}
+
+void ossl_policy_cache_free(X509_POLICY_CACHE *cache)
+{
+ if (!cache)
+ return;
+ ossl_policy_data_free(cache->anyPolicy);
+ sk_X509_POLICY_DATA_pop_free(cache->data, ossl_policy_data_free);
+ OPENSSL_free(cache);
+}
+
+const X509_POLICY_CACHE *ossl_policy_cache_set(X509 *x)
+{
+
+ if (x->policy_cache == NULL) {
+ if (!CRYPTO_THREAD_write_lock(x->lock))
+ return NULL;
+ policy_cache_new(x);
+ CRYPTO_THREAD_unlock(x->lock);
+ }
+
+ return x->policy_cache;
+
+}
+
+X509_POLICY_DATA *ossl_policy_cache_find_data(const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id)
+{
+ int idx;
+ X509_POLICY_DATA tmp;
+ tmp.valid_policy = (ASN1_OBJECT *)id;
+ idx = sk_X509_POLICY_DATA_find(cache->data, &tmp);
+ return sk_X509_POLICY_DATA_value(cache->data, idx);
+}
+
+static int policy_data_cmp(const X509_POLICY_DATA *const *a,
+ const X509_POLICY_DATA *const *b)
+{
+ return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy);
+}
+
+static int policy_cache_set_int(long *out, ASN1_INTEGER *value)
+{
+ if (value == NULL)
+ return 1;
+ if (value->type == V_ASN1_NEG_INTEGER)
+ return 0;
+ *out = ASN1_INTEGER_get(value);
+ return 1;
+}
diff --git a/crypto/x509/pcy_data.c b/crypto/x509/pcy_data.c
new file mode 100644
index 000000000000..6fb8f14ba8e8
--- /dev/null
+++ b/crypto/x509/pcy_data.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2004-2021 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 <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_local.h"
+
+/* Policy Node routines */
+
+void ossl_policy_data_free(X509_POLICY_DATA *data)
+{
+ if (data == NULL)
+ return;
+ ASN1_OBJECT_free(data->valid_policy);
+ /* Don't free qualifiers if shared */
+ if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS))
+ sk_POLICYQUALINFO_pop_free(data->qualifier_set, POLICYQUALINFO_free);
+ sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free);
+ OPENSSL_free(data);
+}
+
+/*
+ * Create a data based on an existing policy. If 'id' is NULL use the OID in
+ * the policy, otherwise use 'id'. This behaviour covers the two types of
+ * data in RFC3280: data with from a CertificatePolicies extension and
+ * additional data with just the qualifiers of anyPolicy and ID from another
+ * source.
+ */
+
+X509_POLICY_DATA *ossl_policy_data_new(POLICYINFO *policy,
+ const ASN1_OBJECT *cid, int crit)
+{
+ X509_POLICY_DATA *ret;
+ ASN1_OBJECT *id;
+
+ if (policy == NULL && cid == NULL)
+ return NULL;
+ if (cid) {
+ id = OBJ_dup(cid);
+ if (id == NULL)
+ return NULL;
+ } else
+ id = NULL;
+ ret = OPENSSL_zalloc(sizeof(*ret));
+ if (ret == NULL) {
+ ASN1_OBJECT_free(id);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ ret->expected_policy_set = sk_ASN1_OBJECT_new_null();
+ if (ret->expected_policy_set == NULL) {
+ OPENSSL_free(ret);
+ ASN1_OBJECT_free(id);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if (crit)
+ ret->flags = POLICY_DATA_FLAG_CRITICAL;
+
+ if (id)
+ ret->valid_policy = id;
+ else {
+ ret->valid_policy = policy->policyid;
+ policy->policyid = NULL;
+ }
+
+ if (policy) {
+ ret->qualifier_set = policy->qualifiers;
+ policy->qualifiers = NULL;
+ }
+
+ return ret;
+}
diff --git a/crypto/x509/pcy_lib.c b/crypto/x509/pcy_lib.c
new file mode 100644
index 000000000000..c4740a0a30c5
--- /dev/null
+++ b/crypto/x509/pcy_lib.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2004-2020 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 <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_local.h"
+
+/* accessor functions */
+
+/* X509_POLICY_TREE stuff */
+
+int X509_policy_tree_level_count(const X509_POLICY_TREE *tree)
+{
+ if (!tree)
+ return 0;
+ return tree->nlevel;
+}
+
+X509_POLICY_LEVEL *X509_policy_tree_get0_level(const X509_POLICY_TREE *tree,
+ int i)
+{
+ if (!tree || (i < 0) || (i >= tree->nlevel))
+ return NULL;
+ return tree->levels + i;
+}
+
+STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies(const
+ X509_POLICY_TREE
+ *tree)
+{
+ if (!tree)
+ return NULL;
+ return tree->auth_policies;
+}
+
+STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies(const
+ X509_POLICY_TREE
+ *tree)
+{
+ if (!tree)
+ return NULL;
+ if (tree->flags & POLICY_FLAG_ANY_POLICY)
+ return tree->auth_policies;
+ else
+ return tree->user_policies;
+}
+
+/* X509_POLICY_LEVEL stuff */
+
+int X509_policy_level_node_count(X509_POLICY_LEVEL *level)
+{
+ int n;
+ if (!level)
+ return 0;
+ if (level->anyPolicy)
+ n = 1;
+ else
+ n = 0;
+ if (level->nodes)
+ n += sk_X509_POLICY_NODE_num(level->nodes);
+ return n;
+}
+
+X509_POLICY_NODE *X509_policy_level_get0_node(const X509_POLICY_LEVEL *level, int i)
+{
+ if (!level)
+ return NULL;
+ if (level->anyPolicy) {
+ if (i == 0)
+ return level->anyPolicy;
+ i--;
+ }
+ return sk_X509_POLICY_NODE_value(level->nodes, i);
+}
+
+/* X509_POLICY_NODE stuff */
+
+const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node)
+{
+ if (!node)
+ return NULL;
+ return node->data->valid_policy;
+}
+
+STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers(const
+ X509_POLICY_NODE
+ *node)
+{
+ if (!node)
+ return NULL;
+ return node->data->qualifier_set;
+}
+
+const X509_POLICY_NODE *X509_policy_node_get0_parent(const X509_POLICY_NODE
+ *node)
+{
+ if (!node)
+ return NULL;
+ return node->parent;
+}
diff --git a/crypto/x509/pcy_local.h b/crypto/x509/pcy_local.h
new file mode 100644
index 000000000000..523f3e35feeb
--- /dev/null
+++ b/crypto/x509/pcy_local.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2004-2023 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
+ */
+
+typedef struct X509_POLICY_DATA_st X509_POLICY_DATA;
+
+DEFINE_STACK_OF(X509_POLICY_DATA)
+
+/* Internal structures */
+
+/*
+ * This structure and the field names correspond to the Policy 'node' of
+ * RFC3280. NB this structure contains no pointers to parent or child data:
+ * X509_POLICY_NODE contains that. This means that the main policy data can
+ * be kept static and cached with the certificate.
+ */
+
+struct X509_POLICY_DATA_st {
+ unsigned int flags;
+ /* Policy OID and qualifiers for this data */
+ ASN1_OBJECT *valid_policy;
+ STACK_OF(POLICYQUALINFO) *qualifier_set;
+ STACK_OF(ASN1_OBJECT) *expected_policy_set;
+};
+
+/* X509_POLICY_DATA flags values */
+
+/*
+ * This flag indicates the structure has been mapped using a policy mapping
+ * extension. If policy mapping is not active its references get deleted.
+ */
+
+#define POLICY_DATA_FLAG_MAPPED 0x1
+
+/*
+ * This flag indicates the data doesn't correspond to a policy in Certificate
+ * Policies: it has been mapped to any policy.
+ */
+
+#define POLICY_DATA_FLAG_MAPPED_ANY 0x2
+
+/* AND with flags to see if any mapping has occurred */
+
+#define POLICY_DATA_FLAG_MAP_MASK 0x3
+
+/* qualifiers are shared and shouldn't be freed */
+
+#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4
+
+/* Parent node is an extra node and should be freed */
+
+#define POLICY_DATA_FLAG_EXTRA_NODE 0x8
+
+/* Corresponding CertificatePolicies is critical */
+
+#define POLICY_DATA_FLAG_CRITICAL 0x10
+
+/* This structure is cached with a certificate */
+
+struct X509_POLICY_CACHE_st {
+ /* anyPolicy data or NULL if no anyPolicy */
+ X509_POLICY_DATA *anyPolicy;
+ /* other policy data */
+ STACK_OF(X509_POLICY_DATA) *data;
+ /* If InhibitAnyPolicy present this is its value or -1 if absent. */
+ long any_skip;
+ /*
+ * If policyConstraints and requireExplicitPolicy present this is its
+ * value or -1 if absent.
+ */
+ long explicit_skip;
+ /*
+ * If policyConstraints and policyMapping present this is its value or -1
+ * if absent.
+ */
+ long map_skip;
+};
+
+/*
+ * #define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL
+ */
+
+/* This structure represents the relationship between nodes */
+
+struct X509_POLICY_NODE_st {
+ /* node data this refers to */
+ const X509_POLICY_DATA *data;
+ /* Parent node */
+ X509_POLICY_NODE *parent;
+ /* Number of child nodes */
+ int nchild;
+};
+
+struct X509_POLICY_LEVEL_st {
+ /* Cert for this level */
+ X509 *cert;
+ /* nodes at this level */
+ STACK_OF(X509_POLICY_NODE) *nodes;
+ /* anyPolicy node */
+ X509_POLICY_NODE *anyPolicy;
+ /* Extra data */
+ /*
+ * STACK_OF(X509_POLICY_DATA) *extra_data;
+ */
+ unsigned int flags;
+};
+
+struct X509_POLICY_TREE_st {
+ /* The number of nodes in the tree */
+ size_t node_count;
+ /* The maximum number of nodes in the tree */
+ size_t node_maximum;
+
+ /* This is the tree 'level' data */
+ X509_POLICY_LEVEL *levels;
+ int nlevel;
+ /*
+ * Extra policy data when additional nodes (not from the certificate) are
+ * required.
+ */
+ STACK_OF(X509_POLICY_DATA) *extra_data;
+ /* This is the authority constrained policy set */
+ STACK_OF(X509_POLICY_NODE) *auth_policies;
+ STACK_OF(X509_POLICY_NODE) *user_policies;
+ unsigned int flags;
+};
+
+/* Set if anyPolicy present in user policies */
+#define POLICY_FLAG_ANY_POLICY 0x2
+
+/* Useful macros */
+
+#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL)
+#define node_critical(node) node_data_critical(node->data)
+
+/* Internal functions */
+
+X509_POLICY_DATA *ossl_policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id,
+ int crit);
+void ossl_policy_data_free(X509_POLICY_DATA *data);
+
+X509_POLICY_DATA *ossl_policy_cache_find_data(const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id);
+int ossl_policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps);
+
+STACK_OF(X509_POLICY_NODE) *ossl_policy_node_cmp_new(void);
+
+void ossl_policy_cache_free(X509_POLICY_CACHE *cache);
+
+X509_POLICY_NODE *ossl_policy_level_find_node(const X509_POLICY_LEVEL *level,
+ const X509_POLICY_NODE *parent,
+ const ASN1_OBJECT *id);
+
+X509_POLICY_NODE *ossl_policy_tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk,
+ const ASN1_OBJECT *id);
+
+X509_POLICY_NODE *ossl_policy_level_add_node(X509_POLICY_LEVEL *level,
+ X509_POLICY_DATA *data,
+ X509_POLICY_NODE *parent,
+ X509_POLICY_TREE *tree,
+ int extra_data);
+void ossl_policy_node_free(X509_POLICY_NODE *node);
+int ossl_policy_node_match(const X509_POLICY_LEVEL *lvl,
+ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);
+
+const X509_POLICY_CACHE *ossl_policy_cache_set(X509 *x);
diff --git a/crypto/x509/pcy_map.c b/crypto/x509/pcy_map.c
new file mode 100644
index 000000000000..60dfd1e3203b
--- /dev/null
+++ b/crypto/x509/pcy_map.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2004-2021 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 <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+
+#include "pcy_local.h"
+
+/*
+ * Set policy mapping entries in cache. Note: this modifies the passed
+ * POLICY_MAPPINGS structure
+ */
+
+int ossl_policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps)
+{
+ POLICY_MAPPING *map;
+ X509_POLICY_DATA *data;
+ X509_POLICY_CACHE *cache = x->policy_cache;
+ int i;
+ int ret = 0;
+ if (sk_POLICY_MAPPING_num(maps) == 0) {
+ ret = -1;
+ goto bad_mapping;
+ }
+ for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) {
+ map = sk_POLICY_MAPPING_value(maps, i);
+ /* Reject if map to or from anyPolicy */
+ if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy)
+ || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) {
+ ret = -1;
+ goto bad_mapping;
+ }
+
+ /* Attempt to find matching policy data */
+ data = ossl_policy_cache_find_data(cache, map->issuerDomainPolicy);
+ /* If we don't have anyPolicy can't map */
+ if (data == NULL && !cache->anyPolicy)
+ continue;
+
+ /* Create a NODE from anyPolicy */
+ if (data == NULL) {
+ data = ossl_policy_data_new(NULL, map->issuerDomainPolicy,
+ cache->anyPolicy->flags
+ & POLICY_DATA_FLAG_CRITICAL);
+ if (data == NULL)
+ goto bad_mapping;
+ data->qualifier_set = cache->anyPolicy->qualifier_set;
+ /*
+ * map->issuerDomainPolicy = NULL;
+ */
+ data->flags |= POLICY_DATA_FLAG_MAPPED_ANY;
+ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+ if (!sk_X509_POLICY_DATA_push(cache->data, data)) {
+ ossl_policy_data_free(data);
+ goto bad_mapping;
+ }
+ } else
+ data->flags |= POLICY_DATA_FLAG_MAPPED;
+ if (!sk_ASN1_OBJECT_push(data->expected_policy_set,
+ map->subjectDomainPolicy))
+ goto bad_mapping;
+ map->subjectDomainPolicy = NULL;
+
+ }
+
+ ret = 1;
+ bad_mapping:
+ sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
+ return ret;
+
+}
diff --git a/crypto/x509/pcy_node.c b/crypto/x509/pcy_node.c
new file mode 100644
index 000000000000..9b77e6e95e05
--- /dev/null
+++ b/crypto/x509/pcy_node.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2004-2023 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 <openssl/asn1.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+#include "pcy_local.h"
+
+static int node_cmp(const X509_POLICY_NODE *const *a,
+ const X509_POLICY_NODE *const *b)
+{
+ return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy);
+}
+
+STACK_OF(X509_POLICY_NODE) *ossl_policy_node_cmp_new(void)
+{
+ return sk_X509_POLICY_NODE_new(node_cmp);
+}
+
+X509_POLICY_NODE *ossl_policy_tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes,
+ const ASN1_OBJECT *id)
+{
+ X509_POLICY_DATA n;
+ X509_POLICY_NODE l;
+ int idx;
+
+ n.valid_policy = (ASN1_OBJECT *)id;
+ l.data = &n;
+
+ idx = sk_X509_POLICY_NODE_find(nodes, &l);
+ return sk_X509_POLICY_NODE_value(nodes, idx);
+
+}
+
+X509_POLICY_NODE *ossl_policy_level_find_node(const X509_POLICY_LEVEL *level,
+ const X509_POLICY_NODE *parent,
+ const ASN1_OBJECT *id)
+{
+ X509_POLICY_NODE *node;
+ int i;
+ for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
+ node = sk_X509_POLICY_NODE_value(level->nodes, i);
+ if (node->parent == parent) {
+ if (!OBJ_cmp(node->data->valid_policy, id))
+ return node;
+ }
+ }
+ return NULL;
+}
+
+X509_POLICY_NODE *ossl_policy_level_add_node(X509_POLICY_LEVEL *level,
+ X509_POLICY_DATA *data,
+ X509_POLICY_NODE *parent,
+ X509_POLICY_TREE *tree,
+ int extra_data)
+{
+ X509_POLICY_NODE *node;
+
+ /* Verify that the tree isn't too large. This mitigates CVE-2023-0464 */
+ if (tree->node_maximum > 0 && tree->node_count >= tree->node_maximum)
+ return NULL;
+
+ node = OPENSSL_zalloc(sizeof(*node));
+ if (node == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ node->data = data;
+ node->parent = parent;
+ if (level != NULL) {
+ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
+ if (level->anyPolicy)
+ goto node_error;
+ level->anyPolicy = node;
+ } else {
+
+ if (level->nodes == NULL)
+ level->nodes = ossl_policy_node_cmp_new();
+ if (level->nodes == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto node_error;
+ }
+ if (!sk_X509_POLICY_NODE_push(level->nodes, node)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto node_error;
+ }
+ }
+ }
+
+ if (extra_data) {
+ if (tree->extra_data == NULL)
+ tree->extra_data = sk_X509_POLICY_DATA_new_null();
+ if (tree->extra_data == NULL){
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto extra_data_error;
+ }
+ if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto extra_data_error;
+ }
+ }
+
+ tree->node_count++;
+ if (parent)
+ parent->nchild++;
+
+ return node;
+
+ extra_data_error:
+ if (level != NULL) {
+ if (level->anyPolicy == node)
+ level->anyPolicy = NULL;
+ else
+ (void) sk_X509_POLICY_NODE_pop(level->nodes);
+ }
+
+ node_error:
+ ossl_policy_node_free(node);
+ return NULL;
+}
+
+void ossl_policy_node_free(X509_POLICY_NODE *node)
+{
+ OPENSSL_free(node);
+}
+
+/*
+ * See if a policy node matches a policy OID. If mapping enabled look through
+ * expected policy set otherwise just valid policy.
+ */
+
+int ossl_policy_node_match(const X509_POLICY_LEVEL *lvl,
+ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid)
+{
+ int i;
+ ASN1_OBJECT *policy_oid;
+ const X509_POLICY_DATA *x = node->data;
+
+ if ((lvl->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(x->flags & POLICY_DATA_FLAG_MAP_MASK)) {
+ if (!OBJ_cmp(x->valid_policy, oid))
+ return 1;
+ return 0;
+ }
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++) {
+ policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i);
+ if (!OBJ_cmp(policy_oid, oid))
+ return 1;
+ }
+ return 0;
+
+}
diff --git a/crypto/x509/pcy_tree.c b/crypto/x509/pcy_tree.c
new file mode 100644
index 000000000000..2012810303ed
--- /dev/null
+++ b/crypto/x509/pcy_tree.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2004-2023 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 <openssl/trace.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_local.h"
+
+/*
+ * If the maximum number of nodes in the policy tree isn't defined, set it to
+ * a generous default of 1000 nodes.
+ *
+ * Defining this to be zero means unlimited policy tree growth which opens the
+ * door on CVE-2023-0464.
+ */
+#ifndef OPENSSL_POLICY_TREE_NODES_MAX
+# define OPENSSL_POLICY_TREE_NODES_MAX 1000
+#endif
+
+static void exnode_free(X509_POLICY_NODE *node);
+
+static void expected_print(BIO *channel,
+ X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node,
+ int indent)
+{
+ if ((lev->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
+ BIO_puts(channel, " Not Mapped\n");
+ else {
+ int i;
+
+ STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
+ ASN1_OBJECT *oid;
+ BIO_puts(channel, " Expected: ");
+ for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) {
+ oid = sk_ASN1_OBJECT_value(pset, i);
+ if (i)
+ BIO_puts(channel, ", ");
+ i2a_ASN1_OBJECT(channel, oid);
+ }
+ BIO_puts(channel, "\n");
+ }
+}
+
+static void tree_print(BIO *channel,
+ char *str, X509_POLICY_TREE *tree,
+ X509_POLICY_LEVEL *curr)
+{
+ X509_POLICY_LEVEL *plev;
+
+ if (!curr)
+ curr = tree->levels + tree->nlevel;
+ else
+ curr++;
+
+ BIO_printf(channel, "Level print after %s\n", str);
+ BIO_printf(channel, "Printing Up to Level %ld\n",
+ (long)(curr - tree->levels));
+ for (plev = tree->levels; plev != curr; plev++) {
+ int i;
+
+ BIO_printf(channel, "Level %ld, flags = %x\n",
+ (long)(plev - tree->levels), plev->flags);
+ for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) {
+ X509_POLICY_NODE *node =
+ sk_X509_POLICY_NODE_value(plev->nodes, i);
+
+ X509_POLICY_NODE_print(channel, node, 2);
+ expected_print(channel, plev, node, 2);
+ BIO_printf(channel, " Flags: %x\n", node->data->flags);
+ }
+ if (plev->anyPolicy)
+ X509_POLICY_NODE_print(channel, plev->anyPolicy, 2);
+ }
+}
+
+#define TREE_PRINT(str, tree, curr) \
+ OSSL_TRACE_BEGIN(X509V3_POLICY) { \
+ tree_print(trc_out, "before tree_prune()", tree, curr); \
+ } OSSL_TRACE_END(X509V3_POLICY)
+
+/*-
+ * Return value: <= 0 on error, or positive bit mask:
+ *
+ * X509_PCY_TREE_VALID: valid tree
+ * X509_PCY_TREE_EMPTY: empty tree (including bare TA case)
+ * X509_PCY_TREE_EXPLICIT: explicit policy required
+ */
+static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
+ unsigned int flags)
+{
+ X509_POLICY_TREE *tree;
+ X509_POLICY_LEVEL *level;
+ const X509_POLICY_CACHE *cache;
+ X509_POLICY_DATA *data = NULL;
+ int ret = X509_PCY_TREE_VALID;
+ int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */
+ int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1;
+ int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1;
+ int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1;
+ int i;
+
+ *ptree = NULL;
+
+ /* Can't do anything with just a trust anchor */
+ if (n == 0)
+ return X509_PCY_TREE_EMPTY;
+
+ /*
+ * First setup the policy cache in all n non-TA certificates, this will be
+ * used in X509_verify_cert() which will invoke the verify callback for all
+ * certificates with invalid policy extensions.
+ */
+ for (i = n - 1; i >= 0; i--) {
+ X509 *x = sk_X509_value(certs, i);
+
+ /* Call for side-effect of computing hash and caching extensions */
+ X509_check_purpose(x, -1, 0);
+
+ /* If cache is NULL, likely ENOMEM: return immediately */
+ if (ossl_policy_cache_set(x) == NULL)
+ return X509_PCY_TREE_INTERNAL;
+ }
+
+ /*
+ * At this point check for invalid policies and required explicit policy.
+ * Note that the explicit_policy counter is a count-down to zero, with the
+ * requirement kicking in if and once it does that. The counter is
+ * decremented for every non-self-issued certificate in the path, but may
+ * be further reduced by policy constraints in a non-leaf certificate.
+ *
+ * The ultimate policy set is the intersection of all the policies along
+ * the path, if we hit a certificate with an empty policy set, and explicit
+ * policy is required we're done.
+ */
+ for (i = n - 1;
+ i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0);
+ i--) {
+ X509 *x = sk_X509_value(certs, i);
+ uint32_t ex_flags = X509_get_extension_flags(x);
+
+ /* All the policies are already cached, we can return early */
+ if (ex_flags & EXFLAG_INVALID_POLICY)
+ return X509_PCY_TREE_INVALID;
+
+ /* Access the cache which we now know exists */
+ cache = ossl_policy_cache_set(x);
+
+ if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL)
+ ret = X509_PCY_TREE_EMPTY;
+ if (explicit_policy > 0) {
+ if (!(ex_flags & EXFLAG_SI))
+ explicit_policy--;
+ if ((cache->explicit_skip >= 0)
+ && (cache->explicit_skip < explicit_policy))
+ explicit_policy = cache->explicit_skip;
+ }
+ }
+
+ if (explicit_policy == 0)
+ ret |= X509_PCY_TREE_EXPLICIT;
+ if ((ret & X509_PCY_TREE_VALID) == 0)
+ return ret;
+
+ /* If we get this far initialize the tree */
+ if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return X509_PCY_TREE_INTERNAL;
+ }
+
+ /* Limit the growth of the tree to mitigate CVE-2023-0464 */
+ tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX;
+
+ /*
+ * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
+ *
+ * The top level is implicitly for the trust anchor with valid expected
+ * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at
+ * depth n, we have the leaf at depth 0 and the TA at depth n).
+ */
+ if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) {
+ OPENSSL_free(tree);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return X509_PCY_TREE_INTERNAL;
+ }
+ tree->nlevel = n+1;
+ level = tree->levels;
+ if ((data = ossl_policy_data_new(NULL,
+ OBJ_nid2obj(NID_any_policy), 0)) == NULL)
+ goto bad_tree;
+ if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) {
+ ossl_policy_data_free(data);
+ goto bad_tree;
+ }
+
+ /*
+ * In this pass initialize all the tree levels and whether anyPolicy and
+ * policy mapping are inhibited at each level.
+ */
+ for (i = n - 1; i >= 0; i--) {
+ X509 *x = sk_X509_value(certs, i);
+ uint32_t ex_flags = X509_get_extension_flags(x);
+
+ /* Access the cache which we now know exists */
+ cache = ossl_policy_cache_set(x);
+
+ X509_up_ref(x);
+ (++level)->cert = x;
+
+ if (!cache->anyPolicy)
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+
+ /* Determine inhibit any and inhibit map flags */
+ if (any_skip == 0) {
+ /*
+ * Any matching allowed only if certificate is self issued and not
+ * the last in the chain.
+ */
+ if (!(ex_flags & EXFLAG_SI) || (i == 0))
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+ } else {
+ if (!(ex_flags & EXFLAG_SI))
+ any_skip--;
+ if ((cache->any_skip >= 0) && (cache->any_skip < any_skip))
+ any_skip = cache->any_skip;
+ }
+
+ if (map_skip == 0)
+ level->flags |= X509_V_FLAG_INHIBIT_MAP;
+ else {
+ if (!(ex_flags & EXFLAG_SI))
+ map_skip--;
+ if ((cache->map_skip >= 0) && (cache->map_skip < map_skip))
+ map_skip = cache->map_skip;
+ }
+ }
+
+ *ptree = tree;
+ return ret;
+
+ bad_tree:
+ X509_policy_tree_free(tree);
+ return X509_PCY_TREE_INTERNAL;
+}
+
+/*
+ * Return value: 1 on success, 0 otherwise
+ */
+static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
+ X509_POLICY_DATA *data,
+ X509_POLICY_TREE *tree)
+{
+ X509_POLICY_LEVEL *last = curr - 1;
+ int i, matched = 0;
+
+ /* Iterate through all in nodes linking matches */
+ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
+ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i);
+
+ if (ossl_policy_node_match(last, node, data->valid_policy)) {
+ if (ossl_policy_level_add_node(curr, data, node, tree, 0) == NULL)
+ return 0;
+ matched = 1;
+ }
+ }
+ if (!matched && last->anyPolicy) {
+ if (ossl_policy_level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This corresponds to RFC3280 6.1.3(d)(1): link any data from
+ * CertificatePolicies onto matching parent or anyPolicy if no match.
+ *
+ * Return value: 1 on success, 0 otherwise.
+ */
+static int tree_link_nodes(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ X509_POLICY_TREE *tree)
+{
+ int i;
+
+ for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) {
+ X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i);
+
+ /* Look for matching nodes in previous level */
+ if (!tree_link_matching_nodes(curr, data, tree))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched
+ * policies in the parent and link to anyPolicy.
+ *
+ * Return value: 1 on success, 0 otherwise.
+ */
+static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id,
+ X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
+{
+ X509_POLICY_DATA *data;
+
+ if (id == NULL)
+ id = node->data->valid_policy;
+ /*
+ * Create a new node with qualifiers from anyPolicy and id from unmatched
+ * node.
+ */
+ if ((data = ossl_policy_data_new(NULL, id, node_critical(node))) == NULL)
+ return 0;
+
+ /* Curr may not have anyPolicy */
+ data->qualifier_set = cache->anyPolicy->qualifier_set;
+ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+ if (ossl_policy_level_add_node(curr, data, node, tree, 1) == NULL) {
+ ossl_policy_data_free(data);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Return value: 1 on success, 0 otherwise.
+ */
+static int tree_link_unmatched(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
+{
+ const X509_POLICY_LEVEL *last = curr - 1;
+ int i;
+
+ if ((last->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) {
+ /* If no policy mapping: matched if one child present */
+ if (node->nchild)
+ return 1;
+ if (!tree_add_unmatched(curr, cache, NULL, node, tree))
+ return 0;
+ /* Add it */
+ } else {
+ /* If mapping: matched if one child per expected policy set */
+ STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set;
+ if (node->nchild == sk_ASN1_OBJECT_num(expset))
+ return 1;
+ /* Locate unmatched nodes */
+ for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) {
+ ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i);
+ if (ossl_policy_level_find_node(curr, node, oid))
+ continue;
+ if (!tree_add_unmatched(curr, cache, oid, node, tree))
+ return 0;
+ }
+
+ }
+ return 1;
+}
+
+/*
+ * Return value: 1 on success, 0 otherwise
+ */
+static int tree_link_any(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ X509_POLICY_TREE *tree)
+{
+ int i;
+ X509_POLICY_NODE *node;
+ X509_POLICY_LEVEL *last = curr - 1;
+
+ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
+ node = sk_X509_POLICY_NODE_value(last->nodes, i);
+
+ if (!tree_link_unmatched(curr, cache, node, tree))
+ return 0;
+ }
+ /* Finally add link to anyPolicy */
+ if (last->anyPolicy &&
+ ossl_policy_level_add_node(curr, cache->anyPolicy,
+ last->anyPolicy, tree, 0) == NULL)
+ return 0;
+ return 1;
+}
+
+/*-
+ * Prune the tree: delete any child mapped child data on the current level then
+ * proceed up the tree deleting any data with no children. If we ever have no
+ * data on a level we can halt because the tree will be empty.
+ *
+ * Return value: <= 0 error, otherwise one of:
+ *
+ * X509_PCY_TREE_VALID: valid tree
+ * X509_PCY_TREE_EMPTY: empty tree
+ */
+static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
+{
+ STACK_OF(X509_POLICY_NODE) *nodes;
+ X509_POLICY_NODE *node;
+ int i;
+ nodes = curr->nodes;
+ if (curr->flags & X509_V_FLAG_INHIBIT_MAP) {
+ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
+ node = sk_X509_POLICY_NODE_value(nodes, i);
+ /* Delete any mapped data: see RFC3280 XXXX */
+ if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) {
+ node->parent->nchild--;
+ OPENSSL_free(node);
+ (void)sk_X509_POLICY_NODE_delete(nodes, i);
+ }
+ }
+ }
+
+ for (;;) {
+ --curr;
+ nodes = curr->nodes;
+ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
+ node = sk_X509_POLICY_NODE_value(nodes, i);
+ if (node->nchild == 0) {
+ node->parent->nchild--;
+ OPENSSL_free(node);
+ (void)sk_X509_POLICY_NODE_delete(nodes, i);
+ }
+ }
+ if (curr->anyPolicy && !curr->anyPolicy->nchild) {
+ if (curr->anyPolicy->parent)
+ curr->anyPolicy->parent->nchild--;
+ OPENSSL_free(curr->anyPolicy);
+ curr->anyPolicy = NULL;
+ }
+ if (curr == tree->levels) {
+ /* If we zapped anyPolicy at top then tree is empty */
+ if (!curr->anyPolicy)
+ return X509_PCY_TREE_EMPTY;
+ break;
+ }
+ }
+ return X509_PCY_TREE_VALID;
+}
+
+/*
+ * Return value: 1 on success, 0 otherwise.
+ */
+static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
+ X509_POLICY_NODE *pcy)
+{
+ if (*pnodes == NULL &&
+ (*pnodes = ossl_policy_node_cmp_new()) == NULL)
+ return 0;
+ if (sk_X509_POLICY_NODE_find(*pnodes, pcy) >= 0)
+ return 1;
+ return sk_X509_POLICY_NODE_push(*pnodes, pcy) != 0;
+}
+
+#define TREE_CALC_FAILURE 0
+#define TREE_CALC_OK_NOFREE 1
+#define TREE_CALC_OK_DOFREE 2
+
+/*-
+ * Calculate the authority set based on policy tree. The 'pnodes' parameter is
+ * used as a store for the set of policy nodes used to calculate the user set.
+ * If the authority set is not anyPolicy then pnodes will just point to the
+ * authority set. If however the authority set is anyPolicy then the set of
+ * valid policies (other than anyPolicy) is store in pnodes.
+ *
+ * Return value:
+ * TREE_CALC_FAILURE on failure,
+ * TREE_CALC_OK_NOFREE on success and pnodes need not be freed,
+ * TREE_CALC_OK_DOFREE on success and pnodes needs to be freed
+ */
+static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
+ STACK_OF(X509_POLICY_NODE) **pnodes)
+{
+ X509_POLICY_LEVEL *curr;
+ X509_POLICY_NODE *node, *anyptr;
+ STACK_OF(X509_POLICY_NODE) **addnodes;
+ int i, j;
+ curr = tree->levels + tree->nlevel - 1;
+
+ /* If last level contains anyPolicy set is anyPolicy */
+ if (curr->anyPolicy) {
+ if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
+ return TREE_CALC_FAILURE;
+ addnodes = pnodes;
+ } else
+ /* Add policies to authority set */
+ addnodes = &tree->auth_policies;
+
+ curr = tree->levels;
+ for (i = 1; i < tree->nlevel; i++) {
+ /*
+ * If no anyPolicy node on this level it can't appear on lower
+ * levels so end search.
+ */
+ if ((anyptr = curr->anyPolicy) == NULL)
+ break;
+ curr++;
+ for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) {
+ node = sk_X509_POLICY_NODE_value(curr->nodes, j);
+ if ((node->parent == anyptr)
+ && !tree_add_auth_node(addnodes, node)) {
+ if (addnodes == pnodes) {
+ sk_X509_POLICY_NODE_free(*pnodes);
+ *pnodes = NULL;
+ }
+ return TREE_CALC_FAILURE;
+ }
+ }
+ }
+ if (addnodes == pnodes)
+ return TREE_CALC_OK_DOFREE;
+
+ *pnodes = tree->auth_policies;
+ return TREE_CALC_OK_NOFREE;
+}
+
+/*
+ * Return value: 1 on success, 0 otherwise.
+ */
+static int tree_calculate_user_set(X509_POLICY_TREE *tree,
+ STACK_OF(ASN1_OBJECT) *policy_oids,
+ STACK_OF(X509_POLICY_NODE) *auth_nodes)
+{
+ int i;
+ X509_POLICY_NODE *node;
+ ASN1_OBJECT *oid;
+ X509_POLICY_NODE *anyPolicy;
+ X509_POLICY_DATA *extra;
+
+ /*
+ * Check if anyPolicy present in authority constrained policy set: this
+ * will happen if it is a leaf node.
+ */
+ if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
+ return 1;
+
+ anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) {
+ oid = sk_ASN1_OBJECT_value(policy_oids, i);
+ if (OBJ_obj2nid(oid) == NID_any_policy) {
+ tree->flags |= POLICY_FLAG_ANY_POLICY;
+ return 1;
+ }
+ }
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) {
+ oid = sk_ASN1_OBJECT_value(policy_oids, i);
+ node = ossl_policy_tree_find_sk(auth_nodes, oid);
+ if (!node) {
+ if (!anyPolicy)
+ continue;
+ /*
+ * Create a new node with policy ID from user set and qualifiers
+ * from anyPolicy.
+ */
+ extra = ossl_policy_data_new(NULL, oid, node_critical(anyPolicy));
+ if (extra == NULL)
+ return 0;
+ extra->qualifier_set = anyPolicy->data->qualifier_set;
+ extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
+ | POLICY_DATA_FLAG_EXTRA_NODE;
+ node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent,
+ tree, 1);
+ if (node == NULL) {
+ ossl_policy_data_free(extra);
+ return 0;
+ }
+ }
+ if (!tree->user_policies) {
+ tree->user_policies = sk_X509_POLICY_NODE_new_null();
+ if (!tree->user_policies) {
+ exnode_free(node);
+ return 0;
+ }
+ }
+ if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) {
+ exnode_free(node);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*-
+ * Return value: <= 0 error, otherwise one of:
+ * X509_PCY_TREE_VALID: valid tree
+ * X509_PCY_TREE_EMPTY: empty tree
+ * (see tree_prune()).
+ */
+static int tree_evaluate(X509_POLICY_TREE *tree)
+{
+ int ret, i;
+ X509_POLICY_LEVEL *curr = tree->levels + 1;
+ const X509_POLICY_CACHE *cache;
+
+ for (i = 1; i < tree->nlevel; i++, curr++) {
+ cache = ossl_policy_cache_set(curr->cert);
+ if (!tree_link_nodes(curr, cache, tree))
+ return X509_PCY_TREE_INTERNAL;
+
+ if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
+ && !tree_link_any(curr, cache, tree))
+ return X509_PCY_TREE_INTERNAL;
+ TREE_PRINT("before tree_prune()", tree, curr);
+ ret = tree_prune(tree, curr);
+ if (ret != X509_PCY_TREE_VALID)
+ return ret;
+ }
+ return X509_PCY_TREE_VALID;
+}
+
+static void exnode_free(X509_POLICY_NODE *node)
+{
+ if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
+ OPENSSL_free(node);
+}
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree)
+{
+ X509_POLICY_LEVEL *curr;
+ int i;
+
+ if (!tree)
+ return;
+
+ sk_X509_POLICY_NODE_free(tree->auth_policies);
+ sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
+
+ for (i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) {
+ X509_free(curr->cert);
+ sk_X509_POLICY_NODE_pop_free(curr->nodes, ossl_policy_node_free);
+ ossl_policy_node_free(curr->anyPolicy);
+ }
+
+ sk_X509_POLICY_DATA_pop_free(tree->extra_data, ossl_policy_data_free);
+ OPENSSL_free(tree->levels);
+ OPENSSL_free(tree);
+
+}
+
+/*-
+ * Application policy checking function.
+ * Return codes:
+ * X509_PCY_TREE_FAILURE: Failure to satisfy explicit policy
+ * X509_PCY_TREE_INVALID: Inconsistent or invalid extensions
+ * X509_PCY_TREE_INTERNAL: Internal error, most likely malloc
+ * X509_PCY_TREE_VALID: Success (null tree if empty or bare TA)
+ */
+int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+ STACK_OF(X509) *certs,
+ STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags)
+{
+ int init_ret;
+ int ret;
+ int calc_ret;
+ X509_POLICY_TREE *tree = NULL;
+ STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
+
+ *ptree = NULL;
+ *pexplicit_policy = 0;
+ init_ret = tree_init(&tree, certs, flags);
+
+ if (init_ret <= 0)
+ return init_ret;
+
+ if ((init_ret & X509_PCY_TREE_EXPLICIT) == 0) {
+ if (init_ret & X509_PCY_TREE_EMPTY) {
+ X509_policy_tree_free(tree);
+ return X509_PCY_TREE_VALID;
+ }
+ } else {
+ *pexplicit_policy = 1;
+ /* Tree empty and requireExplicit True: Error */
+ if (init_ret & X509_PCY_TREE_EMPTY)
+ return X509_PCY_TREE_FAILURE;
+ }
+
+ ret = tree_evaluate(tree);
+ TREE_PRINT("tree_evaluate()", tree, NULL);
+ if (ret <= 0)
+ goto error;
+
+ if (ret == X509_PCY_TREE_EMPTY) {
+ X509_policy_tree_free(tree);
+ if (init_ret & X509_PCY_TREE_EXPLICIT)
+ return X509_PCY_TREE_FAILURE;
+ return X509_PCY_TREE_VALID;
+ }
+
+ /* Tree is not empty: continue */
+
+ if ((calc_ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0)
+ goto error;
+ ret = tree_calculate_user_set(tree, policy_oids, auth_nodes);
+ if (calc_ret == TREE_CALC_OK_DOFREE)
+ sk_X509_POLICY_NODE_free(auth_nodes);
+ if (!ret)
+ goto error;
+
+ *ptree = tree;
+
+ if (init_ret & X509_PCY_TREE_EXPLICIT) {
+ nodes = X509_policy_tree_get0_user_policies(tree);
+ if (sk_X509_POLICY_NODE_num(nodes) <= 0)
+ return X509_PCY_TREE_FAILURE;
+ }
+ return X509_PCY_TREE_VALID;
+
+ error:
+ X509_policy_tree_free(tree);
+ return X509_PCY_TREE_INTERNAL;
+}
diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h
new file mode 100644
index 000000000000..27a99a4b13ed
--- /dev/null
+++ b/crypto/x509/standard_exts.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999-2021 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
+ */
+
+/*
+ * This table will be searched using OBJ_bsearch so it *must* kept in order
+ * of the ext_nid values.
+ */
+
+static const X509V3_EXT_METHOD *standard_exts[] = {
+ &ossl_v3_nscert,
+ &ossl_v3_ns_ia5_list[0],
+ &ossl_v3_ns_ia5_list[1],
+ &ossl_v3_ns_ia5_list[2],
+ &ossl_v3_ns_ia5_list[3],
+ &ossl_v3_ns_ia5_list[4],
+ &ossl_v3_ns_ia5_list[5],
+ &ossl_v3_ns_ia5_list[6],
+ &ossl_v3_skey_id,
+ &ossl_v3_key_usage,
+ &ossl_v3_pkey_usage_period,
+ &ossl_v3_alt[0],
+ &ossl_v3_alt[1],
+ &ossl_v3_bcons,
+ &ossl_v3_crl_num,
+ &ossl_v3_cpols,
+ &ossl_v3_akey_id,
+ &ossl_v3_crld,
+ &ossl_v3_ext_ku,
+ &ossl_v3_delta_crl,
+ &ossl_v3_crl_reason,
+#ifndef OPENSSL_NO_OCSP
+ &ossl_v3_crl_invdate,
+#endif
+ &ossl_v3_sxnet,
+ &ossl_v3_info,
+#ifndef OPENSSL_NO_RFC3779
+ &ossl_v3_addr,
+ &ossl_v3_asid,
+#endif
+#ifndef OPENSSL_NO_OCSP
+ &ossl_v3_ocsp_nonce,
+ &ossl_v3_ocsp_crlid,
+ &ossl_v3_ocsp_accresp,
+ &ossl_v3_ocsp_nocheck,
+ &ossl_v3_ocsp_acutoff,
+ &ossl_v3_ocsp_serviceloc,
+#endif
+ &ossl_v3_sinfo,
+ &ossl_v3_policy_constraints,
+#ifndef OPENSSL_NO_OCSP
+ &ossl_v3_crl_hold,
+#endif
+ &ossl_v3_pci,
+ &ossl_v3_name_constraints,
+ &ossl_v3_policy_mappings,
+ &ossl_v3_inhibit_anyp,
+ &ossl_v3_idp,
+ &ossl_v3_alt[2],
+ &ossl_v3_freshest_crl,
+#ifndef OPENSSL_NO_CT
+ &ossl_v3_ct_scts[0],
+ &ossl_v3_ct_scts[1],
+ &ossl_v3_ct_scts[2],
+#endif
+ &ossl_v3_utf8_list[0],
+ &ossl_v3_issuer_sign_tool,
+ &ossl_v3_tls_feature,
+ &ossl_v3_ext_admission
+};
+
+/* Number of standard extensions */
+
+#define STANDARD_EXTENSION_COUNT OSSL_NELEM(standard_exts)
+
diff --git a/crypto/x509/t_crl.c b/crypto/x509/t_crl.c
index 8e262912ffaa..e77a77978a83 100644
--- a/crypto/x509/t_crl.c
+++ b/crypto/x509/t_crl.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -22,7 +22,7 @@ int X509_CRL_print_fp(FILE *fp, X509_CRL *x)
int ret;
if ((b = BIO_new(BIO_s_file())) == NULL) {
- X509err(X509_F_X509_CRL_PRINT_FP, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
@@ -48,7 +48,7 @@ int X509_CRL_print_ex(BIO *out, X509_CRL *x, unsigned long nmflag)
BIO_printf(out, "Certificate Revocation List (CRL):\n");
l = X509_CRL_get_version(x);
- if (l >= 0 && l <= 1)
+ if (l >= X509_CRL_VERSION_1 && l <= X509_CRL_VERSION_2)
BIO_printf(out, "%8sVersion %ld (0x%lx)\n", "", l + 1, (unsigned long)l);
else
BIO_printf(out, "%8sVersion unknown (%ld)\n", "", l);
diff --git a/crypto/x509/t_req.c b/crypto/x509/t_req.c
index dc3b4f262de9..63626c0d9810 100644
--- a/crypto/x509/t_req.c
+++ b/crypto/x509/t_req.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -24,7 +24,7 @@ int X509_REQ_print_fp(FILE *fp, X509_REQ *x)
int ret;
if ((b = BIO_new(BIO_s_file())) == NULL) {
- X509err(X509_F_X509_REQ_PRINT_FP, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
@@ -42,15 +42,15 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
EVP_PKEY *pkey;
STACK_OF(X509_EXTENSION) *exts;
char mlch = ' ';
- int nmindent = 0;
+ int nmindent = 0, printok = 0;
if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
mlch = '\n';
nmindent = 12;
}
- if (nmflags == X509_FLAG_COMPAT)
- nmindent = 16;
+ if (nmflags == XN_FLAG_COMPAT)
+ printok = 1;
if (!(cflag & X509_FLAG_NO_HEADER)) {
if (BIO_write(bp, "Certificate Request:\n", 21) <= 0)
@@ -60,7 +60,7 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
}
if (!(cflag & X509_FLAG_NO_VERSION)) {
l = X509_REQ_get_version(x);
- if (l >= 0 && l <= 2) {
+ if (l == X509_REQ_VERSION_1) {
if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0)
goto err;
} else {
@@ -72,7 +72,7 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
if (BIO_printf(bp, " Subject:%c", mlch) <= 0)
goto err;
if (X509_NAME_print_ex(bp, X509_REQ_get_subject_name(x),
- nmindent, nmflags) < 0)
+ nmindent, nmflags) < printok)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
@@ -108,7 +108,7 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
goto err;
if (X509_REQ_get_attr_count(x) == 0) {
- if (BIO_printf(bp, "%12sa0:00\n", "") <= 0)
+ if (BIO_printf(bp, "%12s(none)\n", "") <= 0)
goto err;
} else {
for (i = 0; i < X509_REQ_get_attr_count(x); i++) {
@@ -128,7 +128,7 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
ii = 0;
count = X509_ATTRIBUTE_count(a);
if (count == 0) {
- X509err(X509_F_X509_REQ_PRINT_EX, X509_R_INVALID_ATTRIBUTES);
+ ERR_raise(ERR_LIB_X509, X509_R_INVALID_ATTRIBUTES);
return 0;
}
get_next:
@@ -166,14 +166,14 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
if (!(cflag & X509_FLAG_NO_EXTENSIONS)) {
exts = X509_REQ_get_extensions(x);
if (exts) {
- if (BIO_printf(bp, "%8sRequested Extensions:\n", "") <= 0)
+ if (BIO_printf(bp, "%12sRequested Extensions:\n", "") <= 0)
goto err;
for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ex;
int critical;
ex = sk_X509_EXTENSION_value(exts, i);
- if (BIO_printf(bp, "%12s", "") <= 0)
+ if (BIO_printf(bp, "%16s", "") <= 0)
goto err;
obj = X509_EXTENSION_get_object(ex);
if (i2a_ASN1_OBJECT(bp, obj) <= 0)
@@ -181,8 +181,8 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
critical = X509_EXTENSION_get_critical(ex);
if (BIO_printf(bp, ": %s\n", critical ? "critical" : "") <= 0)
goto err;
- if (!X509V3_EXT_print(bp, ex, cflag, 16)) {
- if (BIO_printf(bp, "%16s", "") <= 0
+ if (!X509V3_EXT_print(bp, ex, cflag, 20)) {
+ if (BIO_printf(bp, "%20s", "") <= 0
|| ASN1_STRING_print(bp,
X509_EXTENSION_get_data(ex)) <= 0)
goto err;
@@ -204,7 +204,7 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
return 1;
err:
- X509err(X509_F_X509_REQ_PRINT_EX, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
return 0;
}
diff --git a/crypto/x509/t_x509.c b/crypto/x509/t_x509.c
index ece987a6bdbe..5b0282bc132f 100644
--- a/crypto/x509/t_x509.c
+++ b/crypto/x509/t_x509.c
@@ -1,7 +1,7 @@
/*
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -15,6 +15,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "crypto/asn1.h"
+#include "crypto/x509.h"
#ifndef OPENSSL_NO_STDIO
int X509_print_fp(FILE *fp, X509 *x)
@@ -29,7 +30,7 @@ int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag,
int ret;
if ((b = BIO_new(BIO_s_file())) == NULL) {
- X509err(X509_F_X509_PRINT_EX_FP, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
@@ -50,8 +51,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
long l;
int ret = 0, i;
char *m = NULL, mlch = ' ';
- int nmindent = 0;
- ASN1_INTEGER *bs;
+ int nmindent = 0, printok = 0;
EVP_PKEY *pkey = NULL;
const char *neg;
@@ -60,8 +60,8 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
nmindent = 12;
}
- if (nmflags == X509_FLAG_COMPAT)
- nmindent = 16;
+ if (nmflags == XN_FLAG_COMPAT)
+ printok = 1;
if (!(cflag & X509_FLAG_NO_HEADER)) {
if (BIO_write(bp, "Certificate:\n", 13) <= 0)
@@ -71,7 +71,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
}
if (!(cflag & X509_FLAG_NO_VERSION)) {
l = X509_get_version(x);
- if (l >= 0 && l <= 2) {
+ if (l >= X509_VERSION_1 && l <= X509_VERSION_3) {
if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0)
goto err;
} else {
@@ -80,11 +80,11 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
}
}
if (!(cflag & X509_FLAG_NO_SERIAL)) {
+ const ASN1_INTEGER *bs = X509_get0_serialNumber(x);
if (BIO_write(bp, " Serial Number:", 22) <= 0)
goto err;
- bs = X509_get_serialNumber(x);
if (bs->length <= (int)sizeof(long)) {
ERR_set_mark();
l = ASN1_INTEGER_get(bs);
@@ -130,7 +130,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
if (BIO_printf(bp, " Issuer:%c", mlch) <= 0)
goto err;
if (X509_NAME_print_ex(bp, X509_get_issuer_name(x), nmindent, nmflags)
- < 0)
+ < printok)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
@@ -140,11 +140,11 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
goto err;
if (BIO_write(bp, " Not Before: ", 24) <= 0)
goto err;
- if (!ASN1_TIME_print(bp, X509_get0_notBefore(x)))
+ if (ossl_asn1_time_print_ex(bp, X509_get0_notBefore(x), ASN1_DTFLGS_RFC822) == 0)
goto err;
if (BIO_write(bp, "\n Not After : ", 25) <= 0)
goto err;
- if (!ASN1_TIME_print(bp, X509_get0_notAfter(x)))
+ if (ossl_asn1_time_print_ex(bp, X509_get0_notAfter(x), ASN1_DTFLGS_RFC822) == 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
@@ -153,7 +153,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
if (BIO_printf(bp, " Subject:%c", mlch) <= 0)
goto err;
if (X509_NAME_print_ex
- (bp, X509_get_subject_name(x), nmindent, nmflags) < 0)
+ (bp, X509_get_subject_name(x), nmindent, nmflags) < printok)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
@@ -197,9 +197,10 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
}
}
- if (!(cflag & X509_FLAG_NO_EXTENSIONS))
- X509V3_extensions_print(bp, "X509v3 extensions",
- X509_get0_extensions(x), cflag, 8);
+ if (!(cflag & X509_FLAG_NO_EXTENSIONS)
+ && !X509V3_extensions_print(bp, "X509v3 extensions",
+ X509_get0_extensions(x), cflag, 8))
+ goto err;
if (!(cflag & X509_FLAG_NO_SIGDUMP)) {
const X509_ALGOR *sig_alg;
@@ -226,8 +227,11 @@ int X509_ocspid_print(BIO *bp, X509 *x)
int i;
unsigned char SHA1md[SHA_DIGEST_LENGTH];
ASN1_BIT_STRING *keybstr;
- X509_NAME *subj;
+ const X509_NAME *subj;
+ EVP_MD *md = NULL;
+ if (x == NULL || bp == NULL)
+ return 0;
/*
* display the hash of the subject as it would appear in OCSP requests
*/
@@ -235,11 +239,16 @@ int X509_ocspid_print(BIO *bp, X509 *x)
goto err;
subj = X509_get_subject_name(x);
derlen = i2d_X509_NAME(subj, NULL);
+ if (derlen <= 0)
+ goto err;
if ((der = dertmp = OPENSSL_malloc(derlen)) == NULL)
goto err;
i2d_X509_NAME(subj, &dertmp);
- if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL))
+ md = EVP_MD_fetch(x->libctx, SN_sha1, x->propq);
+ if (md == NULL)
+ goto err;
+ if (!EVP_Digest(der, derlen, SHA1md, NULL, md, NULL))
goto err;
for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
@@ -260,18 +269,19 @@ int X509_ocspid_print(BIO *bp, X509 *x)
goto err;
if (!EVP_Digest(ASN1_STRING_get0_data(keybstr),
- ASN1_STRING_length(keybstr), SHA1md, NULL, EVP_sha1(),
- NULL))
+ ASN1_STRING_length(keybstr), SHA1md, NULL, md, NULL))
goto err;
for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
goto err;
}
BIO_printf(bp, "\n");
+ EVP_MD_free(md);
return 1;
err:
OPENSSL_free(der);
+ EVP_MD_free(md);
return 0;
}
@@ -284,7 +294,7 @@ int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent)
s = sig->data;
for (i = 0; i < n; i++) {
if ((i % 18) == 0) {
- if (BIO_write(bp, "\n", 1) <= 0)
+ if (i > 0 && BIO_write(bp, "\n", 1) <= 0)
return 0;
if (BIO_indent(bp, indent, indent) <= 0)
return 0;
@@ -302,11 +312,14 @@ int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg,
const ASN1_STRING *sig)
{
int sig_nid;
- if (BIO_puts(bp, " Signature Algorithm: ") <= 0)
+ int indent = 4;
+ if (BIO_printf(bp, "%*sSignature Algorithm: ", indent, "") <= 0)
return 0;
if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0)
return 0;
+ if (sig && BIO_printf(bp, "\n%*sSignature Value:", indent, "") <= 0)
+ return 0;
sig_nid = OBJ_obj2nid(sigalg->algorithm);
if (sig_nid != NID_undef) {
int pkey_nid, dig_nid;
@@ -314,13 +327,13 @@ int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg,
if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) {
ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
if (ameth && ameth->sig_print)
- return ameth->sig_print(bp, sigalg, sig, 9, 0);
+ return ameth->sig_print(bp, sigalg, sig, indent + 4, 0);
}
}
- if (sig)
- return X509_signature_dump(bp, sig, 9);
- else if (BIO_puts(bp, "\n") <= 0)
+ if (BIO_write(bp, "\n", 1) != 1)
return 0;
+ if (sig)
+ return X509_signature_dump(bp, sig, indent + 4);
return 1;
}
@@ -377,3 +390,138 @@ int X509_aux_print(BIO *out, X509 *x, int indent)
}
return 1;
}
+
+/*
+ * Helper functions for improving certificate verification error diagnostics
+ */
+
+int ossl_x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags)
+{
+ unsigned long flags = ASN1_STRFLGS_RFC2253 | ASN1_STRFLGS_ESC_QUOTE |
+ XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN;
+
+ if (cert == NULL)
+ return BIO_printf(bio, " (no certificate)\n") > 0;
+ if (BIO_printf(bio, " certificate\n") <= 0
+ || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_SUBJECT))
+ return 0;
+ if (X509_check_issued((X509 *)cert, cert) == X509_V_OK) {
+ if (BIO_printf(bio, " self-issued\n") <= 0)
+ return 0;
+ } else {
+ if (BIO_printf(bio, " ") <= 0
+ || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_ISSUER))
+ return 0;
+ }
+ if (!X509_print_ex(bio, cert, flags,
+ ~(X509_FLAG_NO_SERIAL | X509_FLAG_NO_VALIDITY)))
+ return 0;
+ if (X509_cmp_current_time(X509_get0_notBefore(cert)) > 0)
+ if (BIO_printf(bio, " not yet valid\n") <= 0)
+ return 0;
+ if (X509_cmp_current_time(X509_get0_notAfter(cert)) < 0)
+ if (BIO_printf(bio, " no more valid\n") <= 0)
+ return 0;
+ return X509_print_ex(bio, cert, flags,
+ ~neg_cflags & ~X509_FLAG_EXTENSIONS_ONLY_KID);
+}
+
+static int print_certs(BIO *bio, const STACK_OF(X509) *certs)
+{
+ int i;
+
+ if (certs == NULL || sk_X509_num(certs) <= 0)
+ return BIO_printf(bio, " (no certificates)\n") >= 0;
+
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ X509 *cert = sk_X509_value(certs, i);
+
+ if (cert != NULL) {
+ if (!ossl_x509_print_ex_brief(bio, cert, 0))
+ return 0;
+ if (!X509V3_extensions_print(bio, NULL,
+ X509_get0_extensions(cert),
+ X509_FLAG_EXTENSIONS_ONLY_KID, 8))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int print_store_certs(BIO *bio, X509_STORE *store)
+{
+ if (store != NULL) {
+ STACK_OF(X509) *certs = X509_STORE_get1_all_certs(store);
+ int ret = print_certs(bio, certs);
+
+ sk_X509_pop_free(certs, X509_free);
+ return ret;
+ } else {
+ return BIO_printf(bio, " (no trusted store)\n") >= 0;
+ }
+}
+
+/* Extend the error queue with details on a failed cert verification */
+int X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+ if (ok == 0 && ctx != NULL) {
+ int cert_error = X509_STORE_CTX_get_error(ctx);
+ BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */
+
+ BIO_printf(bio, "%s at depth = %d error = %d (%s)\n",
+ X509_STORE_CTX_get0_parent_ctx(ctx) != NULL
+ ? "CRL path validation"
+ : "Certificate verification",
+ X509_STORE_CTX_get_error_depth(ctx),
+ cert_error, X509_verify_cert_error_string(cert_error));
+ {
+ X509_STORE *ts = X509_STORE_CTX_get0_store(ctx);
+ X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
+ char *str;
+ int idx = 0;
+
+ switch (cert_error) {
+ case X509_V_ERR_HOSTNAME_MISMATCH:
+ BIO_printf(bio, "Expected hostname(s) = ");
+ while ((str = X509_VERIFY_PARAM_get0_host(vpm, idx++)) != NULL)
+ BIO_printf(bio, "%s%s", idx == 1 ? "" : ", ", str);
+ BIO_printf(bio, "\n");
+ break;
+ case X509_V_ERR_EMAIL_MISMATCH:
+ str = X509_VERIFY_PARAM_get0_email(vpm);
+ if (str != NULL)
+ BIO_printf(bio, "Expected email address = %s\n", str);
+ break;
+ case X509_V_ERR_IP_ADDRESS_MISMATCH:
+ str = X509_VERIFY_PARAM_get1_ip_asc(vpm);
+ if (str != NULL)
+ BIO_printf(bio, "Expected IP address = %s\n", str);
+ OPENSSL_free(str);
+ break;
+ default:
+ break;
+ }
+ }
+
+ BIO_printf(bio, "Failure for:\n");
+ ossl_x509_print_ex_brief(bio, X509_STORE_CTX_get_current_cert(ctx),
+ X509_FLAG_NO_EXTENSIONS);
+ if (cert_error == X509_V_ERR_CERT_UNTRUSTED
+ || cert_error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
+ || cert_error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
+ || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
+ || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+ || cert_error == X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
+ || cert_error == X509_V_ERR_STORE_LOOKUP) {
+ BIO_printf(bio, "Non-trusted certs:\n");
+ print_certs(bio, X509_STORE_CTX_get0_untrusted(ctx));
+ BIO_printf(bio, "Certs in trust store:\n");
+ print_store_certs(bio, X509_STORE_CTX_get0_store(ctx));
+ }
+ ERR_raise(ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED);
+ ERR_add_error_mem_bio("\n", bio);
+ BIO_free(bio);
+ }
+
+ return ok;
+}
diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c
new file mode 100644
index 000000000000..20f3d2ba70de
--- /dev/null
+++ b/crypto/x509/v3_addr.c
@@ -0,0 +1,1361 @@
+/*
+ * Copyright 2006-2024 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
+ */
+
+/*
+ * Implementation of RFC 3779 section 2.2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/buffer.h>
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+#include "ext_dat.h"
+#include "x509_local.h"
+
+#ifndef OPENSSL_NO_RFC3779
+
+/*
+ * OpenSSL ASN.1 template translation of RFC 3779 2.2.3.
+ */
+
+ASN1_SEQUENCE(IPAddressRange) = {
+ ASN1_SIMPLE(IPAddressRange, min, ASN1_BIT_STRING),
+ ASN1_SIMPLE(IPAddressRange, max, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(IPAddressRange)
+
+ASN1_CHOICE(IPAddressOrRange) = {
+ ASN1_SIMPLE(IPAddressOrRange, u.addressPrefix, ASN1_BIT_STRING),
+ ASN1_SIMPLE(IPAddressOrRange, u.addressRange, IPAddressRange)
+} ASN1_CHOICE_END(IPAddressOrRange)
+
+ASN1_CHOICE(IPAddressChoice) = {
+ ASN1_SIMPLE(IPAddressChoice, u.inherit, ASN1_NULL),
+ ASN1_SEQUENCE_OF(IPAddressChoice, u.addressesOrRanges, IPAddressOrRange)
+} ASN1_CHOICE_END(IPAddressChoice)
+
+ASN1_SEQUENCE(IPAddressFamily) = {
+ ASN1_SIMPLE(IPAddressFamily, addressFamily, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(IPAddressFamily, ipAddressChoice, IPAddressChoice)
+} ASN1_SEQUENCE_END(IPAddressFamily)
+
+ASN1_ITEM_TEMPLATE(IPAddrBlocks) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0,
+ IPAddrBlocks, IPAddressFamily)
+static_ASN1_ITEM_TEMPLATE_END(IPAddrBlocks)
+
+IMPLEMENT_ASN1_FUNCTIONS(IPAddressRange)
+IMPLEMENT_ASN1_FUNCTIONS(IPAddressOrRange)
+IMPLEMENT_ASN1_FUNCTIONS(IPAddressChoice)
+IMPLEMENT_ASN1_FUNCTIONS(IPAddressFamily)
+
+/*
+ * How much buffer space do we need for a raw address?
+ */
+#define ADDR_RAW_BUF_LEN 16
+
+/*
+ * What's the address length associated with this AFI?
+ */
+static int length_from_afi(const unsigned afi)
+{
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ return 4;
+ case IANA_AFI_IPV6:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Extract the AFI from an IPAddressFamily.
+ */
+unsigned int X509v3_addr_get_afi(const IPAddressFamily *f)
+{
+ if (f == NULL
+ || f->addressFamily == NULL
+ || f->addressFamily->data == NULL
+ || f->addressFamily->length < 2)
+ return 0;
+ return (f->addressFamily->data[0] << 8) | f->addressFamily->data[1];
+}
+
+/*
+ * Expand the bitstring form of an address into a raw byte array.
+ * At the moment this is coded for simplicity, not speed.
+ */
+static int addr_expand(unsigned char *addr,
+ const ASN1_BIT_STRING *bs,
+ const int length, const unsigned char fill)
+{
+ if (bs->length < 0 || bs->length > length)
+ return 0;
+ if (bs->length > 0) {
+ memcpy(addr, bs->data, bs->length);
+ if ((bs->flags & 7) != 0) {
+ unsigned char mask = 0xFF >> (8 - (bs->flags & 7));
+ if (fill == 0)
+ addr[bs->length - 1] &= ~mask;
+ else
+ addr[bs->length - 1] |= mask;
+ }
+ }
+ memset(addr + bs->length, fill, length - bs->length);
+ return 1;
+}
+
+/*
+ * Extract the prefix length from a bitstring.
+ */
+#define addr_prefixlen(bs) ((int) ((bs)->length * 8 - ((bs)->flags & 7)))
+
+/*
+ * i2r handler for one address bitstring.
+ */
+static int i2r_address(BIO *out,
+ const unsigned afi,
+ const unsigned char fill, const ASN1_BIT_STRING *bs)
+{
+ unsigned char addr[ADDR_RAW_BUF_LEN];
+ int i, n;
+
+ if (bs->length < 0)
+ return 0;
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ if (!addr_expand(addr, bs, 4, fill))
+ return 0;
+ BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
+ break;
+ case IANA_AFI_IPV6:
+ if (!addr_expand(addr, bs, 16, fill))
+ return 0;
+ for (n = 16; n > 1 && addr[n - 1] == 0x00 && addr[n - 2] == 0x00;
+ n -= 2) ;
+ for (i = 0; i < n; i += 2)
+ BIO_printf(out, "%x%s", (addr[i] << 8) | addr[i + 1],
+ (i < 14 ? ":" : ""));
+ if (i < 16)
+ BIO_puts(out, ":");
+ if (i == 0)
+ BIO_puts(out, ":");
+ break;
+ default:
+ for (i = 0; i < bs->length; i++)
+ BIO_printf(out, "%s%02x", (i > 0 ? ":" : ""), bs->data[i]);
+ BIO_printf(out, "[%d]", (int)(bs->flags & 7));
+ break;
+ }
+ return 1;
+}
+
+/*
+ * i2r handler for a sequence of addresses and ranges.
+ */
+static int i2r_IPAddressOrRanges(BIO *out,
+ const int indent,
+ const IPAddressOrRanges *aors,
+ const unsigned afi)
+{
+ int i;
+ for (i = 0; i < sk_IPAddressOrRange_num(aors); i++) {
+ const IPAddressOrRange *aor = sk_IPAddressOrRange_value(aors, i);
+ BIO_printf(out, "%*s", indent, "");
+ switch (aor->type) {
+ case IPAddressOrRange_addressPrefix:
+ if (!i2r_address(out, afi, 0x00, aor->u.addressPrefix))
+ return 0;
+ BIO_printf(out, "/%d\n", addr_prefixlen(aor->u.addressPrefix));
+ continue;
+ case IPAddressOrRange_addressRange:
+ if (!i2r_address(out, afi, 0x00, aor->u.addressRange->min))
+ return 0;
+ BIO_puts(out, "-");
+ if (!i2r_address(out, afi, 0xFF, aor->u.addressRange->max))
+ return 0;
+ BIO_puts(out, "\n");
+ continue;
+ }
+ }
+ return 1;
+}
+
+/*
+ * i2r handler for an IPAddrBlocks extension.
+ */
+static int i2r_IPAddrBlocks(const X509V3_EXT_METHOD *method,
+ void *ext, BIO *out, int indent)
+{
+ const IPAddrBlocks *addr = ext;
+ int i;
+ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
+ const unsigned int afi = X509v3_addr_get_afi(f);
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ BIO_printf(out, "%*sIPv4", indent, "");
+ break;
+ case IANA_AFI_IPV6:
+ BIO_printf(out, "%*sIPv6", indent, "");
+ break;
+ default:
+ BIO_printf(out, "%*sUnknown AFI %u", indent, "", afi);
+ break;
+ }
+ if (f->addressFamily->length > 2) {
+ switch (f->addressFamily->data[2]) {
+ case 1:
+ BIO_puts(out, " (Unicast)");
+ break;
+ case 2:
+ BIO_puts(out, " (Multicast)");
+ break;
+ case 3:
+ BIO_puts(out, " (Unicast/Multicast)");
+ break;
+ case 4:
+ BIO_puts(out, " (MPLS)");
+ break;
+ case 64:
+ BIO_puts(out, " (Tunnel)");
+ break;
+ case 65:
+ BIO_puts(out, " (VPLS)");
+ break;
+ case 66:
+ BIO_puts(out, " (BGP MDT)");
+ break;
+ case 128:
+ BIO_puts(out, " (MPLS-labeled VPN)");
+ break;
+ default:
+ BIO_printf(out, " (Unknown SAFI %u)",
+ (unsigned)f->addressFamily->data[2]);
+ break;
+ }
+ }
+ switch (f->ipAddressChoice->type) {
+ case IPAddressChoice_inherit:
+ BIO_puts(out, ": inherit\n");
+ break;
+ case IPAddressChoice_addressesOrRanges:
+ BIO_puts(out, ":\n");
+ if (!i2r_IPAddressOrRanges(out,
+ indent + 2,
+ f->ipAddressChoice->
+ u.addressesOrRanges, afi))
+ return 0;
+ break;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Sort comparison function for a sequence of IPAddressOrRange
+ * elements.
+ *
+ * There's no sane answer we can give if addr_expand() fails, and an
+ * assertion failure on externally supplied data is seriously uncool,
+ * so we just arbitrarily declare that if given invalid inputs this
+ * function returns -1. If this messes up your preferred sort order
+ * for garbage input, tough noogies.
+ */
+static int IPAddressOrRange_cmp(const IPAddressOrRange *a,
+ const IPAddressOrRange *b, const int length)
+{
+ unsigned char addr_a[ADDR_RAW_BUF_LEN], addr_b[ADDR_RAW_BUF_LEN];
+ int prefixlen_a = 0, prefixlen_b = 0;
+ int r;
+
+ switch (a->type) {
+ case IPAddressOrRange_addressPrefix:
+ if (!addr_expand(addr_a, a->u.addressPrefix, length, 0x00))
+ return -1;
+ prefixlen_a = addr_prefixlen(a->u.addressPrefix);
+ break;
+ case IPAddressOrRange_addressRange:
+ if (!addr_expand(addr_a, a->u.addressRange->min, length, 0x00))
+ return -1;
+ prefixlen_a = length * 8;
+ break;
+ }
+
+ switch (b->type) {
+ case IPAddressOrRange_addressPrefix:
+ if (!addr_expand(addr_b, b->u.addressPrefix, length, 0x00))
+ return -1;
+ prefixlen_b = addr_prefixlen(b->u.addressPrefix);
+ break;
+ case IPAddressOrRange_addressRange:
+ if (!addr_expand(addr_b, b->u.addressRange->min, length, 0x00))
+ return -1;
+ prefixlen_b = length * 8;
+ break;
+ }
+
+ if ((r = memcmp(addr_a, addr_b, length)) != 0)
+ return r;
+ else
+ return prefixlen_a - prefixlen_b;
+}
+
+/*
+ * IPv4-specific closure over IPAddressOrRange_cmp, since sk_sort()
+ * comparison routines are only allowed two arguments.
+ */
+static int v4IPAddressOrRange_cmp(const IPAddressOrRange *const *a,
+ const IPAddressOrRange *const *b)
+{
+ return IPAddressOrRange_cmp(*a, *b, 4);
+}
+
+/*
+ * IPv6-specific closure over IPAddressOrRange_cmp, since sk_sort()
+ * comparison routines are only allowed two arguments.
+ */
+static int v6IPAddressOrRange_cmp(const IPAddressOrRange *const *a,
+ const IPAddressOrRange *const *b)
+{
+ return IPAddressOrRange_cmp(*a, *b, 16);
+}
+
+/*
+ * Calculate whether a range collapses to a prefix.
+ * See last paragraph of RFC 3779 2.2.3.7.
+ */
+static int range_should_be_prefix(const unsigned char *min,
+ const unsigned char *max, const int length)
+{
+ unsigned char mask;
+ int i, j;
+
+ /*
+ * It is the responsibility of the caller to confirm min <= max. We don't
+ * use ossl_assert() here since we have no way of signalling an error from
+ * this function - so we just use a plain assert instead.
+ */
+ assert(memcmp(min, max, length) <= 0);
+
+ for (i = 0; i < length && min[i] == max[i]; i++) ;
+ for (j = length - 1; j >= 0 && min[j] == 0x00 && max[j] == 0xFF; j--) ;
+ if (i < j)
+ return -1;
+ if (i > j)
+ return i * 8;
+ mask = min[i] ^ max[i];
+ switch (mask) {
+ case 0x01:
+ j = 7;
+ break;
+ case 0x03:
+ j = 6;
+ break;
+ case 0x07:
+ j = 5;
+ break;
+ case 0x0F:
+ j = 4;
+ break;
+ case 0x1F:
+ j = 3;
+ break;
+ case 0x3F:
+ j = 2;
+ break;
+ case 0x7F:
+ j = 1;
+ break;
+ default:
+ return -1;
+ }
+ if ((min[i] & mask) != 0 || (max[i] & mask) != mask)
+ return -1;
+ else
+ return i * 8 + j;
+}
+
+/*
+ * Construct a prefix.
+ */
+static int make_addressPrefix(IPAddressOrRange **result, unsigned char *addr,
+ const int prefixlen, const int afilen)
+{
+ int bytelen = (prefixlen + 7) / 8, bitlen = prefixlen % 8;
+ IPAddressOrRange *aor;
+
+ if (prefixlen < 0 || prefixlen > (afilen * 8))
+ return 0;
+ if ((aor = IPAddressOrRange_new()) == NULL)
+ return 0;
+ aor->type = IPAddressOrRange_addressPrefix;
+ if (aor->u.addressPrefix == NULL &&
+ (aor->u.addressPrefix = ASN1_BIT_STRING_new()) == NULL)
+ goto err;
+ if (!ASN1_BIT_STRING_set(aor->u.addressPrefix, addr, bytelen))
+ goto err;
+ aor->u.addressPrefix->flags &= ~7;
+ aor->u.addressPrefix->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ if (bitlen > 0) {
+ aor->u.addressPrefix->data[bytelen - 1] &= ~(0xFF >> bitlen);
+ aor->u.addressPrefix->flags |= 8 - bitlen;
+ }
+
+ *result = aor;
+ return 1;
+
+ err:
+ IPAddressOrRange_free(aor);
+ return 0;
+}
+
+/*
+ * Construct a range. If it can be expressed as a prefix,
+ * return a prefix instead. Doing this here simplifies
+ * the rest of the code considerably.
+ */
+static int make_addressRange(IPAddressOrRange **result,
+ unsigned char *min,
+ unsigned char *max, const int length)
+{
+ IPAddressOrRange *aor;
+ int i, prefixlen;
+
+ if (memcmp(min, max, length) > 0)
+ return 0;
+
+ if ((prefixlen = range_should_be_prefix(min, max, length)) >= 0)
+ return make_addressPrefix(result, min, prefixlen, length);
+
+ if ((aor = IPAddressOrRange_new()) == NULL)
+ return 0;
+ aor->type = IPAddressOrRange_addressRange;
+ if ((aor->u.addressRange = IPAddressRange_new()) == NULL)
+ goto err;
+ if (aor->u.addressRange->min == NULL &&
+ (aor->u.addressRange->min = ASN1_BIT_STRING_new()) == NULL)
+ goto err;
+ if (aor->u.addressRange->max == NULL &&
+ (aor->u.addressRange->max = ASN1_BIT_STRING_new()) == NULL)
+ goto err;
+
+ for (i = length; i > 0 && min[i - 1] == 0x00; --i) ;
+ if (!ASN1_BIT_STRING_set(aor->u.addressRange->min, min, i))
+ goto err;
+ aor->u.addressRange->min->flags &= ~7;
+ aor->u.addressRange->min->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ if (i > 0) {
+ unsigned char b = min[i - 1];
+ int j = 1;
+ while ((b & (0xFFU >> j)) != 0)
+ ++j;
+ aor->u.addressRange->min->flags |= 8 - j;
+ }
+
+ for (i = length; i > 0 && max[i - 1] == 0xFF; --i) ;
+ if (!ASN1_BIT_STRING_set(aor->u.addressRange->max, max, i))
+ goto err;
+ aor->u.addressRange->max->flags &= ~7;
+ aor->u.addressRange->max->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ if (i > 0) {
+ unsigned char b = max[i - 1];
+ int j = 1;
+ while ((b & (0xFFU >> j)) != (0xFFU >> j))
+ ++j;
+ aor->u.addressRange->max->flags |= 8 - j;
+ }
+
+ *result = aor;
+ return 1;
+
+ err:
+ IPAddressOrRange_free(aor);
+ return 0;
+}
+
+/*
+ * Construct a new address family or find an existing one.
+ */
+static IPAddressFamily *make_IPAddressFamily(IPAddrBlocks *addr,
+ const unsigned afi,
+ const unsigned *safi)
+{
+ IPAddressFamily *f;
+ unsigned char key[3];
+ int keylen;
+ int i;
+
+ key[0] = (afi >> 8) & 0xFF;
+ key[1] = afi & 0xFF;
+ if (safi != NULL) {
+ key[2] = *safi & 0xFF;
+ keylen = 3;
+ } else {
+ keylen = 2;
+ }
+
+ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
+ f = sk_IPAddressFamily_value(addr, i);
+ if (f->addressFamily->length == keylen &&
+ !memcmp(f->addressFamily->data, key, keylen))
+ return f;
+ }
+
+ if ((f = IPAddressFamily_new()) == NULL)
+ goto err;
+ if (f->ipAddressChoice == NULL &&
+ (f->ipAddressChoice = IPAddressChoice_new()) == NULL)
+ goto err;
+ if (f->addressFamily == NULL &&
+ (f->addressFamily = ASN1_OCTET_STRING_new()) == NULL)
+ goto err;
+ if (!ASN1_OCTET_STRING_set(f->addressFamily, key, keylen))
+ goto err;
+ if (!sk_IPAddressFamily_push(addr, f))
+ goto err;
+
+ return f;
+
+ err:
+ IPAddressFamily_free(f);
+ return NULL;
+}
+
+/*
+ * Add an inheritance element.
+ */
+int X509v3_addr_add_inherit(IPAddrBlocks *addr,
+ const unsigned afi, const unsigned *safi)
+{
+ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi);
+ if (f == NULL ||
+ f->ipAddressChoice == NULL ||
+ (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges &&
+ f->ipAddressChoice->u.addressesOrRanges != NULL))
+ return 0;
+ if (f->ipAddressChoice->type == IPAddressChoice_inherit &&
+ f->ipAddressChoice->u.inherit != NULL)
+ return 1;
+ if (f->ipAddressChoice->u.inherit == NULL &&
+ (f->ipAddressChoice->u.inherit = ASN1_NULL_new()) == NULL)
+ return 0;
+ f->ipAddressChoice->type = IPAddressChoice_inherit;
+ return 1;
+}
+
+/*
+ * Construct an IPAddressOrRange sequence, or return an existing one.
+ */
+static IPAddressOrRanges *make_prefix_or_range(IPAddrBlocks *addr,
+ const unsigned afi,
+ const unsigned *safi)
+{
+ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi);
+ IPAddressOrRanges *aors = NULL;
+
+ if (f == NULL ||
+ f->ipAddressChoice == NULL ||
+ (f->ipAddressChoice->type == IPAddressChoice_inherit &&
+ f->ipAddressChoice->u.inherit != NULL))
+ return NULL;
+ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges)
+ aors = f->ipAddressChoice->u.addressesOrRanges;
+ if (aors != NULL)
+ return aors;
+ if ((aors = sk_IPAddressOrRange_new_null()) == NULL)
+ return NULL;
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ (void)sk_IPAddressOrRange_set_cmp_func(aors, v4IPAddressOrRange_cmp);
+ break;
+ case IANA_AFI_IPV6:
+ (void)sk_IPAddressOrRange_set_cmp_func(aors, v6IPAddressOrRange_cmp);
+ break;
+ }
+ f->ipAddressChoice->type = IPAddressChoice_addressesOrRanges;
+ f->ipAddressChoice->u.addressesOrRanges = aors;
+ return aors;
+}
+
+/*
+ * Add a prefix.
+ */
+int X509v3_addr_add_prefix(IPAddrBlocks *addr,
+ const unsigned afi,
+ const unsigned *safi,
+ unsigned char *a, const int prefixlen)
+{
+ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi);
+ IPAddressOrRange *aor;
+
+ if (aors == NULL
+ || !make_addressPrefix(&aor, a, prefixlen, length_from_afi(afi)))
+ return 0;
+ if (sk_IPAddressOrRange_push(aors, aor))
+ return 1;
+ IPAddressOrRange_free(aor);
+ return 0;
+}
+
+/*
+ * Add a range.
+ */
+int X509v3_addr_add_range(IPAddrBlocks *addr,
+ const unsigned afi,
+ const unsigned *safi,
+ unsigned char *min, unsigned char *max)
+{
+ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi);
+ IPAddressOrRange *aor;
+ int length = length_from_afi(afi);
+ if (aors == NULL)
+ return 0;
+ if (!make_addressRange(&aor, min, max, length))
+ return 0;
+ if (sk_IPAddressOrRange_push(aors, aor))
+ return 1;
+ IPAddressOrRange_free(aor);
+ return 0;
+}
+
+/*
+ * Extract min and max values from an IPAddressOrRange.
+ */
+static int extract_min_max(IPAddressOrRange *aor,
+ unsigned char *min, unsigned char *max, int length)
+{
+ if (aor == NULL || min == NULL || max == NULL)
+ return 0;
+ switch (aor->type) {
+ case IPAddressOrRange_addressPrefix:
+ return (addr_expand(min, aor->u.addressPrefix, length, 0x00) &&
+ addr_expand(max, aor->u.addressPrefix, length, 0xFF));
+ case IPAddressOrRange_addressRange:
+ return (addr_expand(min, aor->u.addressRange->min, length, 0x00) &&
+ addr_expand(max, aor->u.addressRange->max, length, 0xFF));
+ }
+ return 0;
+}
+
+/*
+ * Public wrapper for extract_min_max().
+ */
+int X509v3_addr_get_range(IPAddressOrRange *aor,
+ const unsigned afi,
+ unsigned char *min,
+ unsigned char *max, const int length)
+{
+ int afi_length = length_from_afi(afi);
+ if (aor == NULL || min == NULL || max == NULL ||
+ afi_length == 0 || length < afi_length ||
+ (aor->type != IPAddressOrRange_addressPrefix &&
+ aor->type != IPAddressOrRange_addressRange) ||
+ !extract_min_max(aor, min, max, afi_length))
+ return 0;
+
+ return afi_length;
+}
+
+/*
+ * Sort comparison function for a sequence of IPAddressFamily.
+ *
+ * The last paragraph of RFC 3779 2.2.3.3 is slightly ambiguous about
+ * the ordering: I can read it as meaning that IPv6 without a SAFI
+ * comes before IPv4 with a SAFI, which seems pretty weird. The
+ * examples in appendix B suggest that the author intended the
+ * null-SAFI rule to apply only within a single AFI, which is what I
+ * would have expected and is what the following code implements.
+ */
+static int IPAddressFamily_cmp(const IPAddressFamily *const *a_,
+ const IPAddressFamily *const *b_)
+{
+ const ASN1_OCTET_STRING *a = (*a_)->addressFamily;
+ const ASN1_OCTET_STRING *b = (*b_)->addressFamily;
+ int len = ((a->length <= b->length) ? a->length : b->length);
+ int cmp = memcmp(a->data, b->data, len);
+ return cmp ? cmp : a->length - b->length;
+}
+
+static int IPAddressFamily_check_len(const IPAddressFamily *f)
+{
+ if (f->addressFamily->length < 2 || f->addressFamily->length > 3)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Check whether an IPAddrBLocks is in canonical form.
+ */
+int X509v3_addr_is_canonical(IPAddrBlocks *addr)
+{
+ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
+ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
+ IPAddressOrRanges *aors;
+ int i, j, k;
+
+ /*
+ * Empty extension is canonical.
+ */
+ if (addr == NULL)
+ return 1;
+
+ /*
+ * Check whether the top-level list is in order.
+ */
+ for (i = 0; i < sk_IPAddressFamily_num(addr) - 1; i++) {
+ const IPAddressFamily *a = sk_IPAddressFamily_value(addr, i);
+ const IPAddressFamily *b = sk_IPAddressFamily_value(addr, i + 1);
+
+ if (!IPAddressFamily_check_len(a) || !IPAddressFamily_check_len(b))
+ return 0;
+
+ if (IPAddressFamily_cmp(&a, &b) >= 0)
+ return 0;
+ }
+
+ /*
+ * Top level's ok, now check each address family.
+ */
+ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
+ int length = length_from_afi(X509v3_addr_get_afi(f));
+
+ /*
+ * Inheritance is canonical. Anything other than inheritance or
+ * a SEQUENCE OF IPAddressOrRange is an ASN.1 error or something.
+ */
+ if (f == NULL || f->ipAddressChoice == NULL)
+ return 0;
+ switch (f->ipAddressChoice->type) {
+ case IPAddressChoice_inherit:
+ continue;
+ case IPAddressChoice_addressesOrRanges:
+ break;
+ default:
+ return 0;
+ }
+
+ if (!IPAddressFamily_check_len(f))
+ return 0;
+
+ /*
+ * It's an IPAddressOrRanges sequence, check it.
+ */
+ aors = f->ipAddressChoice->u.addressesOrRanges;
+ if (sk_IPAddressOrRange_num(aors) == 0)
+ return 0;
+ for (j = 0; j < sk_IPAddressOrRange_num(aors) - 1; j++) {
+ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
+ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1);
+
+ if (!extract_min_max(a, a_min, a_max, length) ||
+ !extract_min_max(b, b_min, b_max, length))
+ return 0;
+
+ /*
+ * Punt misordered list, overlapping start, or inverted range.
+ */
+ if (memcmp(a_min, b_min, length) >= 0 ||
+ memcmp(a_min, a_max, length) > 0 ||
+ memcmp(b_min, b_max, length) > 0)
+ return 0;
+
+ /*
+ * Punt if adjacent or overlapping. Check for adjacency by
+ * subtracting one from b_min first.
+ */
+ for (k = length - 1; k >= 0 && b_min[k]-- == 0x00; k--) ;
+ if (memcmp(a_max, b_min, length) >= 0)
+ return 0;
+
+ /*
+ * Check for range that should be expressed as a prefix.
+ */
+ if (a->type == IPAddressOrRange_addressRange &&
+ range_should_be_prefix(a_min, a_max, length) >= 0)
+ return 0;
+ }
+
+ /*
+ * Check range to see if it's inverted or should be a
+ * prefix.
+ */
+ j = sk_IPAddressOrRange_num(aors) - 1;
+ {
+ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
+ if (a != NULL && a->type == IPAddressOrRange_addressRange) {
+ if (!extract_min_max(a, a_min, a_max, length))
+ return 0;
+ if (memcmp(a_min, a_max, length) > 0 ||
+ range_should_be_prefix(a_min, a_max, length) >= 0)
+ return 0;
+ }
+ }
+ }
+
+ /*
+ * If we made it through all that, we're happy.
+ */
+ return 1;
+}
+
+/*
+ * Whack an IPAddressOrRanges into canonical form.
+ */
+static int IPAddressOrRanges_canonize(IPAddressOrRanges *aors,
+ const unsigned afi)
+{
+ int i, j, length = length_from_afi(afi);
+
+ /*
+ * Sort the IPAddressOrRanges sequence.
+ */
+ sk_IPAddressOrRange_sort(aors);
+
+ /*
+ * Clean up representation issues, punt on duplicates or overlaps.
+ */
+ for (i = 0; i < sk_IPAddressOrRange_num(aors) - 1; i++) {
+ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, i);
+ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, i + 1);
+ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
+ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
+
+ if (!extract_min_max(a, a_min, a_max, length) ||
+ !extract_min_max(b, b_min, b_max, length))
+ return 0;
+
+ /*
+ * Punt inverted ranges.
+ */
+ if (memcmp(a_min, a_max, length) > 0 ||
+ memcmp(b_min, b_max, length) > 0)
+ return 0;
+
+ /*
+ * Punt overlaps.
+ */
+ if (memcmp(a_max, b_min, length) >= 0)
+ return 0;
+
+ /*
+ * Merge if a and b are adjacent. We check for
+ * adjacency by subtracting one from b_min first.
+ */
+ for (j = length - 1; j >= 0 && b_min[j]-- == 0x00; j--) ;
+ if (memcmp(a_max, b_min, length) == 0) {
+ IPAddressOrRange *merged;
+ if (!make_addressRange(&merged, a_min, b_max, length))
+ return 0;
+ (void)sk_IPAddressOrRange_set(aors, i, merged);
+ (void)sk_IPAddressOrRange_delete(aors, i + 1);
+ IPAddressOrRange_free(a);
+ IPAddressOrRange_free(b);
+ --i;
+ continue;
+ }
+ }
+
+ /*
+ * Check for inverted final range.
+ */
+ j = sk_IPAddressOrRange_num(aors) - 1;
+ {
+ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
+ if (a != NULL && a->type == IPAddressOrRange_addressRange) {
+ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
+ if (!extract_min_max(a, a_min, a_max, length))
+ return 0;
+ if (memcmp(a_min, a_max, length) > 0)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Whack an IPAddrBlocks extension into canonical form.
+ */
+int X509v3_addr_canonize(IPAddrBlocks *addr)
+{
+ int i;
+ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
+
+ if (!IPAddressFamily_check_len(f))
+ return 0;
+
+ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges &&
+ !IPAddressOrRanges_canonize(f->ipAddressChoice->
+ u.addressesOrRanges,
+ X509v3_addr_get_afi(f)))
+ return 0;
+ }
+ (void)sk_IPAddressFamily_set_cmp_func(addr, IPAddressFamily_cmp);
+ sk_IPAddressFamily_sort(addr);
+ if (!ossl_assert(X509v3_addr_is_canonical(addr)))
+ return 0;
+ return 1;
+}
+
+/*
+ * v2i handler for the IPAddrBlocks extension.
+ */
+static void *v2i_IPAddrBlocks(const struct v3_ext_method *method,
+ struct v3_ext_ctx *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ static const char v4addr_chars[] = "0123456789.";
+ static const char v6addr_chars[] = "0123456789.:abcdefABCDEF";
+ IPAddrBlocks *addr = NULL;
+ char *s = NULL, *t;
+ int i;
+
+ if ((addr = sk_IPAddressFamily_new(IPAddressFamily_cmp)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ CONF_VALUE *val = sk_CONF_VALUE_value(values, i);
+ unsigned char min[ADDR_RAW_BUF_LEN], max[ADDR_RAW_BUF_LEN];
+ unsigned afi, *safi = NULL, safi_;
+ const char *addr_chars = NULL;
+ int prefixlen, i1, i2, delim, length;
+
+ if (!ossl_v3_name_cmp(val->name, "IPv4")) {
+ afi = IANA_AFI_IPV4;
+ } else if (!ossl_v3_name_cmp(val->name, "IPv6")) {
+ afi = IANA_AFI_IPV6;
+ } else if (!ossl_v3_name_cmp(val->name, "IPv4-SAFI")) {
+ afi = IANA_AFI_IPV4;
+ safi = &safi_;
+ } else if (!ossl_v3_name_cmp(val->name, "IPv6-SAFI")) {
+ afi = IANA_AFI_IPV6;
+ safi = &safi_;
+ } else {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR,
+ "%s", val->name);
+ goto err;
+ }
+
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ addr_chars = v4addr_chars;
+ break;
+ case IANA_AFI_IPV6:
+ addr_chars = v6addr_chars;
+ break;
+ }
+
+ length = length_from_afi(afi);
+
+ /*
+ * Handle SAFI, if any, and OPENSSL_strdup() so we can null-terminate
+ * the other input values.
+ */
+ if (safi != NULL) {
+ if (val->value == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE);
+ goto err;
+ }
+ *safi = strtoul(val->value, &t, 0);
+ t += strspn(t, " \t");
+ if (*safi > 0xFF || *t++ != ':') {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SAFI);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ t += strspn(t, " \t");
+ s = OPENSSL_strdup(t);
+ } else {
+ s = OPENSSL_strdup(val->value);
+ }
+ if (s == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /*
+ * Check for inheritance. Not worth additional complexity to
+ * optimize this (seldom-used) case.
+ */
+ if (strcmp(s, "inherit") == 0) {
+ if (!X509v3_addr_add_inherit(addr, afi, safi)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_INHERITANCE);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ OPENSSL_free(s);
+ s = NULL;
+ continue;
+ }
+
+ i1 = strspn(s, addr_chars);
+ i2 = i1 + strspn(s + i1, " \t");
+ delim = s[i2++];
+ s[i1] = '\0';
+
+ if (ossl_a2i_ipadd(min, s) != length) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_IPADDRESS);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+
+ switch (delim) {
+ case '/':
+ prefixlen = (int)strtoul(s + i2, &t, 10);
+ if (t == s + i2
+ || *t != '\0'
+ || prefixlen > (length * 8)
+ || prefixlen < 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ if (!X509v3_addr_add_prefix(addr, afi, safi, min, prefixlen)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ break;
+ case '-':
+ i1 = i2 + strspn(s + i2, " \t");
+ i2 = i1 + strspn(s + i1, addr_chars);
+ if (i1 == i2 || s[i2] != '\0') {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ if (ossl_a2i_ipadd(max, s + i1) != length) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_IPADDRESS);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ if (memcmp(min, max, length_from_afi(afi)) > 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ if (!X509v3_addr_add_range(addr, afi, safi, min, max)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ break;
+ case '\0':
+ if (!X509v3_addr_add_prefix(addr, afi, safi, min, length * 8)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ break;
+ default:
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+
+ OPENSSL_free(s);
+ s = NULL;
+ }
+
+ /*
+ * Canonize the result, then we're done.
+ */
+ if (!X509v3_addr_canonize(addr))
+ goto err;
+ return addr;
+
+ err:
+ OPENSSL_free(s);
+ sk_IPAddressFamily_pop_free(addr, IPAddressFamily_free);
+ return NULL;
+}
+
+/*
+ * OpenSSL dispatch
+ */
+const X509V3_EXT_METHOD ossl_v3_addr = {
+ NID_sbgp_ipAddrBlock, /* nid */
+ 0, /* flags */
+ ASN1_ITEM_ref(IPAddrBlocks), /* template */
+ 0, 0, 0, 0, /* old functions, ignored */
+ 0, /* i2s */
+ 0, /* s2i */
+ 0, /* i2v */
+ v2i_IPAddrBlocks, /* v2i */
+ i2r_IPAddrBlocks, /* i2r */
+ 0, /* r2i */
+ NULL /* extension-specific data */
+};
+
+/*
+ * Figure out whether extension sues inheritance.
+ */
+int X509v3_addr_inherits(IPAddrBlocks *addr)
+{
+ int i;
+ if (addr == NULL)
+ return 0;
+ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
+ if (f->ipAddressChoice->type == IPAddressChoice_inherit)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Figure out whether parent contains child.
+ */
+static int addr_contains(IPAddressOrRanges *parent,
+ IPAddressOrRanges *child, int length)
+{
+ unsigned char p_min[ADDR_RAW_BUF_LEN], p_max[ADDR_RAW_BUF_LEN];
+ unsigned char c_min[ADDR_RAW_BUF_LEN], c_max[ADDR_RAW_BUF_LEN];
+ int p, c;
+
+ if (child == NULL || parent == child)
+ return 1;
+ if (parent == NULL)
+ return 0;
+
+ p = 0;
+ for (c = 0; c < sk_IPAddressOrRange_num(child); c++) {
+ if (!extract_min_max(sk_IPAddressOrRange_value(child, c),
+ c_min, c_max, length))
+ return 0;
+ for (;; p++) {
+ if (p >= sk_IPAddressOrRange_num(parent))
+ return 0;
+ if (!extract_min_max(sk_IPAddressOrRange_value(parent, p),
+ p_min, p_max, length))
+ return 0;
+ if (memcmp(p_max, c_max, length) < 0)
+ continue;
+ if (memcmp(p_min, c_min, length) > 0)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Test whether a is a subset of b.
+ */
+int X509v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b)
+{
+ int i;
+ if (a == NULL || a == b)
+ return 1;
+ if (b == NULL || X509v3_addr_inherits(a) || X509v3_addr_inherits(b))
+ return 0;
+ (void)sk_IPAddressFamily_set_cmp_func(b, IPAddressFamily_cmp);
+ for (i = 0; i < sk_IPAddressFamily_num(a); i++) {
+ IPAddressFamily *fa = sk_IPAddressFamily_value(a, i);
+ int j = sk_IPAddressFamily_find(b, fa);
+ IPAddressFamily *fb = sk_IPAddressFamily_value(b, j);
+
+ if (fb == NULL)
+ return 0;
+ if (!IPAddressFamily_check_len(fa) || !IPAddressFamily_check_len(fb))
+ return 0;
+ if (!addr_contains(fb->ipAddressChoice->u.addressesOrRanges,
+ fa->ipAddressChoice->u.addressesOrRanges,
+ length_from_afi(X509v3_addr_get_afi(fb))))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Validation error handling via callback.
+ */
+# define validation_err(_err_) \
+ do { \
+ if (ctx != NULL) { \
+ ctx->error = _err_; \
+ ctx->error_depth = i; \
+ ctx->current_cert = x; \
+ rv = ctx->verify_cb(0, ctx); \
+ } else { \
+ rv = 0; \
+ } \
+ if (rv == 0) \
+ goto done; \
+ } while (0)
+
+/*
+ * Core code for RFC 3779 2.3 path validation.
+ *
+ * Returns 1 for success, 0 on error.
+ *
+ * When returning 0, ctx->error MUST be set to an appropriate value other than
+ * X509_V_OK.
+ */
+static int addr_validate_path_internal(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *chain,
+ IPAddrBlocks *ext)
+{
+ IPAddrBlocks *child = NULL;
+ int i, j, ret = 0, rv;
+ X509 *x;
+
+ if (!ossl_assert(chain != NULL && sk_X509_num(chain) > 0)
+ || !ossl_assert(ctx != NULL || ext != NULL)
+ || !ossl_assert(ctx == NULL || ctx->verify_cb != NULL)) {
+ if (ctx != NULL)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+
+ /*
+ * Figure out where to start. If we don't have an extension to
+ * check, we're done. Otherwise, check canonical form and
+ * set up for walking up the chain.
+ */
+ if (ext != NULL) {
+ i = -1;
+ x = NULL;
+ } else {
+ i = 0;
+ x = sk_X509_value(chain, i);
+ if ((ext = x->rfc3779_addr) == NULL)
+ return 1; /* Return success */
+ }
+ if (!X509v3_addr_is_canonical(ext))
+ validation_err(X509_V_ERR_INVALID_EXTENSION);
+ (void)sk_IPAddressFamily_set_cmp_func(ext, IPAddressFamily_cmp);
+ if ((child = sk_IPAddressFamily_dup(ext)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ if (ctx != NULL)
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ goto done;
+ }
+
+ /*
+ * Now walk up the chain. No cert may list resources that its
+ * parent doesn't list.
+ */
+ for (i++; i < sk_X509_num(chain); i++) {
+ x = sk_X509_value(chain, i);
+ if (!X509v3_addr_is_canonical(x->rfc3779_addr))
+ validation_err(X509_V_ERR_INVALID_EXTENSION);
+ if (x->rfc3779_addr == NULL) {
+ for (j = 0; j < sk_IPAddressFamily_num(child); j++) {
+ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j);
+
+ if (!IPAddressFamily_check_len(fc))
+ goto done;
+
+ if (fc->ipAddressChoice->type != IPAddressChoice_inherit) {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ break;
+ }
+ }
+ continue;
+ }
+ (void)sk_IPAddressFamily_set_cmp_func(x->rfc3779_addr,
+ IPAddressFamily_cmp);
+ for (j = 0; j < sk_IPAddressFamily_num(child); j++) {
+ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j);
+ int k = sk_IPAddressFamily_find(x->rfc3779_addr, fc);
+ IPAddressFamily *fp =
+ sk_IPAddressFamily_value(x->rfc3779_addr, k);
+
+ if (fp == NULL) {
+ if (fc->ipAddressChoice->type ==
+ IPAddressChoice_addressesOrRanges) {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ break;
+ }
+ continue;
+ }
+
+ if (!IPAddressFamily_check_len(fc) || !IPAddressFamily_check_len(fp))
+ goto done;
+
+ if (fp->ipAddressChoice->type ==
+ IPAddressChoice_addressesOrRanges) {
+ if (fc->ipAddressChoice->type == IPAddressChoice_inherit
+ || addr_contains(fp->ipAddressChoice->u.addressesOrRanges,
+ fc->ipAddressChoice->u.addressesOrRanges,
+ length_from_afi(X509v3_addr_get_afi(fc))))
+ (void)sk_IPAddressFamily_set(child, j, fp);
+ else
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ }
+ }
+ }
+
+ /*
+ * Trust anchor can't inherit.
+ */
+ if (x->rfc3779_addr != NULL) {
+ for (j = 0; j < sk_IPAddressFamily_num(x->rfc3779_addr); j++) {
+ IPAddressFamily *fp = sk_IPAddressFamily_value(x->rfc3779_addr, j);
+
+ if (!IPAddressFamily_check_len(fp))
+ goto done;
+
+ if (fp->ipAddressChoice->type == IPAddressChoice_inherit
+ && sk_IPAddressFamily_find(child, fp) >= 0)
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ }
+ }
+ ret = 1;
+ done:
+ sk_IPAddressFamily_free(child);
+ return ret;
+}
+
+#undef validation_err
+
+/*
+ * RFC 3779 2.3 path validation -- called from X509_verify_cert().
+ */
+int X509v3_addr_validate_path(X509_STORE_CTX *ctx)
+{
+ if (ctx->chain == NULL
+ || sk_X509_num(ctx->chain) == 0
+ || ctx->verify_cb == NULL) {
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+ return addr_validate_path_internal(ctx, ctx->chain, NULL);
+}
+
+/*
+ * RFC 3779 2.3 path validation of an extension.
+ * Test whether chain covers extension.
+ */
+int X509v3_addr_validate_resource_set(STACK_OF(X509) *chain,
+ IPAddrBlocks *ext, int allow_inheritance)
+{
+ if (ext == NULL)
+ return 1;
+ if (chain == NULL || sk_X509_num(chain) == 0)
+ return 0;
+ if (!allow_inheritance && X509v3_addr_inherits(ext))
+ return 0;
+ return addr_validate_path_internal(NULL, chain, ext);
+}
+
+#endif /* OPENSSL_NO_RFC3779 */
diff --git a/crypto/x509/v3_admis.c b/crypto/x509/v3_admis.c
new file mode 100644
index 000000000000..53259c29f569
--- /dev/null
+++ b/crypto/x509/v3_admis.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2017-2023 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/types.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+#include <openssl/x509v3.h>
+
+#include <openssl/safestack.h>
+
+#include "v3_admis.h"
+#include "ext_dat.h"
+
+ASN1_SEQUENCE(NAMING_AUTHORITY) = {
+ ASN1_OPT(NAMING_AUTHORITY, namingAuthorityId, ASN1_OBJECT),
+ ASN1_OPT(NAMING_AUTHORITY, namingAuthorityUrl, ASN1_IA5STRING),
+ ASN1_OPT(NAMING_AUTHORITY, namingAuthorityText, DIRECTORYSTRING),
+} ASN1_SEQUENCE_END(NAMING_AUTHORITY)
+
+ASN1_SEQUENCE(PROFESSION_INFO) = {
+ ASN1_EXP_OPT(PROFESSION_INFO, namingAuthority, NAMING_AUTHORITY, 0),
+ ASN1_SEQUENCE_OF(PROFESSION_INFO, professionItems, DIRECTORYSTRING),
+ ASN1_SEQUENCE_OF_OPT(PROFESSION_INFO, professionOIDs, ASN1_OBJECT),
+ ASN1_OPT(PROFESSION_INFO, registrationNumber, ASN1_PRINTABLESTRING),
+ ASN1_OPT(PROFESSION_INFO, addProfessionInfo, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(PROFESSION_INFO)
+
+ASN1_SEQUENCE(ADMISSIONS) = {
+ ASN1_EXP_OPT(ADMISSIONS, admissionAuthority, GENERAL_NAME, 0),
+ ASN1_EXP_OPT(ADMISSIONS, namingAuthority, NAMING_AUTHORITY, 1),
+ ASN1_SEQUENCE_OF(ADMISSIONS, professionInfos, PROFESSION_INFO),
+} ASN1_SEQUENCE_END(ADMISSIONS)
+
+ASN1_SEQUENCE(ADMISSION_SYNTAX) = {
+ ASN1_OPT(ADMISSION_SYNTAX, admissionAuthority, GENERAL_NAME),
+ ASN1_SEQUENCE_OF(ADMISSION_SYNTAX, contentsOfAdmissions, ADMISSIONS),
+} ASN1_SEQUENCE_END(ADMISSION_SYNTAX)
+
+IMPLEMENT_ASN1_FUNCTIONS(NAMING_AUTHORITY)
+IMPLEMENT_ASN1_FUNCTIONS(PROFESSION_INFO)
+IMPLEMENT_ASN1_FUNCTIONS(ADMISSIONS)
+IMPLEMENT_ASN1_FUNCTIONS(ADMISSION_SYNTAX)
+
+static int i2r_ADMISSION_SYNTAX(const struct v3_ext_method *method, void *in,
+ BIO *bp, int ind);
+
+const X509V3_EXT_METHOD ossl_v3_ext_admission = {
+ NID_x509ExtAdmission, /* .ext_nid = */
+ 0, /* .ext_flags = */
+ ASN1_ITEM_ref(ADMISSION_SYNTAX), /* .it = */
+ NULL, NULL, NULL, NULL,
+ NULL, /* .i2s = */
+ NULL, /* .s2i = */
+ NULL, /* .i2v = */
+ NULL, /* .v2i = */
+ &i2r_ADMISSION_SYNTAX, /* .i2r = */
+ NULL, /* .r2i = */
+ NULL /* extension-specific data */
+};
+
+static int i2r_NAMING_AUTHORITY(const struct v3_ext_method *method, void *in,
+ BIO *bp, int ind)
+{
+ NAMING_AUTHORITY *namingAuthority = (NAMING_AUTHORITY *) in;
+
+ if (namingAuthority == NULL)
+ return 0;
+
+ if (namingAuthority->namingAuthorityId == NULL
+ && namingAuthority->namingAuthorityText == NULL
+ && namingAuthority->namingAuthorityUrl == NULL)
+ return 0;
+
+ if (BIO_printf(bp, "%*snamingAuthority:\n", ind, "") <= 0)
+ goto err;
+
+ if (namingAuthority->namingAuthorityId != NULL) {
+ char objbuf[128];
+ const char *ln = OBJ_nid2ln(OBJ_obj2nid(namingAuthority->namingAuthorityId));
+
+ if (BIO_printf(bp, "%*s namingAuthorityId: ", ind, "") <= 0)
+ goto err;
+
+ OBJ_obj2txt(objbuf, sizeof(objbuf), namingAuthority->namingAuthorityId, 1);
+
+ if (BIO_printf(bp, "%s%s%s%s\n", ln ? ln : "",
+ ln ? " (" : "", objbuf, ln ? ")" : "") <= 0)
+ goto err;
+ }
+ if (namingAuthority->namingAuthorityText != NULL) {
+ if (BIO_printf(bp, "%*s namingAuthorityText: ", ind, "") <= 0
+ || ASN1_STRING_print(bp, namingAuthority->namingAuthorityText) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+ if (namingAuthority->namingAuthorityUrl != NULL ) {
+ if (BIO_printf(bp, "%*s namingAuthorityUrl: ", ind, "") <= 0
+ || ASN1_STRING_print(bp, namingAuthority->namingAuthorityUrl) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+ return 1;
+
+err:
+ return 0;
+}
+
+static int i2r_ADMISSION_SYNTAX(const struct v3_ext_method *method, void *in,
+ BIO *bp, int ind)
+{
+ ADMISSION_SYNTAX * admission = (ADMISSION_SYNTAX *)in;
+ int i, j, k;
+
+ if (admission->admissionAuthority != NULL) {
+ if (BIO_printf(bp, "%*sadmissionAuthority:\n", ind, "") <= 0
+ || BIO_printf(bp, "%*s ", ind, "") <= 0
+ || GENERAL_NAME_print(bp, admission->admissionAuthority) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+
+ for (i = 0; i < sk_ADMISSIONS_num(admission->contentsOfAdmissions); i++) {
+ ADMISSIONS *entry = sk_ADMISSIONS_value(admission->contentsOfAdmissions, i);
+
+ if (BIO_printf(bp, "%*sEntry %0d:\n", ind, "", 1 + i) <= 0)
+ goto err;
+
+ if (entry->admissionAuthority != NULL) {
+ if (BIO_printf(bp, "%*s admissionAuthority:\n", ind, "") <= 0
+ || BIO_printf(bp, "%*s ", ind, "") <= 0
+ || GENERAL_NAME_print(bp, entry->admissionAuthority) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+
+ if (entry->namingAuthority != NULL) {
+ if (i2r_NAMING_AUTHORITY(method, entry->namingAuthority, bp, ind + 2) <= 0)
+ goto err;
+ }
+
+ for (j = 0; j < sk_PROFESSION_INFO_num(entry->professionInfos); j++) {
+ PROFESSION_INFO *pinfo = sk_PROFESSION_INFO_value(entry->professionInfos, j);
+
+ if (BIO_printf(bp, "%*s Profession Info Entry %0d:\n", ind, "", 1 + j) <= 0)
+ goto err;
+
+ if (pinfo->registrationNumber != NULL) {
+ if (BIO_printf(bp, "%*s registrationNumber: ", ind, "") <= 0
+ || ASN1_STRING_print(bp, pinfo->registrationNumber) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+
+ if (pinfo->namingAuthority != NULL) {
+ if (i2r_NAMING_AUTHORITY(method, pinfo->namingAuthority, bp, ind + 4) <= 0)
+ goto err;
+ }
+
+ if (pinfo->professionItems != NULL) {
+
+ if (BIO_printf(bp, "%*s Info Entries:\n", ind, "") <= 0)
+ goto err;
+ for (k = 0; k < sk_ASN1_STRING_num(pinfo->professionItems); k++) {
+ ASN1_STRING *val = sk_ASN1_STRING_value(pinfo->professionItems, k);
+
+ if (BIO_printf(bp, "%*s ", ind, "") <= 0
+ || ASN1_STRING_print(bp, val) <= 0
+ || BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+ }
+
+ if (pinfo->professionOIDs != NULL) {
+ if (BIO_printf(bp, "%*s Profession OIDs:\n", ind, "") <= 0)
+ goto err;
+ for (k = 0; k < sk_ASN1_OBJECT_num(pinfo->professionOIDs); k++) {
+ ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(pinfo->professionOIDs, k);
+ const char *ln = OBJ_nid2ln(OBJ_obj2nid(obj));
+ char objbuf[128];
+
+ OBJ_obj2txt(objbuf, sizeof(objbuf), obj, 1);
+ if (BIO_printf(bp, "%*s %s%s%s%s\n", ind, "",
+ ln ? ln : "", ln ? " (" : "",
+ objbuf, ln ? ")" : "") <= 0)
+ goto err;
+ }
+ }
+ }
+ }
+ return 1;
+
+err:
+ return 0;
+}
+
+const ASN1_OBJECT *NAMING_AUTHORITY_get0_authorityId(const NAMING_AUTHORITY *n)
+{
+ return n->namingAuthorityId;
+}
+
+void NAMING_AUTHORITY_set0_authorityId(NAMING_AUTHORITY *n, ASN1_OBJECT *id)
+{
+ ASN1_OBJECT_free(n->namingAuthorityId);
+ n->namingAuthorityId = id;
+}
+
+const ASN1_IA5STRING *NAMING_AUTHORITY_get0_authorityURL(const NAMING_AUTHORITY *n)
+{
+ return n->namingAuthorityUrl;
+}
+
+void NAMING_AUTHORITY_set0_authorityURL(NAMING_AUTHORITY *n, ASN1_IA5STRING *u)
+{
+ ASN1_IA5STRING_free(n->namingAuthorityUrl);
+ n->namingAuthorityUrl = u;
+}
+
+const ASN1_STRING *NAMING_AUTHORITY_get0_authorityText(const NAMING_AUTHORITY *n)
+{
+ return n->namingAuthorityText;
+}
+
+void NAMING_AUTHORITY_set0_authorityText(NAMING_AUTHORITY *n, ASN1_STRING *t)
+{
+ ASN1_IA5STRING_free(n->namingAuthorityText);
+ n->namingAuthorityText = t;
+}
+
+const GENERAL_NAME *ADMISSION_SYNTAX_get0_admissionAuthority(const ADMISSION_SYNTAX *as)
+{
+ return as->admissionAuthority;
+}
+
+void ADMISSION_SYNTAX_set0_admissionAuthority(ADMISSION_SYNTAX *as,
+ GENERAL_NAME *aa)
+{
+ GENERAL_NAME_free(as->admissionAuthority);
+ as->admissionAuthority = aa;
+}
+
+const STACK_OF(ADMISSIONS) *ADMISSION_SYNTAX_get0_contentsOfAdmissions(const ADMISSION_SYNTAX *as)
+{
+ return as->contentsOfAdmissions;
+}
+
+void ADMISSION_SYNTAX_set0_contentsOfAdmissions(ADMISSION_SYNTAX *as,
+ STACK_OF(ADMISSIONS) *a)
+{
+ sk_ADMISSIONS_pop_free(as->contentsOfAdmissions, ADMISSIONS_free);
+ as->contentsOfAdmissions = a;
+}
+
+const GENERAL_NAME *ADMISSIONS_get0_admissionAuthority(const ADMISSIONS *a)
+{
+ return a->admissionAuthority;
+}
+
+void ADMISSIONS_set0_admissionAuthority(ADMISSIONS *a, GENERAL_NAME *aa)
+{
+ GENERAL_NAME_free(a->admissionAuthority);
+ a->admissionAuthority = aa;
+}
+
+const NAMING_AUTHORITY *ADMISSIONS_get0_namingAuthority(const ADMISSIONS *a)
+{
+ return a->namingAuthority;
+}
+
+void ADMISSIONS_set0_namingAuthority(ADMISSIONS *a, NAMING_AUTHORITY *na)
+{
+ NAMING_AUTHORITY_free(a->namingAuthority);
+ a->namingAuthority = na;
+}
+
+const PROFESSION_INFOS *ADMISSIONS_get0_professionInfos(const ADMISSIONS *a)
+{
+ return a->professionInfos;
+}
+
+void ADMISSIONS_set0_professionInfos(ADMISSIONS *a, PROFESSION_INFOS *pi)
+{
+ sk_PROFESSION_INFO_pop_free(a->professionInfos, PROFESSION_INFO_free);
+ a->professionInfos = pi;
+}
+
+const ASN1_OCTET_STRING *PROFESSION_INFO_get0_addProfessionInfo(const PROFESSION_INFO *pi)
+{
+ return pi->addProfessionInfo;
+}
+
+void PROFESSION_INFO_set0_addProfessionInfo(PROFESSION_INFO *pi,
+ ASN1_OCTET_STRING *aos)
+{
+ ASN1_OCTET_STRING_free(pi->addProfessionInfo);
+ pi->addProfessionInfo = aos;
+}
+
+const NAMING_AUTHORITY *PROFESSION_INFO_get0_namingAuthority(const PROFESSION_INFO *pi)
+{
+ return pi->namingAuthority;
+}
+
+void PROFESSION_INFO_set0_namingAuthority(PROFESSION_INFO *pi,
+ NAMING_AUTHORITY *na)
+{
+ NAMING_AUTHORITY_free(pi->namingAuthority);
+ pi->namingAuthority = na;
+}
+
+const STACK_OF(ASN1_STRING) *PROFESSION_INFO_get0_professionItems(const PROFESSION_INFO *pi)
+{
+ return pi->professionItems;
+}
+
+void PROFESSION_INFO_set0_professionItems(PROFESSION_INFO *pi,
+ STACK_OF(ASN1_STRING) *as)
+{
+ sk_ASN1_STRING_pop_free(pi->professionItems, ASN1_STRING_free);
+ pi->professionItems = as;
+}
+
+const STACK_OF(ASN1_OBJECT) *PROFESSION_INFO_get0_professionOIDs(const PROFESSION_INFO *pi)
+{
+ return pi->professionOIDs;
+}
+
+void PROFESSION_INFO_set0_professionOIDs(PROFESSION_INFO *pi,
+ STACK_OF(ASN1_OBJECT) *po)
+{
+ sk_ASN1_OBJECT_pop_free(pi->professionOIDs, ASN1_OBJECT_free);
+ pi->professionOIDs = po;
+}
+
+const ASN1_PRINTABLESTRING *PROFESSION_INFO_get0_registrationNumber(const PROFESSION_INFO *pi)
+{
+ return pi->registrationNumber;
+}
+
+void PROFESSION_INFO_set0_registrationNumber(PROFESSION_INFO *pi,
+ ASN1_PRINTABLESTRING *rn)
+{
+ ASN1_PRINTABLESTRING_free(pi->registrationNumber);
+ pi->registrationNumber = rn;
+}
diff --git a/crypto/x509/v3_admis.h b/crypto/x509/v3_admis.h
new file mode 100644
index 000000000000..1e82c0f4a33f
--- /dev/null
+++ b/crypto/x509/v3_admis.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017-2018 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
+ */
+
+#ifndef OSSL_CRYPTO_X509_V3_ADMIS_H
+# define OSSL_CRYPTO_X509_V3_ADMIS_H
+
+struct NamingAuthority_st {
+ ASN1_OBJECT* namingAuthorityId;
+ ASN1_IA5STRING* namingAuthorityUrl;
+ ASN1_STRING* namingAuthorityText; /* i.e. DIRECTORYSTRING */
+};
+
+struct ProfessionInfo_st {
+ NAMING_AUTHORITY* namingAuthority;
+ STACK_OF(ASN1_STRING)* professionItems; /* i.e. DIRECTORYSTRING */
+ STACK_OF(ASN1_OBJECT)* professionOIDs;
+ ASN1_PRINTABLESTRING* registrationNumber;
+ ASN1_OCTET_STRING* addProfessionInfo;
+};
+
+struct Admissions_st {
+ GENERAL_NAME* admissionAuthority;
+ NAMING_AUTHORITY* namingAuthority;
+ STACK_OF(PROFESSION_INFO)* professionInfos;
+};
+
+struct AdmissionSyntax_st {
+ GENERAL_NAME* admissionAuthority;
+ STACK_OF(ADMISSIONS)* contentsOfAdmissions;
+};
+
+#endif
diff --git a/crypto/x509/v3_akeya.c b/crypto/x509/v3_akeya.c
new file mode 100644
index 000000000000..aae8c21e73c2
--- /dev/null
+++ b/crypto/x509/v3_akeya.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2001-2016 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+ASN1_SEQUENCE(AUTHORITY_KEYID) = {
+ ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0),
+ ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1),
+ ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2)
+} ASN1_SEQUENCE_END(AUTHORITY_KEYID)
+
+IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID)
diff --git a/crypto/x509/v3_akid.c b/crypto/x509/v3_akid.c
new file mode 100644
index 000000000000..43b515f50c49
--- /dev/null
+++ b/crypto/x509/v3_akid.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+#include "ext_dat.h"
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ AUTHORITY_KEYID *akeyid,
+ STACK_OF(CONF_VALUE)
+ *extlist);
+static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD ossl_v3_akey_id = {
+ NID_authority_key_identifier,
+ X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_AUTHORITY_KEYID,
+ (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID,
+ 0, 0,
+ NULL
+};
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ AUTHORITY_KEYID *akeyid,
+ STACK_OF(CONF_VALUE)
+ *extlist)
+{
+ char *tmp = NULL;
+ STACK_OF(CONF_VALUE) *origextlist = extlist, *tmpextlist;
+
+ if (akeyid->keyid) {
+ tmp = OPENSSL_buf2hexstr(akeyid->keyid->data, akeyid->keyid->length);
+ if (tmp == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (!X509V3_add_value((akeyid->issuer || akeyid->serial) ? "keyid" : NULL,
+ tmp, &extlist)) {
+ OPENSSL_free(tmp);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_X509_LIB);
+ goto err;
+ }
+ OPENSSL_free(tmp);
+ }
+ if (akeyid->issuer) {
+ tmpextlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
+ if (tmpextlist == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_X509_LIB);
+ goto err;
+ }
+ extlist = tmpextlist;
+ }
+ if (akeyid->serial) {
+ tmp = OPENSSL_buf2hexstr(akeyid->serial->data, akeyid->serial->length);
+ if (tmp == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!X509V3_add_value("serial", tmp, &extlist)) {
+ OPENSSL_free(tmp);
+ goto err;
+ }
+ OPENSSL_free(tmp);
+ }
+ return extlist;
+ err:
+ if (origextlist == NULL)
+ sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free);
+ return NULL;
+}
+
+/*-
+ * Currently two options:
+ * keyid: use the issuers subject keyid, the value 'always' means its is
+ * an error if the issuer certificate doesn't have a key id.
+ * issuer: use the issuers cert issuer and serial number. The default is
+ * to only use this if keyid is not present. With the option 'always'
+ * this is always included.
+ */
+
+static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ char keyid = 0, issuer = 0;
+ int i, n = sk_CONF_VALUE_num(values);
+ CONF_VALUE *cnf;
+ ASN1_OCTET_STRING *ikeyid = NULL;
+ X509_NAME *isname = NULL;
+ GENERAL_NAMES *gens = NULL;
+ GENERAL_NAME *gen = NULL;
+ ASN1_INTEGER *serial = NULL;
+ X509_EXTENSION *ext;
+ X509 *issuer_cert;
+ int same_issuer, ss;
+ AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
+
+ if (akeyid == NULL)
+ goto err;
+
+ if (n == 1 && strcmp(sk_CONF_VALUE_value(values, 0)->name, "none") == 0) {
+ return akeyid;
+ }
+
+ for (i = 0; i < n; i++) {
+ cnf = sk_CONF_VALUE_value(values, i);
+ if (strcmp(cnf->name, "keyid") == 0) {
+ keyid = 1;
+ if (cnf->value && strcmp(cnf->value, "always") == 0)
+ keyid = 2;
+ } else if (strcmp(cnf->name, "issuer") == 0) {
+ issuer = 1;
+ if (cnf->value && strcmp(cnf->value, "always") == 0)
+ issuer = 2;
+ } else {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_UNKNOWN_OPTION,
+ "name=%s", cnf->name);
+ goto err;
+ }
+ }
+
+ if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+ return akeyid;
+
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ goto err;
+ }
+ if ((issuer_cert = ctx->issuer_cert) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE);
+ goto err;
+ }
+ same_issuer = ctx->subject_cert == ctx->issuer_cert;
+ ERR_set_mark();
+ if (ctx->issuer_pkey != NULL)
+ ss = X509_check_private_key(ctx->subject_cert, ctx->issuer_pkey);
+ else
+ ss = same_issuer;
+ ERR_pop_to_mark();
+
+ /* unless forced with "always", AKID is suppressed for self-signed certs */
+ if (keyid == 2 || (keyid == 1 && !ss)) {
+ /*
+ * prefer any pre-existing subject key identifier of the issuer cert
+ * except issuer cert is same as subject cert and is not self-signed
+ */
+ i = X509_get_ext_by_NID(issuer_cert, NID_subject_key_identifier, -1);
+ if (i >= 0 && (ext = X509_get_ext(issuer_cert, i)) != NULL
+ && !(same_issuer && !ss))
+ ikeyid = X509V3_EXT_d2i(ext);
+ if (ikeyid == NULL && same_issuer && ctx->issuer_pkey != NULL) {
+ /* generate fallback AKID, emulating s2i_skey_id(..., "hash") */
+ X509_PUBKEY *pubkey = NULL;
+
+ if (X509_PUBKEY_set(&pubkey, ctx->issuer_pkey))
+ ikeyid = ossl_x509_pubkey_hash(pubkey);
+ X509_PUBKEY_free(pubkey);
+ }
+ if ((keyid == 2 || issuer == 0)
+ && (ikeyid == NULL
+ || ASN1_STRING_length(ikeyid) <= 2) /* indicating "none" */) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
+ goto err;
+ }
+ }
+
+ if (issuer == 2 || (issuer == 1 && ikeyid == NULL)) {
+ isname = X509_NAME_dup(X509_get_issuer_name(issuer_cert));
+ serial = ASN1_INTEGER_dup(X509_get0_serialNumber(issuer_cert));
+ if (isname == NULL || serial == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
+ goto err;
+ }
+ }
+
+ if (isname != NULL) {
+ if ((gens = sk_GENERAL_NAME_new_null()) == NULL
+ || (gen = GENERAL_NAME_new()) == NULL
+ || !sk_GENERAL_NAME_push(gens, gen)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ gen->type = GEN_DIRNAME;
+ gen->d.dirn = isname;
+ }
+
+ akeyid->issuer = gens;
+ gen = NULL;
+ gens = NULL;
+ akeyid->serial = serial;
+ akeyid->keyid = ikeyid;
+
+ return akeyid;
+
+ err:
+ sk_GENERAL_NAME_free(gens);
+ GENERAL_NAME_free(gen);
+ X509_NAME_free(isname);
+ ASN1_INTEGER_free(serial);
+ ASN1_OCTET_STRING_free(ikeyid);
+ AUTHORITY_KEYID_free(akeyid);
+ return NULL;
+}
diff --git a/crypto/x509/v3_asid.c b/crypto/x509/v3_asid.c
new file mode 100644
index 000000000000..c2b6f8a660df
--- /dev/null
+++ b/crypto/x509/v3_asid.c
@@ -0,0 +1,910 @@
+/*
+ * Copyright 2006-2024 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
+ */
+
+/*
+ * Implementation of RFC 3779 section 3.2.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509.h>
+#include "crypto/x509.h"
+#include <openssl/bn.h>
+#include "ext_dat.h"
+#include "x509_local.h"
+
+#ifndef OPENSSL_NO_RFC3779
+
+/*
+ * OpenSSL ASN.1 template translation of RFC 3779 3.2.3.
+ */
+
+ASN1_SEQUENCE(ASRange) = {
+ ASN1_SIMPLE(ASRange, min, ASN1_INTEGER),
+ ASN1_SIMPLE(ASRange, max, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(ASRange)
+
+ASN1_CHOICE(ASIdOrRange) = {
+ ASN1_SIMPLE(ASIdOrRange, u.id, ASN1_INTEGER),
+ ASN1_SIMPLE(ASIdOrRange, u.range, ASRange)
+} ASN1_CHOICE_END(ASIdOrRange)
+
+ASN1_CHOICE(ASIdentifierChoice) = {
+ ASN1_SIMPLE(ASIdentifierChoice, u.inherit, ASN1_NULL),
+ ASN1_SEQUENCE_OF(ASIdentifierChoice, u.asIdsOrRanges, ASIdOrRange)
+} ASN1_CHOICE_END(ASIdentifierChoice)
+
+ASN1_SEQUENCE(ASIdentifiers) = {
+ ASN1_EXP_OPT(ASIdentifiers, asnum, ASIdentifierChoice, 0),
+ ASN1_EXP_OPT(ASIdentifiers, rdi, ASIdentifierChoice, 1)
+} ASN1_SEQUENCE_END(ASIdentifiers)
+
+IMPLEMENT_ASN1_FUNCTIONS(ASRange)
+IMPLEMENT_ASN1_FUNCTIONS(ASIdOrRange)
+IMPLEMENT_ASN1_FUNCTIONS(ASIdentifierChoice)
+IMPLEMENT_ASN1_FUNCTIONS(ASIdentifiers)
+
+/*
+ * i2r method for an ASIdentifierChoice.
+ */
+static int i2r_ASIdentifierChoice(BIO *out,
+ ASIdentifierChoice *choice,
+ int indent, const char *msg)
+{
+ int i;
+ char *s;
+ if (choice == NULL)
+ return 1;
+ BIO_printf(out, "%*s%s:\n", indent, "", msg);
+ switch (choice->type) {
+ case ASIdentifierChoice_inherit:
+ BIO_printf(out, "%*sinherit\n", indent + 2, "");
+ break;
+ case ASIdentifierChoice_asIdsOrRanges:
+ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges); i++) {
+ ASIdOrRange *aor =
+ sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
+ switch (aor->type) {
+ case ASIdOrRange_id:
+ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.id)) == NULL)
+ return 0;
+ BIO_printf(out, "%*s%s\n", indent + 2, "", s);
+ OPENSSL_free(s);
+ break;
+ case ASIdOrRange_range:
+ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->min)) == NULL)
+ return 0;
+ BIO_printf(out, "%*s%s-", indent + 2, "", s);
+ OPENSSL_free(s);
+ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->max)) == NULL)
+ return 0;
+ BIO_printf(out, "%s\n", s);
+ OPENSSL_free(s);
+ break;
+ default:
+ return 0;
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * i2r method for an ASIdentifier extension.
+ */
+static int i2r_ASIdentifiers(const X509V3_EXT_METHOD *method,
+ void *ext, BIO *out, int indent)
+{
+ ASIdentifiers *asid = ext;
+ return (i2r_ASIdentifierChoice(out, asid->asnum, indent,
+ "Autonomous System Numbers") &&
+ i2r_ASIdentifierChoice(out, asid->rdi, indent,
+ "Routing Domain Identifiers"));
+}
+
+/*
+ * Sort comparison function for a sequence of ASIdOrRange elements.
+ */
+static int ASIdOrRange_cmp(const ASIdOrRange *const *a_,
+ const ASIdOrRange *const *b_)
+{
+ const ASIdOrRange *a = *a_, *b = *b_;
+
+ assert((a->type == ASIdOrRange_id && a->u.id != NULL) ||
+ (a->type == ASIdOrRange_range && a->u.range != NULL &&
+ a->u.range->min != NULL && a->u.range->max != NULL));
+
+ assert((b->type == ASIdOrRange_id && b->u.id != NULL) ||
+ (b->type == ASIdOrRange_range && b->u.range != NULL &&
+ b->u.range->min != NULL && b->u.range->max != NULL));
+
+ if (a->type == ASIdOrRange_id && b->type == ASIdOrRange_id)
+ return ASN1_INTEGER_cmp(a->u.id, b->u.id);
+
+ if (a->type == ASIdOrRange_range && b->type == ASIdOrRange_range) {
+ int r = ASN1_INTEGER_cmp(a->u.range->min, b->u.range->min);
+ return r != 0 ? r : ASN1_INTEGER_cmp(a->u.range->max,
+ b->u.range->max);
+ }
+
+ if (a->type == ASIdOrRange_id)
+ return ASN1_INTEGER_cmp(a->u.id, b->u.range->min);
+ else
+ return ASN1_INTEGER_cmp(a->u.range->min, b->u.id);
+}
+
+/*
+ * Add an inherit element.
+ */
+int X509v3_asid_add_inherit(ASIdentifiers *asid, int which)
+{
+ ASIdentifierChoice **choice;
+ if (asid == NULL)
+ return 0;
+ switch (which) {
+ case V3_ASID_ASNUM:
+ choice = &asid->asnum;
+ break;
+ case V3_ASID_RDI:
+ choice = &asid->rdi;
+ break;
+ default:
+ return 0;
+ }
+ if (*choice == NULL) {
+ if ((*choice = ASIdentifierChoice_new()) == NULL)
+ return 0;
+ if (((*choice)->u.inherit = ASN1_NULL_new()) == NULL) {
+ ASIdentifierChoice_free(*choice);
+ *choice = NULL;
+ return 0;
+ }
+ (*choice)->type = ASIdentifierChoice_inherit;
+ }
+ return (*choice)->type == ASIdentifierChoice_inherit;
+}
+
+/*
+ * Add an ID or range to an ASIdentifierChoice.
+ */
+int X509v3_asid_add_id_or_range(ASIdentifiers *asid,
+ int which, ASN1_INTEGER *min, ASN1_INTEGER *max)
+{
+ ASIdentifierChoice **choice;
+ ASIdOrRange *aor;
+ if (asid == NULL)
+ return 0;
+ switch (which) {
+ case V3_ASID_ASNUM:
+ choice = &asid->asnum;
+ break;
+ case V3_ASID_RDI:
+ choice = &asid->rdi;
+ break;
+ default:
+ return 0;
+ }
+ if (*choice != NULL && (*choice)->type != ASIdentifierChoice_asIdsOrRanges)
+ return 0;
+ if (*choice == NULL) {
+ if ((*choice = ASIdentifierChoice_new()) == NULL)
+ return 0;
+ (*choice)->u.asIdsOrRanges = sk_ASIdOrRange_new(ASIdOrRange_cmp);
+ if ((*choice)->u.asIdsOrRanges == NULL) {
+ ASIdentifierChoice_free(*choice);
+ *choice = NULL;
+ return 0;
+ }
+ (*choice)->type = ASIdentifierChoice_asIdsOrRanges;
+ }
+ if ((aor = ASIdOrRange_new()) == NULL)
+ return 0;
+ if (!sk_ASIdOrRange_reserve((*choice)->u.asIdsOrRanges, 1))
+ goto err;
+ if (max == NULL) {
+ aor->type = ASIdOrRange_id;
+ aor->u.id = min;
+ } else {
+ aor->type = ASIdOrRange_range;
+ if ((aor->u.range = ASRange_new()) == NULL)
+ goto err;
+ ASN1_INTEGER_free(aor->u.range->min);
+ aor->u.range->min = min;
+ ASN1_INTEGER_free(aor->u.range->max);
+ aor->u.range->max = max;
+ }
+ /* Cannot fail due to the reservation above */
+ if (!ossl_assert(sk_ASIdOrRange_push((*choice)->u.asIdsOrRanges, aor)))
+ goto err;
+ return 1;
+
+ err:
+ ASIdOrRange_free(aor);
+ return 0;
+}
+
+/*
+ * Extract min and max values from an ASIdOrRange.
+ */
+static int extract_min_max(ASIdOrRange *aor,
+ ASN1_INTEGER **min, ASN1_INTEGER **max)
+{
+ if (!ossl_assert(aor != NULL))
+ return 0;
+ switch (aor->type) {
+ case ASIdOrRange_id:
+ *min = aor->u.id;
+ *max = aor->u.id;
+ return 1;
+ case ASIdOrRange_range:
+ *min = aor->u.range->min;
+ *max = aor->u.range->max;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check whether an ASIdentifierChoice is in canonical form.
+ */
+static int ASIdentifierChoice_is_canonical(ASIdentifierChoice *choice)
+{
+ ASN1_INTEGER *a_max_plus_one = NULL;
+ ASN1_INTEGER *orig;
+ BIGNUM *bn = NULL;
+ int i, ret = 0;
+
+ /*
+ * Empty element or inheritance is canonical.
+ */
+ if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
+ return 1;
+
+ /*
+ * If not a list, or if empty list, it's broken.
+ */
+ if (choice->type != ASIdentifierChoice_asIdsOrRanges ||
+ sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0)
+ return 0;
+
+ /*
+ * It's a list, check it.
+ */
+ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
+ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
+ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
+ ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max =
+ NULL;
+
+ if (!extract_min_max(a, &a_min, &a_max)
+ || !extract_min_max(b, &b_min, &b_max))
+ goto done;
+
+ /*
+ * Punt misordered list, overlapping start, or inverted range.
+ */
+ if (ASN1_INTEGER_cmp(a_min, b_min) >= 0 ||
+ ASN1_INTEGER_cmp(a_min, a_max) > 0 ||
+ ASN1_INTEGER_cmp(b_min, b_max) > 0)
+ goto done;
+
+ /*
+ * Calculate a_max + 1 to check for adjacency.
+ */
+ if ((bn == NULL && (bn = BN_new()) == NULL) ||
+ ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
+ !BN_add_word(bn, 1)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+
+ if ((a_max_plus_one =
+ BN_to_ASN1_INTEGER(bn, orig = a_max_plus_one)) == NULL) {
+ a_max_plus_one = orig;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+
+ /*
+ * Punt if adjacent or overlapping.
+ */
+ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) >= 0)
+ goto done;
+ }
+
+ /*
+ * Check for inverted range.
+ */
+ i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1;
+ {
+ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
+ ASN1_INTEGER *a_min, *a_max;
+ if (a != NULL && a->type == ASIdOrRange_range) {
+ if (!extract_min_max(a, &a_min, &a_max)
+ || ASN1_INTEGER_cmp(a_min, a_max) > 0)
+ goto done;
+ }
+ }
+
+ ret = 1;
+
+ done:
+ ASN1_INTEGER_free(a_max_plus_one);
+ BN_free(bn);
+ return ret;
+}
+
+/*
+ * Check whether an ASIdentifier extension is in canonical form.
+ */
+int X509v3_asid_is_canonical(ASIdentifiers *asid)
+{
+ return (asid == NULL ||
+ (ASIdentifierChoice_is_canonical(asid->asnum) &&
+ ASIdentifierChoice_is_canonical(asid->rdi)));
+}
+
+/*
+ * Whack an ASIdentifierChoice into canonical form.
+ */
+static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice)
+{
+ ASN1_INTEGER *a_max_plus_one = NULL;
+ ASN1_INTEGER *orig;
+ BIGNUM *bn = NULL;
+ int i, ret = 0;
+
+ /*
+ * Nothing to do for empty element or inheritance.
+ */
+ if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
+ return 1;
+
+ /*
+ * If not a list, or if empty list, it's broken.
+ */
+ if (choice->type != ASIdentifierChoice_asIdsOrRanges ||
+ sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ return 0;
+ }
+
+ /*
+ * We have a non-empty list. Sort it.
+ */
+ sk_ASIdOrRange_sort(choice->u.asIdsOrRanges);
+
+ /*
+ * Now check for errors and suboptimal encoding, rejecting the
+ * former and fixing the latter.
+ */
+ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
+ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
+ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
+ ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max =
+ NULL;
+
+ if (!extract_min_max(a, &a_min, &a_max)
+ || !extract_min_max(b, &b_min, &b_max))
+ goto done;
+
+ /*
+ * Make sure we're properly sorted (paranoia).
+ */
+ if (!ossl_assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0))
+ goto done;
+
+ /*
+ * Punt inverted ranges.
+ */
+ if (ASN1_INTEGER_cmp(a_min, a_max) > 0 ||
+ ASN1_INTEGER_cmp(b_min, b_max) > 0)
+ goto done;
+
+ /*
+ * Check for overlaps.
+ */
+ if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ goto done;
+ }
+
+ /*
+ * Calculate a_max + 1 to check for adjacency.
+ */
+ if ((bn == NULL && (bn = BN_new()) == NULL) ||
+ ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
+ !BN_add_word(bn, 1)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+
+ if ((a_max_plus_one =
+ BN_to_ASN1_INTEGER(bn, orig = a_max_plus_one)) == NULL) {
+ a_max_plus_one = orig;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+
+ /*
+ * If a and b are adjacent, merge them.
+ */
+ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) == 0) {
+ ASRange *r;
+ switch (a->type) {
+ case ASIdOrRange_id:
+ if ((r = OPENSSL_malloc(sizeof(*r))) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+ r->min = a_min;
+ r->max = b_max;
+ a->type = ASIdOrRange_range;
+ a->u.range = r;
+ break;
+ case ASIdOrRange_range:
+ ASN1_INTEGER_free(a->u.range->max);
+ a->u.range->max = b_max;
+ break;
+ }
+ switch (b->type) {
+ case ASIdOrRange_id:
+ b->u.id = NULL;
+ break;
+ case ASIdOrRange_range:
+ b->u.range->max = NULL;
+ break;
+ }
+ ASIdOrRange_free(b);
+ (void)sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1);
+ i--;
+ continue;
+ }
+ }
+
+ /*
+ * Check for final inverted range.
+ */
+ i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1;
+ {
+ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
+ ASN1_INTEGER *a_min, *a_max;
+ if (a != NULL && a->type == ASIdOrRange_range) {
+ if (!extract_min_max(a, &a_min, &a_max)
+ || ASN1_INTEGER_cmp(a_min, a_max) > 0)
+ goto done;
+ }
+ }
+
+ /* Paranoia */
+ if (!ossl_assert(ASIdentifierChoice_is_canonical(choice)))
+ goto done;
+
+ ret = 1;
+
+ done:
+ ASN1_INTEGER_free(a_max_plus_one);
+ BN_free(bn);
+ return ret;
+}
+
+/*
+ * Whack an ASIdentifier extension into canonical form.
+ */
+int X509v3_asid_canonize(ASIdentifiers *asid)
+{
+ return (asid == NULL ||
+ (ASIdentifierChoice_canonize(asid->asnum) &&
+ ASIdentifierChoice_canonize(asid->rdi)));
+}
+
+/*
+ * v2i method for an ASIdentifier extension.
+ */
+static void *v2i_ASIdentifiers(const struct v3_ext_method *method,
+ struct v3_ext_ctx *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ ASN1_INTEGER *min = NULL, *max = NULL;
+ ASIdentifiers *asid = NULL;
+ int i;
+
+ if ((asid = ASIdentifiers_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ CONF_VALUE *val = sk_CONF_VALUE_value(values, i);
+ int i1 = 0, i2 = 0, i3 = 0, is_range = 0, which = 0;
+
+ /*
+ * Figure out whether this is an AS or an RDI.
+ */
+ if (!ossl_v3_name_cmp(val->name, "AS")) {
+ which = V3_ASID_ASNUM;
+ } else if (!ossl_v3_name_cmp(val->name, "RDI")) {
+ which = V3_ASID_RDI;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+
+ if (val->value == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ goto err;
+ }
+
+ /*
+ * Handle inheritance.
+ */
+ if (strcmp(val->value, "inherit") == 0) {
+ if (X509v3_asid_add_inherit(asid, which))
+ continue;
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_INHERITANCE);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+
+ /*
+ * Number, range, or mistake, pick it apart and figure out which.
+ */
+ i1 = strspn(val->value, "0123456789");
+ if (val->value[i1] == '\0') {
+ is_range = 0;
+ } else {
+ is_range = 1;
+ i2 = i1 + strspn(val->value + i1, " \t");
+ if (val->value[i2] != '-') {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_ASNUMBER);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ i2++;
+ i2 = i2 + strspn(val->value + i2, " \t");
+ i3 = i2 + strspn(val->value + i2, "0123456789");
+ if (val->value[i3] != '\0') {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_ASRANGE);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ }
+
+ /*
+ * Syntax is ok, read and add it.
+ */
+ if (!is_range) {
+ if (!X509V3_get_value_int(val, &min)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ } else {
+ char *s = OPENSSL_strdup(val->value);
+ if (s == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ s[i1] = '\0';
+ min = s2i_ASN1_INTEGER(NULL, s);
+ max = s2i_ASN1_INTEGER(NULL, s + i2);
+ OPENSSL_free(s);
+ if (min == NULL || max == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (ASN1_INTEGER_cmp(min, max) > 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ goto err;
+ }
+ }
+ if (!X509v3_asid_add_id_or_range(asid, which, min, max)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ min = max = NULL;
+ }
+
+ /*
+ * Canonize the result, then we're done.
+ */
+ if (!X509v3_asid_canonize(asid))
+ goto err;
+ return asid;
+
+ err:
+ ASIdentifiers_free(asid);
+ ASN1_INTEGER_free(min);
+ ASN1_INTEGER_free(max);
+ return NULL;
+}
+
+/*
+ * OpenSSL dispatch.
+ */
+const X509V3_EXT_METHOD ossl_v3_asid = {
+ NID_sbgp_autonomousSysNum, /* nid */
+ 0, /* flags */
+ ASN1_ITEM_ref(ASIdentifiers), /* template */
+ 0, 0, 0, 0, /* old functions, ignored */
+ 0, /* i2s */
+ 0, /* s2i */
+ 0, /* i2v */
+ v2i_ASIdentifiers, /* v2i */
+ i2r_ASIdentifiers, /* i2r */
+ 0, /* r2i */
+ NULL /* extension-specific data */
+};
+
+/*
+ * Figure out whether extension uses inheritance.
+ */
+int X509v3_asid_inherits(ASIdentifiers *asid)
+{
+ return (asid != NULL &&
+ ((asid->asnum != NULL &&
+ asid->asnum->type == ASIdentifierChoice_inherit) ||
+ (asid->rdi != NULL &&
+ asid->rdi->type == ASIdentifierChoice_inherit)));
+}
+
+/*
+ * Figure out whether parent contains child.
+ */
+static int asid_contains(ASIdOrRanges *parent, ASIdOrRanges *child)
+{
+ ASN1_INTEGER *p_min = NULL, *p_max = NULL, *c_min = NULL, *c_max = NULL;
+ int p, c;
+
+ if (child == NULL || parent == child)
+ return 1;
+ if (parent == NULL)
+ return 0;
+
+ p = 0;
+ for (c = 0; c < sk_ASIdOrRange_num(child); c++) {
+ if (!extract_min_max(sk_ASIdOrRange_value(child, c), &c_min, &c_max))
+ return 0;
+ for (;; p++) {
+ if (p >= sk_ASIdOrRange_num(parent))
+ return 0;
+ if (!extract_min_max(sk_ASIdOrRange_value(parent, p), &p_min,
+ &p_max))
+ return 0;
+ if (ASN1_INTEGER_cmp(p_max, c_max) < 0)
+ continue;
+ if (ASN1_INTEGER_cmp(p_min, c_min) > 0)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Test whether a is a subset of b.
+ */
+int X509v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b)
+{
+ int subset;
+
+ if (a == NULL || a == b)
+ return 1;
+
+ if (b == NULL)
+ return 0;
+
+ if (X509v3_asid_inherits(a) || X509v3_asid_inherits(b))
+ return 0;
+
+ subset = a->asnum == NULL
+ || (b->asnum != NULL
+ && asid_contains(b->asnum->u.asIdsOrRanges,
+ a->asnum->u.asIdsOrRanges));
+ if (!subset)
+ return 0;
+
+ return a->rdi == NULL
+ || (b->rdi != NULL
+ && asid_contains(b->rdi->u.asIdsOrRanges,
+ a->rdi->u.asIdsOrRanges));
+}
+
+/*
+ * Validation error handling via callback.
+ */
+#define validation_err(_err_) \
+ do { \
+ if (ctx != NULL) { \
+ ctx->error = _err_; \
+ ctx->error_depth = i; \
+ ctx->current_cert = x; \
+ ret = ctx->verify_cb(0, ctx); \
+ } else { \
+ ret = 0; \
+ } \
+ if (!ret) \
+ goto done; \
+ } while (0)
+
+/*
+ * Core code for RFC 3779 3.3 path validation.
+ */
+static int asid_validate_path_internal(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *chain,
+ ASIdentifiers *ext)
+{
+ ASIdOrRanges *child_as = NULL, *child_rdi = NULL;
+ int i, ret = 1, inherit_as = 0, inherit_rdi = 0;
+ X509 *x;
+
+ if (!ossl_assert(chain != NULL && sk_X509_num(chain) > 0)
+ || !ossl_assert(ctx != NULL || ext != NULL)
+ || !ossl_assert(ctx == NULL || ctx->verify_cb != NULL)) {
+ if (ctx != NULL)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+
+
+ /*
+ * Figure out where to start. If we don't have an extension to
+ * check, we're done. Otherwise, check canonical form and
+ * set up for walking up the chain.
+ */
+ if (ext != NULL) {
+ i = -1;
+ x = NULL;
+ } else {
+ i = 0;
+ x = sk_X509_value(chain, i);
+ if ((ext = x->rfc3779_asid) == NULL)
+ goto done;
+ }
+ if (!X509v3_asid_is_canonical(ext))
+ validation_err(X509_V_ERR_INVALID_EXTENSION);
+ if (ext->asnum != NULL) {
+ switch (ext->asnum->type) {
+ case ASIdentifierChoice_inherit:
+ inherit_as = 1;
+ break;
+ case ASIdentifierChoice_asIdsOrRanges:
+ child_as = ext->asnum->u.asIdsOrRanges;
+ break;
+ }
+ }
+ if (ext->rdi != NULL) {
+ switch (ext->rdi->type) {
+ case ASIdentifierChoice_inherit:
+ inherit_rdi = 1;
+ break;
+ case ASIdentifierChoice_asIdsOrRanges:
+ child_rdi = ext->rdi->u.asIdsOrRanges;
+ break;
+ }
+ }
+
+ /*
+ * Now walk up the chain. Extensions must be in canonical form, no
+ * cert may list resources that its parent doesn't list.
+ */
+ for (i++; i < sk_X509_num(chain); i++) {
+ x = sk_X509_value(chain, i);
+ if (!ossl_assert(x != NULL)) {
+ if (ctx != NULL)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+ if (x->rfc3779_asid == NULL) {
+ if (child_as != NULL || child_rdi != NULL)
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ continue;
+ }
+ if (!X509v3_asid_is_canonical(x->rfc3779_asid))
+ validation_err(X509_V_ERR_INVALID_EXTENSION);
+ if (x->rfc3779_asid->asnum == NULL && child_as != NULL) {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ child_as = NULL;
+ inherit_as = 0;
+ }
+ if (x->rfc3779_asid->asnum != NULL &&
+ x->rfc3779_asid->asnum->type ==
+ ASIdentifierChoice_asIdsOrRanges) {
+ if (inherit_as
+ || asid_contains(x->rfc3779_asid->asnum->u.asIdsOrRanges,
+ child_as)) {
+ child_as = x->rfc3779_asid->asnum->u.asIdsOrRanges;
+ inherit_as = 0;
+ } else {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ }
+ }
+ if (x->rfc3779_asid->rdi == NULL && child_rdi != NULL) {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ child_rdi = NULL;
+ inherit_rdi = 0;
+ }
+ if (x->rfc3779_asid->rdi != NULL &&
+ x->rfc3779_asid->rdi->type == ASIdentifierChoice_asIdsOrRanges) {
+ if (inherit_rdi ||
+ asid_contains(x->rfc3779_asid->rdi->u.asIdsOrRanges,
+ child_rdi)) {
+ child_rdi = x->rfc3779_asid->rdi->u.asIdsOrRanges;
+ inherit_rdi = 0;
+ } else {
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ }
+ }
+ }
+
+ /*
+ * Trust anchor can't inherit.
+ */
+ if (!ossl_assert(x != NULL)) {
+ if (ctx != NULL)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+ if (x->rfc3779_asid != NULL) {
+ if (x->rfc3779_asid->asnum != NULL &&
+ x->rfc3779_asid->asnum->type == ASIdentifierChoice_inherit)
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ if (x->rfc3779_asid->rdi != NULL &&
+ x->rfc3779_asid->rdi->type == ASIdentifierChoice_inherit)
+ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
+ }
+
+ done:
+ return ret;
+}
+
+#undef validation_err
+
+/*
+ * RFC 3779 3.3 path validation -- called from X509_verify_cert().
+ */
+int X509v3_asid_validate_path(X509_STORE_CTX *ctx)
+{
+ if (ctx->chain == NULL
+ || sk_X509_num(ctx->chain) == 0
+ || ctx->verify_cb == NULL) {
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return 0;
+ }
+ return asid_validate_path_internal(ctx, ctx->chain, NULL);
+}
+
+/*
+ * RFC 3779 3.3 path validation of an extension.
+ * Test whether chain covers extension.
+ */
+int X509v3_asid_validate_resource_set(STACK_OF(X509) *chain,
+ ASIdentifiers *ext, int allow_inheritance)
+{
+ if (ext == NULL)
+ return 1;
+ if (chain == NULL || sk_X509_num(chain) == 0)
+ return 0;
+ if (!allow_inheritance && X509v3_asid_inherits(ext))
+ return 0;
+ return asid_validate_path_internal(NULL, chain, ext);
+}
+
+#endif /* OPENSSL_NO_RFC3779 */
diff --git a/crypto/x509/v3_bcons.c b/crypto/x509/v3_bcons.c
new file mode 100644
index 000000000000..6e7a165f26e8
--- /dev/null
+++ b/crypto/x509/v3_bcons.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+#include "x509_local.h"
+
+static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ BASIC_CONSTRAINTS *bcons,
+ STACK_OF(CONF_VALUE)
+ *extlist);
+static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD ossl_v3_bcons = {
+ NID_basic_constraints, 0,
+ ASN1_ITEM_ref(BASIC_CONSTRAINTS),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_BASIC_CONSTRAINTS,
+ (X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS,
+ NULL, NULL,
+ NULL
+};
+
+ASN1_SEQUENCE(BASIC_CONSTRAINTS) = {
+ ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN),
+ ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS)
+
+IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
+
+static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ BASIC_CONSTRAINTS *bcons,
+ STACK_OF(CONF_VALUE)
+ *extlist)
+{
+ X509V3_add_value_bool("CA", bcons->ca, &extlist);
+ X509V3_add_value_int("pathlen", bcons->pathlen, &extlist);
+ return extlist;
+}
+
+static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ BASIC_CONSTRAINTS *bcons = NULL;
+ CONF_VALUE *val;
+ int i;
+
+ if ((bcons = BASIC_CONSTRAINTS_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ val = sk_CONF_VALUE_value(values, i);
+ if (strcmp(val->name, "CA") == 0) {
+ if (!X509V3_get_value_bool(val, &bcons->ca))
+ goto err;
+ } else if (strcmp(val->name, "pathlen") == 0) {
+ if (!X509V3_get_value_int(val, &bcons->pathlen))
+ goto err;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NAME);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ }
+ return bcons;
+ err:
+ BASIC_CONSTRAINTS_free(bcons);
+ return NULL;
+}
diff --git a/crypto/x509/v3_bitst.c b/crypto/x509/v3_bitst.c
new file mode 100644
index 000000000000..b53c5ba3ecd3
--- /dev/null
+++ b/crypto/x509/v3_bitst.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static BIT_STRING_BITNAME ns_cert_type_table[] = {
+ {0, "SSL Client", "client"},
+ {1, "SSL Server", "server"},
+ {2, "S/MIME", "email"},
+ {3, "Object Signing", "objsign"},
+ {4, "Unused", "reserved"},
+ {5, "SSL CA", "sslCA"},
+ {6, "S/MIME CA", "emailCA"},
+ {7, "Object Signing CA", "objCA"},
+ {-1, NULL, NULL}
+};
+
+static BIT_STRING_BITNAME key_usage_type_table[] = {
+ {0, "Digital Signature", "digitalSignature"},
+ {1, "Non Repudiation", "nonRepudiation"},
+ {2, "Key Encipherment", "keyEncipherment"},
+ {3, "Data Encipherment", "dataEncipherment"},
+ {4, "Key Agreement", "keyAgreement"},
+ {5, "Certificate Sign", "keyCertSign"},
+ {6, "CRL Sign", "cRLSign"},
+ {7, "Encipher Only", "encipherOnly"},
+ {8, "Decipher Only", "decipherOnly"},
+ {-1, NULL, NULL}
+};
+
+const X509V3_EXT_METHOD ossl_v3_nscert =
+EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table);
+const X509V3_EXT_METHOD ossl_v3_key_usage =
+EXT_BITSTRING(NID_key_usage, key_usage_type_table);
+
+STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ ASN1_BIT_STRING *bits,
+ STACK_OF(CONF_VALUE) *ret)
+{
+ BIT_STRING_BITNAME *bnam;
+ for (bnam = method->usr_data; bnam->lname; bnam++) {
+ if (ASN1_BIT_STRING_get_bit(bits, bnam->bitnum))
+ X509V3_add_value(bnam->lname, NULL, &ret);
+ }
+ return ret;
+}
+
+ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ CONF_VALUE *val;
+ ASN1_BIT_STRING *bs;
+ int i;
+ BIT_STRING_BITNAME *bnam;
+ if ((bs = ASN1_BIT_STRING_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ for (bnam = method->usr_data; bnam->lname; bnam++) {
+ if (strcmp(bnam->sname, val->name) == 0
+ || strcmp(bnam->lname, val->name) == 0) {
+ if (!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ ASN1_BIT_STRING_free(bs);
+ return NULL;
+ }
+ break;
+ }
+ }
+ if (!bnam->lname) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT,
+ "%s", val->name);
+ ASN1_BIT_STRING_free(bs);
+ return NULL;
+ }
+ }
+ return bs;
+}
diff --git a/crypto/x509/v3_conf.c b/crypto/x509/v3_conf.c
new file mode 100644
index 000000000000..1c11d671b2ed
--- /dev/null
+++ b/crypto/x509/v3_conf.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright 1999-2021 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
+ */
+
+/* extension creation utilities */
+
+#include <stdio.h>
+#include "crypto/ctype.h"
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509.h>
+#include "crypto/x509.h"
+#include <openssl/x509v3.h>
+
+static int v3_check_critical(const char **value);
+static int v3_check_generic(const char **value);
+static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid,
+ int crit, const char *value);
+static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
+ int crit, int type,
+ X509V3_CTX *ctx);
+static char *conf_lhash_get_string(void *db, const char *section, const char *value);
+static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section);
+static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method,
+ int ext_nid, int crit, void *ext_struc);
+static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx,
+ long *ext_len);
+
+static X509_EXTENSION *X509V3_EXT_nconf_int(CONF *conf, X509V3_CTX *ctx,
+ const char *section,
+ const char *name, const char *value)
+{
+ int crit;
+ int ext_type;
+ X509_EXTENSION *ret;
+
+ crit = v3_check_critical(&value);
+ if ((ext_type = v3_check_generic(&value)))
+ return v3_generic_extension(name, value, crit, ext_type, ctx);
+ ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value);
+ if (!ret) {
+ if (section != NULL)
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_ERROR_IN_EXTENSION,
+ "section=%s, name=%s, value=%s",
+ section, name, value);
+ else
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_ERROR_IN_EXTENSION,
+ "name=%s, value=%s", name, value);
+ }
+ return ret;
+}
+
+X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, const char *name,
+ const char *value)
+{
+ return X509V3_EXT_nconf_int(conf, ctx, NULL, name, value);
+}
+
+X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid,
+ const char *value)
+{
+ int crit;
+ int ext_type;
+
+ crit = v3_check_critical(&value);
+ if ((ext_type = v3_check_generic(&value)))
+ return v3_generic_extension(OBJ_nid2sn(ext_nid),
+ value, crit, ext_type, ctx);
+ return do_ext_nconf(conf, ctx, ext_nid, crit, value);
+}
+
+/* CONF *conf: Config file */
+/* char *value: Value */
+static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid,
+ int crit, const char *value)
+{
+ const X509V3_EXT_METHOD *method;
+ X509_EXTENSION *ext;
+ STACK_OF(CONF_VALUE) *nval;
+ void *ext_struc;
+
+ if (ext_nid == NID_undef) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME);
+ return NULL;
+ }
+ if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION);
+ return NULL;
+ }
+ /* Now get internal extension representation based on type */
+ if (method->v2i) {
+ if (*value == '@')
+ nval = NCONF_get_section(conf, value + 1);
+ else
+ nval = X509V3_parse_list(value);
+ if (nval == NULL || sk_CONF_VALUE_num(nval) <= 0) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_EXTENSION_STRING,
+ "name=%s,section=%s", OBJ_nid2sn(ext_nid), value);
+ if (*value != '@')
+ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+ return NULL;
+ }
+ ext_struc = method->v2i(method, ctx, nval);
+ if (*value != '@')
+ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+ if (!ext_struc)
+ return NULL;
+ } else if (method->s2i) {
+ if ((ext_struc = method->s2i(method, ctx, value)) == NULL)
+ return NULL;
+ } else if (method->r2i) {
+ if (!ctx->db || !ctx->db_meth) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_CONFIG_DATABASE);
+ return NULL;
+ }
+ if ((ext_struc = method->r2i(method, ctx, value)) == NULL)
+ return NULL;
+ } else {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED,
+ "name=%s", OBJ_nid2sn(ext_nid));
+ return NULL;
+ }
+
+ ext = do_ext_i2d(method, ext_nid, crit, ext_struc);
+ if (method->it)
+ ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it));
+ else
+ method->ext_free(ext_struc);
+ return ext;
+
+}
+
+static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method,
+ int ext_nid, int crit, void *ext_struc)
+{
+ unsigned char *ext_der = NULL;
+ int ext_len;
+ ASN1_OCTET_STRING *ext_oct = NULL;
+ X509_EXTENSION *ext;
+
+ /* Convert internal representation to DER */
+ if (method->it) {
+ ext_der = NULL;
+ ext_len =
+ ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it));
+ if (ext_len < 0)
+ goto merr;
+ } else {
+ unsigned char *p;
+
+ ext_len = method->i2d(ext_struc, NULL);
+ if (ext_len <= 0)
+ goto merr;
+ if ((ext_der = OPENSSL_malloc(ext_len)) == NULL)
+ goto merr;
+ p = ext_der;
+ method->i2d(ext_struc, &p);
+ }
+ if ((ext_oct = ASN1_OCTET_STRING_new()) == NULL)
+ goto merr;
+ ext_oct->data = ext_der;
+ ext_der = NULL;
+ ext_oct->length = ext_len;
+
+ ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct);
+ if (!ext)
+ goto merr;
+ ASN1_OCTET_STRING_free(ext_oct);
+
+ return ext;
+
+ merr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(ext_der);
+ ASN1_OCTET_STRING_free(ext_oct);
+ return NULL;
+
+}
+
+/* Given an internal structure, nid and critical flag create an extension */
+
+X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc)
+{
+ const X509V3_EXT_METHOD *method;
+
+ if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION);
+ return NULL;
+ }
+ return do_ext_i2d(method, ext_nid, crit, ext_struc);
+}
+
+/* Check the extension string for critical flag */
+static int v3_check_critical(const char **value)
+{
+ const char *p = *value;
+
+ if ((strlen(p) < 9) || strncmp(p, "critical,", 9))
+ return 0;
+ p += 9;
+ while (ossl_isspace(*p))
+ p++;
+ *value = p;
+ return 1;
+}
+
+/* Check extension string for generic extension and return the type */
+static int v3_check_generic(const char **value)
+{
+ int gen_type = 0;
+ const char *p = *value;
+
+ if ((strlen(p) >= 4) && strncmp(p, "DER:", 4) == 0) {
+ p += 4;
+ gen_type = 1;
+ } else if ((strlen(p) >= 5) && strncmp(p, "ASN1:", 5) == 0) {
+ p += 5;
+ gen_type = 2;
+ } else
+ return 0;
+
+ while (ossl_isspace(*p))
+ p++;
+ *value = p;
+ return gen_type;
+}
+
+/* Create a generic extension: for now just handle DER type */
+static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
+ int crit, int gen_type,
+ X509V3_CTX *ctx)
+{
+ unsigned char *ext_der = NULL;
+ long ext_len = 0;
+ ASN1_OBJECT *obj = NULL;
+ ASN1_OCTET_STRING *oct = NULL;
+ X509_EXTENSION *extension = NULL;
+
+ if ((obj = OBJ_txt2obj(ext, 0)) == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR,
+ "name=%s", ext);
+ goto err;
+ }
+
+ if (gen_type == 1)
+ ext_der = OPENSSL_hexstr2buf(value, &ext_len);
+ else if (gen_type == 2)
+ ext_der = generic_asn1(value, ctx, &ext_len);
+
+ if (ext_der == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR,
+ "value=%s", value);
+ goto err;
+ }
+
+ if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ oct->data = ext_der;
+ oct->length = ext_len;
+ ext_der = NULL;
+
+ extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct);
+
+ err:
+ ASN1_OBJECT_free(obj);
+ ASN1_OCTET_STRING_free(oct);
+ OPENSSL_free(ext_der);
+ return extension;
+
+}
+
+static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx,
+ long *ext_len)
+{
+ ASN1_TYPE *typ;
+ unsigned char *ext_der = NULL;
+
+ typ = ASN1_generate_v3(value, ctx);
+ if (typ == NULL)
+ return NULL;
+ *ext_len = i2d_ASN1_TYPE(typ, &ext_der);
+ ASN1_TYPE_free(typ);
+ return ext_der;
+}
+
+static void delete_ext(STACK_OF(X509_EXTENSION) *sk, X509_EXTENSION *dext)
+{
+ int idx;
+ ASN1_OBJECT *obj;
+
+ obj = X509_EXTENSION_get_object(dext);
+ while ((idx = X509v3_get_ext_by_OBJ(sk, obj, -1)) >= 0)
+ X509_EXTENSION_free(X509v3_delete_ext(sk, idx));
+}
+
+/*
+ * This is the main function: add a bunch of extensions based on a config
+ * file section to an extension STACK. Just check in case sk == NULL.
+ * Note that on error new elements may have been added to *sk if sk != NULL.
+ */
+int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, const char *section,
+ STACK_OF(X509_EXTENSION) **sk)
+{
+ X509_EXTENSION *ext;
+ STACK_OF(CONF_VALUE) *nval;
+ CONF_VALUE *val;
+ int i;
+
+ if ((nval = NCONF_get_section(conf, section)) == NULL)
+ return 0;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if ((ext = X509V3_EXT_nconf_int(conf, ctx, val->section,
+ val->name, val->value)) == NULL)
+ return 0;
+ if (sk != NULL) {
+ if (ctx->flags == X509V3_CTX_REPLACE)
+ delete_ext(*sk, ext);
+ if (X509v3_add_ext(sk, ext, -1) == NULL) {
+ X509_EXTENSION_free(ext);
+ return 0;
+ }
+ }
+ X509_EXTENSION_free(ext);
+ }
+ return 1;
+}
+
+/*
+ * Add extensions to a certificate. Just check in case cert == NULL.
+ * Note that on error new elements may remain added to cert if cert != NULL.
+ */
+int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
+ X509 *cert)
+{
+ STACK_OF(X509_EXTENSION) **sk = NULL;
+ if (cert != NULL)
+ sk = &cert->cert_info.extensions;
+ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
+}
+
+/*
+ * Add extensions to a CRL. Just check in case crl == NULL.
+ * Note that on error new elements may remain added to crl if crl != NULL.
+ */
+int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
+ X509_CRL *crl)
+{
+ STACK_OF(X509_EXTENSION) **sk = NULL;
+ if (crl != NULL)
+ sk = &crl->crl.extensions;
+ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
+}
+
+/*
+ * Add extensions to certificate request. Just check in case req is NULL.
+ * Note that on error new elements may remain added to req if req != NULL.
+ */
+int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
+ X509_REQ *req)
+{
+ STACK_OF(X509_EXTENSION) *exts = NULL;
+ int ret = X509V3_EXT_add_nconf_sk(conf, ctx, section, &exts);
+
+ if (ret && req != NULL && exts != NULL)
+ ret = X509_REQ_add_extensions(req, exts);
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ return ret;
+}
+
+/* Config database functions */
+
+char *X509V3_get_string(X509V3_CTX *ctx, const char *name, const char *section)
+{
+ if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_OPERATION_NOT_DEFINED);
+ return NULL;
+ }
+ if (ctx->db_meth->get_string)
+ return ctx->db_meth->get_string(ctx->db, name, section);
+ return NULL;
+}
+
+STACK_OF(CONF_VALUE) *X509V3_get_section(X509V3_CTX *ctx, const char *section)
+{
+ if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_OPERATION_NOT_DEFINED);
+ return NULL;
+ }
+ if (ctx->db_meth->get_section)
+ return ctx->db_meth->get_section(ctx->db, section);
+ return NULL;
+}
+
+void X509V3_string_free(X509V3_CTX *ctx, char *str)
+{
+ if (!str)
+ return;
+ if (ctx->db_meth->free_string)
+ ctx->db_meth->free_string(ctx->db, str);
+}
+
+void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section)
+{
+ if (!section)
+ return;
+ if (ctx->db_meth->free_section)
+ ctx->db_meth->free_section(ctx->db, section);
+}
+
+static char *nconf_get_string(void *db, const char *section, const char *value)
+{
+ return NCONF_get_string(db, section, value);
+}
+
+static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, const char *section)
+{
+ return NCONF_get_section(db, section);
+}
+
+static X509V3_CONF_METHOD nconf_method = {
+ nconf_get_string,
+ nconf_get_section,
+ NULL,
+ NULL
+};
+
+void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ return;
+ }
+ ctx->db_meth = &nconf_method;
+ ctx->db = conf;
+}
+
+void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req,
+ X509_CRL *crl, int flags)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ return;
+ }
+ ctx->flags = flags;
+ ctx->issuer_cert = issuer;
+ ctx->subject_cert = subj;
+ ctx->subject_req = req;
+ ctx->crl = crl;
+ ctx->db_meth = NULL;
+ ctx->db = NULL;
+ ctx->issuer_pkey = NULL;
+}
+
+/* For API backward compatibility, this is separate from X509V3_set_ctx() */
+int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (ctx->subject_cert == NULL && pkey != NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+ ctx->issuer_pkey = pkey;
+ return 1;
+}
+
+/* Old conf compatibility functions */
+
+X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ const char *name, const char *value)
+{
+ CONF *ctmp;
+ X509_EXTENSION *ret;
+
+ if ((ctmp = NCONF_new(NULL)) == NULL)
+ return NULL;
+ CONF_set_nconf(ctmp, conf);
+ ret = X509V3_EXT_nconf(ctmp, ctx, name, value);
+ CONF_set_nconf(ctmp, NULL);
+ NCONF_free(ctmp);
+ return ret;
+}
+
+X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf,
+ X509V3_CTX *ctx, int ext_nid, const char *value)
+{
+ CONF *ctmp;
+ X509_EXTENSION *ret;
+
+ if ((ctmp = NCONF_new(NULL)) == NULL)
+ return NULL;
+ CONF_set_nconf(ctmp, conf);
+ ret = X509V3_EXT_nconf_nid(ctmp, ctx, ext_nid, value);
+ CONF_set_nconf(ctmp, NULL);
+ NCONF_free(ctmp);
+ return ret;
+}
+
+static char *conf_lhash_get_string(void *db, const char *section, const char *value)
+{
+ return CONF_get_string(db, section, value);
+}
+
+static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section)
+{
+ return CONF_get_section(db, section);
+}
+
+static X509V3_CONF_METHOD conf_lhash_method = {
+ conf_lhash_get_string,
+ conf_lhash_get_section,
+ NULL,
+ NULL
+};
+
+void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ return;
+ }
+ ctx->db_meth = &conf_lhash_method;
+ ctx->db = lhash;
+}
+
+int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ const char *section, X509 *cert)
+{
+ CONF *ctmp;
+ int ret;
+
+ if ((ctmp = NCONF_new(NULL)) == NULL)
+ return 0;
+ CONF_set_nconf(ctmp, conf);
+ ret = X509V3_EXT_add_nconf(ctmp, ctx, section, cert);
+ CONF_set_nconf(ctmp, NULL);
+ NCONF_free(ctmp);
+ return ret;
+}
+
+/* Same as above but for a CRL */
+
+int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ const char *section, X509_CRL *crl)
+{
+ CONF *ctmp;
+ int ret;
+
+ if ((ctmp = NCONF_new(NULL)) == NULL)
+ return 0;
+ CONF_set_nconf(ctmp, conf);
+ ret = X509V3_EXT_CRL_add_nconf(ctmp, ctx, section, crl);
+ CONF_set_nconf(ctmp, NULL);
+ NCONF_free(ctmp);
+ return ret;
+}
+
+/* Add extensions to certificate request */
+
+int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ const char *section, X509_REQ *req)
+{
+ CONF *ctmp;
+ int ret;
+
+ if ((ctmp = NCONF_new(NULL)) == NULL)
+ return 0;
+ CONF_set_nconf(ctmp, conf);
+ ret = X509V3_EXT_REQ_add_nconf(ctmp, ctx, section, req);
+ CONF_set_nconf(ctmp, NULL);
+ NCONF_free(ctmp);
+ return ret;
+}
diff --git a/crypto/x509/v3_cpols.c b/crypto/x509/v3_cpols.c
new file mode 100644
index 000000000000..5353a6916761
--- /dev/null
+++ b/crypto/x509/v3_cpols.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+#include "x509_local.h"
+#include "pcy_local.h"
+#include "ext_dat.h"
+
+/* Certificate policies extension support: this one is a bit complex... */
+
+static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
+ BIO *out, int indent);
+static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, const char *value);
+static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
+ int indent);
+static void print_notice(BIO *out, USERNOTICE *notice, int indent);
+static POLICYINFO *policy_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *polstrs, int ia5org);
+static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *unot, int ia5org);
+static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos);
+static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len);
+static int displaytext_get_tag_len(const char *tagstr);
+
+const X509V3_EXT_METHOD ossl_v3_cpols = {
+ NID_certificate_policies, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES),
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2R)i2r_certpol,
+ (X509V3_EXT_R2I)r2i_certpol,
+ NULL
+};
+
+ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
+ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
+
+IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
+
+ASN1_SEQUENCE(POLICYINFO) = {
+ ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT),
+ ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO)
+} ASN1_SEQUENCE_END(POLICYINFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO)
+
+ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY);
+
+ASN1_ADB(POLICYQUALINFO) = {
+ ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)),
+ ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE))
+} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL);
+
+ASN1_SEQUENCE(POLICYQUALINFO) = {
+ ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT),
+ ASN1_ADB_OBJECT(POLICYQUALINFO)
+} ASN1_SEQUENCE_END(POLICYQUALINFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO)
+
+ASN1_SEQUENCE(USERNOTICE) = {
+ ASN1_OPT(USERNOTICE, noticeref, NOTICEREF),
+ ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT)
+} ASN1_SEQUENCE_END(USERNOTICE)
+
+IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE)
+
+ASN1_SEQUENCE(NOTICEREF) = {
+ ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT),
+ ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(NOTICEREF)
+
+IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF)
+
+static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, const char *value)
+{
+ STACK_OF(POLICYINFO) *pols;
+ char *pstr;
+ POLICYINFO *pol;
+ ASN1_OBJECT *pobj;
+ STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
+ CONF_VALUE *cnf;
+ const int num = sk_CONF_VALUE_num(vals);
+ int i, ia5org;
+
+ if (vals == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_X509V3_LIB);
+ return NULL;
+ }
+
+ pols = sk_POLICYINFO_new_reserve(NULL, num);
+ if (pols == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ ia5org = 0;
+ for (i = 0; i < num; i++) {
+ cnf = sk_CONF_VALUE_value(vals, i);
+ if (cnf->value != NULL || cnf->name == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER);
+ X509V3_conf_add_error_name_value(cnf);
+ goto err;
+ }
+ pstr = cnf->name;
+ if (strcmp(pstr, "ia5org") == 0) {
+ ia5org = 1;
+ continue;
+ } else if (*pstr == '@') {
+ STACK_OF(CONF_VALUE) *polsect;
+
+ polsect = X509V3_get_section(ctx, pstr + 1);
+ if (polsect == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_SECTION,
+ "%s", cnf->name);
+ goto err;
+ }
+ pol = policy_section(ctx, polsect, ia5org);
+ X509V3_section_free(ctx, polsect);
+ if (pol == NULL)
+ goto err;
+ } else {
+ if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3,
+ X509V3_R_INVALID_OBJECT_IDENTIFIER,
+ "%s", cnf->name);
+ goto err;
+ }
+ pol = POLICYINFO_new();
+ if (pol == NULL) {
+ ASN1_OBJECT_free(pobj);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ pol->policyid = pobj;
+ }
+ if (!sk_POLICYINFO_push(pols, pol)) {
+ POLICYINFO_free(pol);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ return pols;
+ err:
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
+ return NULL;
+}
+
+static POLICYINFO *policy_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *polstrs, int ia5org)
+{
+ int i;
+ CONF_VALUE *cnf;
+ POLICYINFO *pol;
+ POLICYQUALINFO *qual;
+
+ if ((pol = POLICYINFO_new()) == NULL)
+ goto merr;
+ for (i = 0; i < sk_CONF_VALUE_num(polstrs); i++) {
+ cnf = sk_CONF_VALUE_value(polstrs, i);
+ if (strcmp(cnf->name, "policyIdentifier") == 0) {
+ ASN1_OBJECT *pobj;
+
+ if ((pobj = OBJ_txt2obj(cnf->value, 0)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ pol->policyid = pobj;
+
+ } else if (!ossl_v3_name_cmp(cnf->name, "CPS")) {
+ if (pol->qualifiers == NULL)
+ pol->qualifiers = sk_POLICYQUALINFO_new_null();
+ if ((qual = POLICYQUALINFO_new()) == NULL)
+ goto merr;
+ if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+ goto merr;
+ if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_cps)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if ((qual->d.cpsuri = ASN1_IA5STRING_new()) == NULL)
+ goto merr;
+ if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
+ strlen(cnf->value)))
+ goto merr;
+ } else if (!ossl_v3_name_cmp(cnf->name, "userNotice")) {
+ STACK_OF(CONF_VALUE) *unot;
+ if (*cnf->value != '@') {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXPECTED_A_SECTION_NAME);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ unot = X509V3_get_section(ctx, cnf->value + 1);
+ if (!unot) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SECTION);
+
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ qual = notice_section(ctx, unot, ia5org);
+ X509V3_section_free(ctx, unot);
+ if (!qual)
+ goto err;
+ if (pol->qualifiers == NULL)
+ pol->qualifiers = sk_POLICYQUALINFO_new_null();
+ if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+ goto merr;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OPTION);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+ if (pol->policyid == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_POLICY_IDENTIFIER);
+ goto err;
+ }
+
+ return pol;
+
+ merr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+
+ err:
+ POLICYINFO_free(pol);
+ return NULL;
+}
+
+static int displaytext_get_tag_len(const char *tagstr)
+{
+ char *colon = strchr(tagstr, ':');
+
+ return (colon == NULL) ? -1 : colon - tagstr;
+}
+
+static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len)
+{
+ int len;
+
+ *tag_len = 0;
+ len = displaytext_get_tag_len(tagstr);
+
+ if (len == -1)
+ return V_ASN1_VISIBLESTRING;
+ *tag_len = len;
+ if (len == sizeof("UTF8") - 1 && strncmp(tagstr, "UTF8", len) == 0)
+ return V_ASN1_UTF8STRING;
+ if (len == sizeof("UTF8String") - 1 && strncmp(tagstr, "UTF8String", len) == 0)
+ return V_ASN1_UTF8STRING;
+ if (len == sizeof("BMP") - 1 && strncmp(tagstr, "BMP", len) == 0)
+ return V_ASN1_BMPSTRING;
+ if (len == sizeof("BMPSTRING") - 1 && strncmp(tagstr, "BMPSTRING", len) == 0)
+ return V_ASN1_BMPSTRING;
+ if (len == sizeof("VISIBLE") - 1 && strncmp(tagstr, "VISIBLE", len) == 0)
+ return V_ASN1_VISIBLESTRING;
+ if (len == sizeof("VISIBLESTRING") - 1 && strncmp(tagstr, "VISIBLESTRING", len) == 0)
+ return V_ASN1_VISIBLESTRING;
+ *tag_len = 0;
+ return V_ASN1_VISIBLESTRING;
+}
+
+static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *unot, int ia5org)
+{
+ int i, ret, len, tag;
+ unsigned int tag_len;
+ CONF_VALUE *cnf;
+ USERNOTICE *not;
+ POLICYQUALINFO *qual;
+ char *value = NULL;
+
+ if ((qual = POLICYQUALINFO_new()) == NULL)
+ goto merr;
+ if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if ((not = USERNOTICE_new()) == NULL)
+ goto merr;
+ qual->d.usernotice = not;
+ for (i = 0; i < sk_CONF_VALUE_num(unot); i++) {
+ cnf = sk_CONF_VALUE_value(unot, i);
+
+ value = cnf->value;
+ if (strcmp(cnf->name, "explicitText") == 0) {
+ tag = displaytext_str2tag(value, &tag_len);
+ if ((not->exptext = ASN1_STRING_type_new(tag)) == NULL)
+ goto merr;
+ if (tag_len != 0)
+ value += tag_len + 1;
+ len = strlen(value);
+ if (!ASN1_STRING_set(not->exptext, value, len))
+ goto merr;
+ } else if (strcmp(cnf->name, "organization") == 0) {
+ NOTICEREF *nref;
+
+ if (!not->noticeref) {
+ if ((nref = NOTICEREF_new()) == NULL)
+ goto merr;
+ not->noticeref = nref;
+ } else
+ nref = not->noticeref;
+ if (ia5org)
+ nref->organization->type = V_ASN1_IA5STRING;
+ else
+ nref->organization->type = V_ASN1_VISIBLESTRING;
+ if (!ASN1_STRING_set(nref->organization, cnf->value,
+ strlen(cnf->value)))
+ goto merr;
+ } else if (strcmp(cnf->name, "noticeNumbers") == 0) {
+ NOTICEREF *nref;
+
+ STACK_OF(CONF_VALUE) *nos;
+ if (!not->noticeref) {
+ if ((nref = NOTICEREF_new()) == NULL)
+ goto merr;
+ not->noticeref = nref;
+ } else
+ nref = not->noticeref;
+ nos = X509V3_parse_list(cnf->value);
+ if (!nos || !sk_CONF_VALUE_num(nos)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NUMBERS);
+ X509V3_conf_add_error_name_value(cnf);
+ sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
+ goto err;
+ }
+ ret = nref_nos(nref->noticenos, nos);
+ sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
+ if (!ret)
+ goto err;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OPTION);
+ X509V3_conf_add_error_name_value(cnf);
+ goto err;
+ }
+ }
+
+ if (not->noticeref &&
+ (!not->noticeref->noticenos || !not->noticeref->organization)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
+ goto err;
+ }
+
+ return qual;
+
+ merr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+
+ err:
+ POLICYQUALINFO_free(qual);
+ return NULL;
+}
+
+static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos)
+{
+ CONF_VALUE *cnf;
+ ASN1_INTEGER *aint;
+
+ int i;
+
+ for (i = 0; i < sk_CONF_VALUE_num(nos); i++) {
+ cnf = sk_CONF_VALUE_value(nos, i);
+ if ((aint = s2i_ASN1_INTEGER(NULL, cnf->name)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NUMBER);
+ goto err;
+ }
+ if (!sk_ASN1_INTEGER_push(nnums, aint))
+ goto merr;
+ }
+ return 1;
+
+ merr:
+ ASN1_INTEGER_free(aint);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+
+ err:
+ return 0;
+}
+
+static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
+ BIO *out, int indent)
+{
+ int i;
+ POLICYINFO *pinfo;
+ /* First print out the policy OIDs */
+ for (i = 0; i < sk_POLICYINFO_num(pol); i++) {
+ if (i > 0)
+ BIO_puts(out, "\n");
+ pinfo = sk_POLICYINFO_value(pol, i);
+ BIO_printf(out, "%*sPolicy: ", indent, "");
+ i2a_ASN1_OBJECT(out, pinfo->policyid);
+ if (pinfo->qualifiers) {
+ BIO_puts(out, "\n");
+ print_qualifiers(out, pinfo->qualifiers, indent + 2);
+ }
+ }
+ return 1;
+}
+
+static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
+ int indent)
+{
+ POLICYQUALINFO *qualinfo;
+ int i;
+ for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
+ if (i > 0)
+ BIO_puts(out, "\n");
+ qualinfo = sk_POLICYQUALINFO_value(quals, i);
+ switch (OBJ_obj2nid(qualinfo->pqualid)) {
+ case NID_id_qt_cps:
+ BIO_printf(out, "%*sCPS: %.*s", indent, "",
+ qualinfo->d.cpsuri->length,
+ qualinfo->d.cpsuri->data);
+ break;
+
+ case NID_id_qt_unotice:
+ BIO_printf(out, "%*sUser Notice:\n", indent, "");
+ print_notice(out, qualinfo->d.usernotice, indent + 2);
+ break;
+
+ default:
+ BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, "");
+
+ i2a_ASN1_OBJECT(out, qualinfo->pqualid);
+ break;
+ }
+ }
+}
+
+static void print_notice(BIO *out, USERNOTICE *notice, int indent)
+{
+ int i;
+ if (notice->noticeref) {
+ NOTICEREF *ref;
+ ref = notice->noticeref;
+ BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
+ ref->organization->length,
+ ref->organization->data);
+ BIO_printf(out, "%*sNumber%s: ", indent, "",
+ sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
+ for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
+ ASN1_INTEGER *num;
+ char *tmp;
+ num = sk_ASN1_INTEGER_value(ref->noticenos, i);
+ if (i)
+ BIO_puts(out, ", ");
+ if (num == NULL)
+ BIO_puts(out, "(null)");
+ else {
+ tmp = i2s_ASN1_INTEGER(NULL, num);
+ if (tmp == NULL)
+ return;
+ BIO_puts(out, tmp);
+ OPENSSL_free(tmp);
+ }
+ }
+ if (notice->exptext)
+ BIO_puts(out, "\n");
+ }
+ if (notice->exptext)
+ BIO_printf(out, "%*sExplicit Text: %.*s", indent, "",
+ notice->exptext->length,
+ notice->exptext->data);
+}
+
+void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
+{
+ const X509_POLICY_DATA *dat = node->data;
+
+ BIO_printf(out, "%*sPolicy: ", indent, "");
+
+ i2a_ASN1_OBJECT(out, dat->valid_policy);
+ BIO_puts(out, "\n");
+ BIO_printf(out, "%*s%s\n", indent + 2, "",
+ node_data_critical(dat) ? "Critical" : "Non Critical");
+ if (dat->qualifier_set) {
+ print_qualifiers(out, dat->qualifier_set, indent + 2);
+ BIO_puts(out, "\n");
+ }
+ else
+ BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, "");
+}
diff --git a/crypto/x509/v3_crld.c b/crypto/x509/v3_crld.c
new file mode 100644
index 000000000000..07c8379d3521
--- /dev/null
+++ b/crypto/x509/v3_crld.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright 1999-2024 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+#include "crypto/x509.h"
+#include "ext_dat.h"
+#include "x509_local.h"
+
+static void *v2i_crld(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
+ int indent);
+
+const X509V3_EXT_METHOD ossl_v3_crld = {
+ NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+ v2i_crld,
+ i2r_crldp, 0,
+ NULL
+};
+
+const X509V3_EXT_METHOD ossl_v3_freshest_crl = {
+ NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+ v2i_crld,
+ i2r_crldp, 0,
+ NULL
+};
+
+static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx,
+ char *sect)
+{
+ STACK_OF(CONF_VALUE) *gnsect;
+ STACK_OF(GENERAL_NAME) *gens;
+ if (*sect == '@')
+ gnsect = X509V3_get_section(ctx, sect + 1);
+ else
+ gnsect = X509V3_parse_list(sect);
+ if (!gnsect) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND);
+ return NULL;
+ }
+ gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect);
+ if (*sect == '@')
+ X509V3_section_free(ctx, gnsect);
+ else
+ sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free);
+ return gens;
+}
+
+static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
+ CONF_VALUE *cnf)
+{
+ STACK_OF(GENERAL_NAME) *fnm = NULL;
+ STACK_OF(X509_NAME_ENTRY) *rnm = NULL;
+
+ if (cnf->value == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE);
+ goto err;
+ }
+
+ if (strncmp(cnf->name, "fullname", 9) == 0) {
+ fnm = gnames_from_sectname(ctx, cnf->value);
+ if (!fnm)
+ goto err;
+ } else if (strcmp(cnf->name, "relativename") == 0) {
+ int ret;
+ STACK_OF(CONF_VALUE) *dnsect;
+ X509_NAME *nm;
+ nm = X509_NAME_new();
+ if (nm == NULL)
+ return -1;
+ dnsect = X509V3_get_section(ctx, cnf->value);
+ if (!dnsect) {
+ X509_NAME_free(nm);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND);
+ return -1;
+ }
+ ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
+ X509V3_section_free(ctx, dnsect);
+ rnm = nm->entries;
+ nm->entries = NULL;
+ X509_NAME_free(nm);
+ if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0)
+ goto err;
+ /*
+ * Since its a name fragment can't have more than one RDNSequence
+ */
+ if (sk_X509_NAME_ENTRY_value(rnm,
+ sk_X509_NAME_ENTRY_num(rnm) - 1)->set) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_MULTIPLE_RDNS);
+ goto err;
+ }
+ } else
+ return 0;
+
+ if (*pdp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_DISTPOINT_ALREADY_SET);
+ goto err;
+ }
+
+ *pdp = DIST_POINT_NAME_new();
+ if (*pdp == NULL)
+ goto err;
+ if (fnm) {
+ (*pdp)->type = 0;
+ (*pdp)->name.fullname = fnm;
+ } else {
+ (*pdp)->type = 1;
+ (*pdp)->name.relativename = rnm;
+ }
+
+ return 1;
+
+ err:
+ sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free);
+ sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free);
+ return -1;
+}
+
+static const BIT_STRING_BITNAME reason_flags[] = {
+ {0, "Unused", "unused"},
+ {1, "Key Compromise", "keyCompromise"},
+ {2, "CA Compromise", "CACompromise"},
+ {3, "Affiliation Changed", "affiliationChanged"},
+ {4, "Superseded", "superseded"},
+ {5, "Cessation Of Operation", "cessationOfOperation"},
+ {6, "Certificate Hold", "certificateHold"},
+ {7, "Privilege Withdrawn", "privilegeWithdrawn"},
+ {8, "AA Compromise", "AACompromise"},
+ {-1, NULL, NULL}
+};
+
+static int set_reasons(ASN1_BIT_STRING **preas, char *value)
+{
+ STACK_OF(CONF_VALUE) *rsk = NULL;
+ const BIT_STRING_BITNAME *pbn;
+ const char *bnam;
+ int i, ret = 0;
+ rsk = X509V3_parse_list(value);
+ if (rsk == NULL)
+ return 0;
+ if (*preas != NULL)
+ goto err;
+ for (i = 0; i < sk_CONF_VALUE_num(rsk); i++) {
+ bnam = sk_CONF_VALUE_value(rsk, i)->name;
+ if (*preas == NULL) {
+ *preas = ASN1_BIT_STRING_new();
+ if (*preas == NULL)
+ goto err;
+ }
+ for (pbn = reason_flags; pbn->lname; pbn++) {
+ if (strcmp(pbn->sname, bnam) == 0) {
+ if (!ASN1_BIT_STRING_set_bit(*preas, pbn->bitnum, 1))
+ goto err;
+ break;
+ }
+ }
+ if (pbn->lname == NULL)
+ goto err;
+ }
+ ret = 1;
+
+ err:
+ sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free);
+ return ret;
+}
+
+static int print_reasons(BIO *out, const char *rname,
+ ASN1_BIT_STRING *rflags, int indent)
+{
+ int first = 1;
+ const BIT_STRING_BITNAME *pbn;
+ BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, "");
+ for (pbn = reason_flags; pbn->lname; pbn++) {
+ if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum)) {
+ if (first)
+ first = 0;
+ else
+ BIO_puts(out, ", ");
+ BIO_puts(out, pbn->lname);
+ }
+ }
+ if (first)
+ BIO_puts(out, "<EMPTY>\n");
+ else
+ BIO_puts(out, "\n");
+ return 1;
+}
+
+static DIST_POINT *crldp_from_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ int i;
+ CONF_VALUE *cnf;
+ DIST_POINT *point = DIST_POINT_new();
+
+ if (point == NULL)
+ goto err;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ int ret;
+ cnf = sk_CONF_VALUE_value(nval, i);
+ ret = set_dist_point_name(&point->distpoint, ctx, cnf);
+ if (ret > 0)
+ continue;
+ if (ret < 0)
+ goto err;
+ if (strcmp(cnf->name, "reasons") == 0) {
+ if (!set_reasons(&point->reasons, cnf->value))
+ goto err;
+ } else if (strcmp(cnf->name, "CRLissuer") == 0) {
+ point->CRLissuer = gnames_from_sectname(ctx, cnf->value);
+ if (point->CRLissuer == NULL)
+ goto err;
+ }
+ }
+
+ return point;
+
+ err:
+ DIST_POINT_free(point);
+ return NULL;
+}
+
+static void *v2i_crld(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ STACK_OF(DIST_POINT) *crld;
+ GENERAL_NAMES *gens = NULL;
+ GENERAL_NAME *gen = NULL;
+ CONF_VALUE *cnf;
+ const int num = sk_CONF_VALUE_num(nval);
+ int i;
+
+ crld = sk_DIST_POINT_new_reserve(NULL, num);
+ if (crld == NULL)
+ goto merr;
+ for (i = 0; i < num; i++) {
+ DIST_POINT *point;
+
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if (cnf->value == NULL) {
+ STACK_OF(CONF_VALUE) *dpsect;
+ dpsect = X509V3_get_section(ctx, cnf->name);
+ if (!dpsect)
+ goto err;
+ point = crldp_from_section(ctx, dpsect);
+ X509V3_section_free(ctx, dpsect);
+ if (point == NULL)
+ goto err;
+ sk_DIST_POINT_push(crld, point); /* no failure as it was reserved */
+ } else {
+ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
+ goto err;
+ if ((gens = GENERAL_NAMES_new()) == NULL)
+ goto merr;
+ if (!sk_GENERAL_NAME_push(gens, gen))
+ goto merr;
+ gen = NULL;
+ if ((point = DIST_POINT_new()) == NULL)
+ goto merr;
+ sk_DIST_POINT_push(crld, point); /* no failure as it was reserved */
+ if ((point->distpoint = DIST_POINT_NAME_new()) == NULL)
+ goto merr;
+ point->distpoint->name.fullname = gens;
+ point->distpoint->type = 0;
+ gens = NULL;
+ }
+ }
+ return crld;
+
+ merr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ err:
+ GENERAL_NAME_free(gen);
+ GENERAL_NAMES_free(gens);
+ sk_DIST_POINT_pop_free(crld, DIST_POINT_free);
+ return NULL;
+}
+
+static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval;
+
+ switch (operation) {
+ case ASN1_OP_NEW_POST:
+ dpn->dpname = NULL;
+ break;
+
+ case ASN1_OP_FREE_POST:
+ X509_NAME_free(dpn->dpname);
+ break;
+ }
+ return 1;
+}
+
+
+ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = {
+ ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0),
+ ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1)
+} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type)
+
+
+IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME)
+
+ASN1_SEQUENCE(DIST_POINT) = {
+ ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0),
+ ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1),
+ ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2)
+} ASN1_SEQUENCE_END(DIST_POINT)
+
+IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT)
+
+ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT)
+ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS)
+
+IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS)
+
+ASN1_SEQUENCE(ISSUING_DIST_POINT) = {
+ ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5)
+} ASN1_SEQUENCE_END(ISSUING_DIST_POINT)
+
+IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
+
+static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
+ int indent);
+static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+
+const X509V3_EXT_METHOD ossl_v3_idp = {
+ NID_issuing_distribution_point, X509V3_EXT_MULTILINE,
+ ASN1_ITEM_ref(ISSUING_DIST_POINT),
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+ v2i_idp,
+ i2r_idp, 0,
+ NULL
+};
+
+static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ ISSUING_DIST_POINT *idp = NULL;
+ CONF_VALUE *cnf;
+ char *name, *val;
+ int i, ret;
+ idp = ISSUING_DIST_POINT_new();
+ if (idp == NULL)
+ goto merr;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ name = cnf->name;
+ val = cnf->value;
+ ret = set_dist_point_name(&idp->distpoint, ctx, cnf);
+ if (ret > 0)
+ continue;
+ if (ret < 0)
+ goto err;
+ if (strcmp(name, "onlyuser") == 0) {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyuser))
+ goto err;
+ } else if (strcmp(name, "onlyCA") == 0) {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyCA))
+ goto err;
+ } else if (strcmp(name, "onlyAA") == 0) {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyattr))
+ goto err;
+ } else if (strcmp(name, "indirectCRL") == 0) {
+ if (!X509V3_get_value_bool(cnf, &idp->indirectCRL))
+ goto err;
+ } else if (strcmp(name, "onlysomereasons") == 0) {
+ if (!set_reasons(&idp->onlysomereasons, val))
+ goto err;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NAME);
+ X509V3_conf_add_error_name_value(cnf);
+ goto err;
+ }
+ }
+ return idp;
+
+ merr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ err:
+ ISSUING_DIST_POINT_free(idp);
+ return NULL;
+}
+
+static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent)
+{
+ int i;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ if (i > 0)
+ BIO_puts(out, "\n");
+ BIO_printf(out, "%*s", indent + 2, "");
+ GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i));
+ }
+ return 1;
+}
+
+static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent)
+{
+ if (dpn->type == 0) {
+ BIO_printf(out, "%*sFull Name:\n", indent, "");
+ print_gens(out, dpn->name.fullname, indent);
+ } else {
+ X509_NAME ntmp;
+ ntmp.entries = dpn->name.relativename;
+ BIO_printf(out, "%*sRelative Name:\n%*s", indent, "", indent + 2, "");
+ X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE);
+ BIO_puts(out, "\n");
+ }
+ return 1;
+}
+
+static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
+ int indent)
+{
+ ISSUING_DIST_POINT *idp = pidp;
+ if (idp->distpoint)
+ print_distpoint(out, idp->distpoint, indent);
+ if (idp->onlyuser > 0)
+ BIO_printf(out, "%*sOnly User Certificates\n", indent, "");
+ if (idp->onlyCA > 0)
+ BIO_printf(out, "%*sOnly CA Certificates\n", indent, "");
+ if (idp->indirectCRL > 0)
+ BIO_printf(out, "%*sIndirect CRL\n", indent, "");
+ if (idp->onlysomereasons)
+ print_reasons(out, "Only Some Reasons", idp->onlysomereasons, indent);
+ if (idp->onlyattr > 0)
+ BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, "");
+ if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0)
+ && (idp->indirectCRL <= 0) && !idp->onlysomereasons
+ && (idp->onlyattr <= 0))
+ BIO_printf(out, "%*s<EMPTY>\n", indent, "");
+
+ return 1;
+}
+
+static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
+ int indent)
+{
+ STACK_OF(DIST_POINT) *crld = pcrldp;
+ DIST_POINT *point;
+ int i;
+ for (i = 0; i < sk_DIST_POINT_num(crld); i++) {
+ if (i > 0)
+ BIO_puts(out, "\n");
+ point = sk_DIST_POINT_value(crld, i);
+ if (point->distpoint)
+ print_distpoint(out, point->distpoint, indent);
+ if (point->reasons)
+ print_reasons(out, "Reasons", point->reasons, indent);
+ if (point->CRLissuer) {
+ BIO_printf(out, "%*sCRL Issuer:\n", indent, "");
+ print_gens(out, point->CRLissuer, indent);
+ }
+ }
+ return 1;
+}
+
+/* Append any nameRelativeToCRLIssuer in dpn to iname, set in dpn->dpname */
+int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, const X509_NAME *iname)
+{
+ int i;
+ STACK_OF(X509_NAME_ENTRY) *frag;
+ X509_NAME_ENTRY *ne;
+
+ if (dpn == NULL || dpn->type != 1)
+ return 1;
+ frag = dpn->name.relativename;
+ X509_NAME_free(dpn->dpname); /* just in case it was already set */
+ dpn->dpname = X509_NAME_dup(iname);
+ if (dpn->dpname == NULL)
+ return 0;
+ for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) {
+ ne = sk_X509_NAME_ENTRY_value(frag, i);
+ if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1))
+ goto err;
+ }
+ /* generate cached encoding of name */
+ if (i2d_X509_NAME(dpn->dpname, NULL) >= 0)
+ return 1;
+
+ err:
+ X509_NAME_free(dpn->dpname);
+ dpn->dpname = NULL;
+ return 0;
+}
diff --git a/crypto/x509/v3_enum.c b/crypto/x509/v3_enum.c
new file mode 100644
index 000000000000..b73a6d55162b
--- /dev/null
+++ b/crypto/x509/v3_enum.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static ENUMERATED_NAMES crl_reasons[] = {
+ {CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"},
+ {CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"},
+ {CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"},
+ {CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed",
+ "affiliationChanged"},
+ {CRL_REASON_SUPERSEDED, "Superseded", "superseded"},
+ {CRL_REASON_CESSATION_OF_OPERATION,
+ "Cessation Of Operation", "cessationOfOperation"},
+ {CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"},
+ {CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"},
+ {CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn",
+ "privilegeWithdrawn"},
+ {CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"},
+ {-1, NULL, NULL}
+};
+
+const X509V3_EXT_METHOD ossl_v3_crl_reason = {
+ NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED),
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE,
+ 0,
+ 0, 0, 0, 0,
+ crl_reasons
+};
+
+char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method,
+ const ASN1_ENUMERATED *e)
+{
+ ENUMERATED_NAMES *enam;
+ long strval;
+
+ strval = ASN1_ENUMERATED_get(e);
+ for (enam = method->usr_data; enam->lname; enam++) {
+ if (strval == enam->bitnum)
+ return OPENSSL_strdup(enam->lname);
+ }
+ return i2s_ASN1_ENUMERATED(method, e);
+}
diff --git a/crypto/x509/v3_extku.c b/crypto/x509/v3_extku.c
new file mode 100644
index 000000000000..4f2a86bdcb2b
--- /dev/null
+++ b/crypto/x509/v3_extku.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD
+ *method, void *eku, STACK_OF(CONF_VALUE)
+ *extlist);
+
+const X509V3_EXT_METHOD ossl_v3_ext_ku = {
+ NID_ext_key_usage, 0,
+ ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
+ 0, 0, 0, 0,
+ 0, 0,
+ i2v_EXTENDED_KEY_USAGE,
+ v2i_EXTENDED_KEY_USAGE,
+ 0, 0,
+ NULL
+};
+
+/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */
+const X509V3_EXT_METHOD ossl_v3_ocsp_accresp = {
+ NID_id_pkix_OCSP_acceptableResponses, 0,
+ ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
+ 0, 0, 0, 0,
+ 0, 0,
+ i2v_EXTENDED_KEY_USAGE,
+ v2i_EXTENDED_KEY_USAGE,
+ 0, 0,
+ NULL
+};
+
+ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT)
+ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE)
+
+IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
+
+static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD
+ *method, void *a, STACK_OF(CONF_VALUE)
+ *ext_list)
+{
+ EXTENDED_KEY_USAGE *eku = a;
+ int i;
+ ASN1_OBJECT *obj;
+ char obj_tmp[80];
+ for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
+ obj = sk_ASN1_OBJECT_value(eku, i);
+ i2t_ASN1_OBJECT(obj_tmp, 80, obj);
+ X509V3_add_value(NULL, obj_tmp, &ext_list);
+ }
+ return ext_list;
+}
+
+static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ EXTENDED_KEY_USAGE *extku;
+ char *extval;
+ ASN1_OBJECT *objtmp;
+ CONF_VALUE *val;
+ const int num = sk_CONF_VALUE_num(nval);
+ int i;
+
+ extku = sk_ASN1_OBJECT_new_reserve(NULL, num);
+ if (extku == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ sk_ASN1_OBJECT_free(extku);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (val->value)
+ extval = val->value;
+ else
+ extval = val->name;
+ if ((objtmp = OBJ_txt2obj(extval, 0)) == NULL) {
+ sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free);
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER,
+ "%s", extval);
+ return NULL;
+ }
+ sk_ASN1_OBJECT_push(extku, objtmp); /* no failure as it was reserved */
+ }
+ return extku;
+}
diff --git a/crypto/x509/v3_genn.c b/crypto/x509/v3_genn.c
new file mode 100644
index 000000000000..1f67bf2f63ab
--- /dev/null
+++ b/crypto/x509/v3_genn.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1999-2023 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+
+ASN1_SEQUENCE(OTHERNAME) = {
+ ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT),
+ /* Maybe have a true ANY DEFINED BY later */
+ ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0)
+} ASN1_SEQUENCE_END(OTHERNAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME)
+
+ASN1_SEQUENCE(EDIPARTYNAME) = {
+ /* DirectoryString is a CHOICE type so use explicit tagging */
+ ASN1_EXP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0),
+ ASN1_EXP(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1)
+} ASN1_SEQUENCE_END(EDIPARTYNAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME)
+
+ASN1_CHOICE(GENERAL_NAME) = {
+ ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME),
+ ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL),
+ ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS),
+ /* Don't decode this */
+ ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400),
+ /* X509_NAME is a CHOICE type so use EXPLICIT */
+ ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME),
+ ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY),
+ ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI),
+ ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD),
+ ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID)
+} ASN1_CHOICE_END(GENERAL_NAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME)
+
+ASN1_ITEM_TEMPLATE(GENERAL_NAMES) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME)
+ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES)
+
+IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
+
+GENERAL_NAME *GENERAL_NAME_dup(const GENERAL_NAME *a)
+{
+ return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME,
+ (d2i_of_void *)d2i_GENERAL_NAME,
+ (char *)a);
+}
+
+static int edipartyname_cmp(const EDIPARTYNAME *a, const EDIPARTYNAME *b)
+{
+ int res;
+
+ if (a == NULL || b == NULL) {
+ /*
+ * Shouldn't be possible in a valid GENERAL_NAME, but we handle it
+ * anyway. OTHERNAME_cmp treats NULL != NULL so we do the same here
+ */
+ return -1;
+ }
+ if (a->nameAssigner == NULL && b->nameAssigner != NULL)
+ return -1;
+ if (a->nameAssigner != NULL && b->nameAssigner == NULL)
+ return 1;
+ /* If we get here then both have nameAssigner set, or both unset */
+ if (a->nameAssigner != NULL) {
+ res = ASN1_STRING_cmp(a->nameAssigner, b->nameAssigner);
+ if (res != 0)
+ return res;
+ }
+ /*
+ * partyName is required, so these should never be NULL. We treat it in
+ * the same way as the a == NULL || b == NULL case above
+ */
+ if (a->partyName == NULL || b->partyName == NULL)
+ return -1;
+
+ return ASN1_STRING_cmp(a->partyName, b->partyName);
+}
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b)
+{
+ int result = -1;
+
+ if (!a || !b || a->type != b->type)
+ return -1;
+ switch (a->type) {
+ case GEN_X400:
+ result = ASN1_STRING_cmp(a->d.x400Address, b->d.x400Address);
+ break;
+
+ case GEN_EDIPARTY:
+ result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName);
+ break;
+
+ case GEN_OTHERNAME:
+ result = OTHERNAME_cmp(a->d.otherName, b->d.otherName);
+ break;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5);
+ break;
+
+ case GEN_DIRNAME:
+ result = X509_NAME_cmp(a->d.dirn, b->d.dirn);
+ break;
+
+ case GEN_IPADD:
+ result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip);
+ break;
+
+ case GEN_RID:
+ result = OBJ_cmp(a->d.rid, b->d.rid);
+ break;
+ }
+ return result;
+}
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b)
+{
+ int result = -1;
+
+ if (!a || !b)
+ return -1;
+ /* Check their type first. */
+ if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0)
+ return result;
+ /* Check the value. */
+ result = ASN1_TYPE_cmp(a->value, b->value);
+ return result;
+}
+
+void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value)
+{
+ switch (type) {
+ case GEN_X400:
+ a->d.x400Address = value;
+ break;
+
+ case GEN_EDIPARTY:
+ a->d.ediPartyName = value;
+ break;
+
+ case GEN_OTHERNAME:
+ a->d.otherName = value;
+ break;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ a->d.ia5 = value;
+ break;
+
+ case GEN_DIRNAME:
+ a->d.dirn = value;
+ break;
+
+ case GEN_IPADD:
+ a->d.ip = value;
+ break;
+
+ case GEN_RID:
+ a->d.rid = value;
+ break;
+ }
+ a->type = type;
+}
+
+void *GENERAL_NAME_get0_value(const GENERAL_NAME *a, int *ptype)
+{
+ if (ptype)
+ *ptype = a->type;
+ switch (a->type) {
+ case GEN_X400:
+ return a->d.x400Address;
+
+ case GEN_EDIPARTY:
+ return a->d.ediPartyName;
+
+ case GEN_OTHERNAME:
+ return a->d.otherName;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ return a->d.ia5;
+
+ case GEN_DIRNAME:
+ return a->d.dirn;
+
+ case GEN_IPADD:
+ return a->d.ip;
+
+ case GEN_RID:
+ return a->d.rid;
+
+ default:
+ return NULL;
+ }
+}
+
+int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
+ ASN1_OBJECT *oid, ASN1_TYPE *value)
+{
+ OTHERNAME *oth;
+ oth = OTHERNAME_new();
+ if (oth == NULL)
+ return 0;
+ ASN1_TYPE_free(oth->value);
+ oth->type_id = oid;
+ oth->value = value;
+ GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth);
+ return 1;
+}
+
+int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen,
+ ASN1_OBJECT **poid, ASN1_TYPE **pvalue)
+{
+ if (gen->type != GEN_OTHERNAME)
+ return 0;
+ if (poid)
+ *poid = gen->d.otherName->type_id;
+ if (pvalue)
+ *pvalue = gen->d.otherName->value;
+ return 1;
+}
diff --git a/crypto/x509/v3_ia5.c b/crypto/x509/v3_ia5.c
new file mode 100644
index 000000000000..6722b6c01f05
--- /dev/null
+++ b/crypto/x509/v3_ia5.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+const X509V3_EXT_METHOD ossl_v3_ns_ia5_list[8] = {
+ EXT_IA5STRING(NID_netscape_base_url),
+ EXT_IA5STRING(NID_netscape_revocation_url),
+ EXT_IA5STRING(NID_netscape_ca_revocation_url),
+ EXT_IA5STRING(NID_netscape_renewal_url),
+ EXT_IA5STRING(NID_netscape_ca_policy_url),
+ EXT_IA5STRING(NID_netscape_ssl_server_name),
+ EXT_IA5STRING(NID_netscape_comment),
+ EXT_END
+};
+
+char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5)
+{
+ char *tmp;
+
+ if (ia5 == NULL || ia5->length <= 0)
+ return NULL;
+ if ((tmp = OPENSSL_malloc(ia5->length + 1)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memcpy(tmp, ia5->data, ia5->length);
+ tmp[ia5->length] = 0;
+ return tmp;
+}
+
+ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, const char *str)
+{
+ ASN1_IA5STRING *ia5;
+ if (str == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
+ return NULL;
+ }
+ if ((ia5 = ASN1_IA5STRING_new()) == NULL)
+ goto err;
+ if (!ASN1_STRING_set((ASN1_STRING *)ia5, str, strlen(str))) {
+ ASN1_IA5STRING_free(ia5);
+ return NULL;
+ }
+#ifdef CHARSET_EBCDIC
+ ebcdic2ascii(ia5->data, ia5->data, ia5->length);
+#endif /* CHARSET_EBCDIC */
+ return ia5;
+ err:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+}
diff --git a/crypto/x509/v3_info.c b/crypto/x509/v3_info.c
new file mode 100644
index 000000000000..5f21ce11e7d5
--- /dev/null
+++ b/crypto/x509/v3_info.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
+ *method, AUTHORITY_INFO_ACCESS
+ *ainfo, STACK_OF(CONF_VALUE)
+ *ret);
+static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
+ *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE)
+ *nval);
+
+const X509V3_EXT_METHOD ossl_v3_info = { NID_info_access, X509V3_EXT_MULTILINE,
+ ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS,
+ (X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
+ 0, 0,
+ NULL
+};
+
+const X509V3_EXT_METHOD ossl_v3_sinfo = { NID_sinfo_access, X509V3_EXT_MULTILINE,
+ ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS,
+ (X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
+ 0, 0,
+ NULL
+};
+
+ASN1_SEQUENCE(ACCESS_DESCRIPTION) = {
+ ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT),
+ ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME)
+} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION)
+
+IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
+
+ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION)
+ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS)
+
+IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(
+ X509V3_EXT_METHOD *method, AUTHORITY_INFO_ACCESS *ainfo,
+ STACK_OF(CONF_VALUE) *ret)
+{
+ ACCESS_DESCRIPTION *desc;
+ int i, nlen;
+ char objtmp[80], *ntmp;
+ CONF_VALUE *vtmp;
+ STACK_OF(CONF_VALUE) *tret = ret;
+
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) {
+ STACK_OF(CONF_VALUE) *tmp;
+
+ desc = sk_ACCESS_DESCRIPTION_value(ainfo, i);
+ tmp = i2v_GENERAL_NAME(method, desc->location, tret);
+ if (tmp == NULL)
+ goto err;
+ tret = tmp;
+ vtmp = sk_CONF_VALUE_value(tret, i);
+ i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
+ nlen = strlen(objtmp) + 3 + strlen(vtmp->name) + 1;
+ ntmp = OPENSSL_malloc(nlen);
+ if (ntmp == NULL)
+ goto err;
+ BIO_snprintf(ntmp, nlen, "%s - %s", objtmp, vtmp->name);
+ OPENSSL_free(vtmp->name);
+ vtmp->name = ntmp;
+ }
+ if (ret == NULL && tret == NULL)
+ return sk_CONF_VALUE_new_null();
+
+ return tret;
+ err:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ if (ret == NULL && tret != NULL)
+ sk_CONF_VALUE_pop_free(tret, X509V3_conf_free);
+ return NULL;
+}
+
+static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
+ *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE)
+ *nval)
+{
+ AUTHORITY_INFO_ACCESS *ainfo = NULL;
+ CONF_VALUE *cnf, ctmp;
+ ACCESS_DESCRIPTION *acc;
+ int i;
+ const int num = sk_CONF_VALUE_num(nval);
+ char *objtmp, *ptmp;
+
+ if ((ainfo = sk_ACCESS_DESCRIPTION_new_reserve(NULL, num)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for (i = 0; i < num; i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if ((acc = ACCESS_DESCRIPTION_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ sk_ACCESS_DESCRIPTION_push(ainfo, acc); /* Cannot fail due to reserve */
+ ptmp = strchr(cnf->name, ';');
+ if (ptmp == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX);
+ goto err;
+ }
+ ctmp.name = ptmp + 1;
+ ctmp.value = cnf->value;
+ if (!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0))
+ goto err;
+ if ((objtmp = OPENSSL_strndup(cnf->name, ptmp - cnf->name)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ acc->method = OBJ_txt2obj(objtmp, 0);
+ if (!acc->method) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_BAD_OBJECT,
+ "value=%s", objtmp);
+ OPENSSL_free(objtmp);
+ goto err;
+ }
+ OPENSSL_free(objtmp);
+ }
+ return ainfo;
+ err:
+ sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
+ return NULL;
+}
+
+int i2a_ACCESS_DESCRIPTION(BIO *bp, const ACCESS_DESCRIPTION *a)
+{
+ i2a_ASN1_OBJECT(bp, a->method);
+ return 2;
+}
diff --git a/crypto/x509/v3_int.c b/crypto/x509/v3_int.c
new file mode 100644
index 000000000000..dae26a5ba9d7
--- /dev/null
+++ b/crypto/x509/v3_int.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+const X509V3_EXT_METHOD ossl_v3_crl_num = {
+ NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ 0,
+ 0, 0, 0, 0, NULL
+};
+
+const X509V3_EXT_METHOD ossl_v3_delta_crl = {
+ NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ 0,
+ 0, 0, 0, 0, NULL
+};
+
+static void *s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx,
+ const char *value)
+{
+ return s2i_ASN1_INTEGER(meth, value);
+}
+
+const X509V3_EXT_METHOD ossl_v3_inhibit_anyp = {
+ NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ (X509V3_EXT_S2I)s2i_asn1_int,
+ 0, 0, 0, 0, NULL
+};
diff --git a/crypto/x509/v3_ist.c b/crypto/x509/v3_ist.c
new file mode 100644
index 000000000000..96c40a3961a2
--- /dev/null
+++ b/crypto/x509/v3_ist.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2020-2024 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+/*
+ * Issuer Sign Tool (1.2.643.100.112) The name of the tool used to signs the subject (ASN1_SEQUENCE)
+ * This extention is required to obtain the status of a qualified certificate at Russian Federation.
+ * RFC-style description is available here: https://tools.ietf.org/html/draft-deremin-rfc4491-bis-04#section-5
+ * Russian Federal Law 63 "Digital Sign" is available here: http://www.consultant.ru/document/cons_doc_LAW_112701/
+ */
+
+ASN1_SEQUENCE(ISSUER_SIGN_TOOL) = {
+ ASN1_SIMPLE(ISSUER_SIGN_TOOL, signTool, ASN1_UTF8STRING),
+ ASN1_SIMPLE(ISSUER_SIGN_TOOL, cATool, ASN1_UTF8STRING),
+ ASN1_SIMPLE(ISSUER_SIGN_TOOL, signToolCert, ASN1_UTF8STRING),
+ ASN1_SIMPLE(ISSUER_SIGN_TOOL, cAToolCert, ASN1_UTF8STRING)
+} ASN1_SEQUENCE_END(ISSUER_SIGN_TOOL)
+
+IMPLEMENT_ASN1_FUNCTIONS(ISSUER_SIGN_TOOL)
+
+
+static ISSUER_SIGN_TOOL *v2i_issuer_sign_tool(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ ISSUER_SIGN_TOOL *ist = ISSUER_SIGN_TOOL_new();
+ int i;
+
+ if (ist == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for (i = 0; i < sk_CONF_VALUE_num(nval); ++i) {
+ CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i);
+
+ if (cnf == NULL) {
+ continue;
+ }
+ if (strcmp(cnf->name, "signTool") == 0) {
+ ist->signTool = ASN1_UTF8STRING_new();
+ if (ist->signTool == NULL
+ || cnf->value == NULL
+ || !ASN1_STRING_set(ist->signTool, cnf->value, strlen(cnf->value))) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ } else if (strcmp(cnf->name, "cATool") == 0) {
+ ist->cATool = ASN1_UTF8STRING_new();
+ if (ist->cATool == NULL
+ || cnf->value == NULL
+ || !ASN1_STRING_set(ist->cATool, cnf->value, strlen(cnf->value))) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ } else if (strcmp(cnf->name, "signToolCert") == 0) {
+ ist->signToolCert = ASN1_UTF8STRING_new();
+ if (ist->signToolCert == NULL
+ || cnf->value == NULL
+ || !ASN1_STRING_set(ist->signToolCert, cnf->value, strlen(cnf->value))) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ } else if (strcmp(cnf->name, "cAToolCert") == 0) {
+ ist->cAToolCert = ASN1_UTF8STRING_new();
+ if (ist->cAToolCert == NULL
+ || cnf->value == NULL
+ || !ASN1_STRING_set(ist->cAToolCert, cnf->value, strlen(cnf->value))) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ } else {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_INVALID_ARGUMENT);
+ goto err;
+ }
+ }
+ return ist;
+
+err:
+ ISSUER_SIGN_TOOL_free(ist);
+ return NULL;
+}
+
+static int i2r_issuer_sign_tool(X509V3_EXT_METHOD *method,
+ ISSUER_SIGN_TOOL *ist, BIO *out,
+ int indent)
+{
+ int new_line = 0;
+
+ if (ist == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+ if (ist->signTool != NULL) {
+ if (new_line == 1) {
+ BIO_write(out, "\n", 1);
+ }
+ BIO_printf(out, "%*ssignTool : ", indent, "");
+ BIO_write(out, ist->signTool->data, ist->signTool->length);
+ new_line = 1;
+ }
+ if (ist->cATool != NULL) {
+ if (new_line == 1) {
+ BIO_write(out, "\n", 1);
+ }
+ BIO_printf(out, "%*scATool : ", indent, "");
+ BIO_write(out, ist->cATool->data, ist->cATool->length);
+ new_line = 1;
+ }
+ if (ist->signToolCert != NULL) {
+ if (new_line == 1) {
+ BIO_write(out, "\n", 1);
+ }
+ BIO_printf(out, "%*ssignToolCert: ", indent, "");
+ BIO_write(out, ist->signToolCert->data, ist->signToolCert->length);
+ new_line = 1;
+ }
+ if (ist->cAToolCert != NULL) {
+ if (new_line == 1) {
+ BIO_write(out, "\n", 1);
+ }
+ BIO_printf(out, "%*scAToolCert : ", indent, "");
+ BIO_write(out, ist->cAToolCert->data, ist->cAToolCert->length);
+ new_line = 1;
+ }
+ return 1;
+}
+
+const X509V3_EXT_METHOD ossl_v3_issuer_sign_tool = {
+ NID_issuerSignTool, /* nid */
+ X509V3_EXT_MULTILINE, /* flags */
+ ASN1_ITEM_ref(ISSUER_SIGN_TOOL), /* template */
+ 0, 0, 0, 0, /* old functions, ignored */
+ 0, /* i2s */
+ 0, /* s2i */
+ 0, /* i2v */
+ (X509V3_EXT_V2I)v2i_issuer_sign_tool, /* v2i */
+ (X509V3_EXT_I2R)i2r_issuer_sign_tool, /* i2r */
+ 0, /* r2i */
+ NULL /* extension-specific data */
+};
diff --git a/crypto/x509/v3_lib.c b/crypto/x509/v3_lib.c
new file mode 100644
index 000000000000..6d91df99550f
--- /dev/null
+++ b/crypto/x509/v3_lib.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright 1999-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
+ */
+
+/* X509 v3 extension utilities */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+
+#include "ext_dat.h"
+
+static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
+
+static int ext_cmp(const X509V3_EXT_METHOD *const *a,
+ const X509V3_EXT_METHOD *const *b);
+static void ext_list_free(X509V3_EXT_METHOD *ext);
+
+int X509V3_EXT_add(X509V3_EXT_METHOD *ext)
+{
+ if (ext_list == NULL
+ && (ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+static int ext_cmp(const X509V3_EXT_METHOD *const *a,
+ const X509V3_EXT_METHOD *const *b)
+{
+ return ((*a)->ext_nid - (*b)->ext_nid);
+}
+
+DECLARE_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *,
+ const X509V3_EXT_METHOD *, ext);
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *,
+ const X509V3_EXT_METHOD *, ext);
+
+#include "standard_exts.h"
+
+const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
+{
+ X509V3_EXT_METHOD tmp;
+ const X509V3_EXT_METHOD *t = &tmp, *const *ret;
+ int idx;
+
+ if (nid < 0)
+ return NULL;
+ tmp.ext_nid = nid;
+ ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT);
+ if (ret)
+ return *ret;
+ if (!ext_list)
+ return NULL;
+ idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
+ return sk_X509V3_EXT_METHOD_value(ext_list, idx);
+}
+
+const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
+{
+ int nid;
+ if ((nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext))) == NID_undef)
+ return NULL;
+ return X509V3_EXT_get_nid(nid);
+}
+
+int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
+{
+ for (; extlist->ext_nid != -1; extlist++)
+ if (!X509V3_EXT_add(extlist))
+ return 0;
+ return 1;
+}
+
+int X509V3_EXT_add_alias(int nid_to, int nid_from)
+{
+ const X509V3_EXT_METHOD *ext;
+ X509V3_EXT_METHOD *tmpext;
+
+ if ((ext = X509V3_EXT_get_nid(nid_from)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_NOT_FOUND);
+ return 0;
+ }
+ if ((tmpext = OPENSSL_malloc(sizeof(*tmpext))) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ *tmpext = *ext;
+ tmpext->ext_nid = nid_to;
+ tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
+ if (!X509V3_EXT_add(tmpext)) {
+ OPENSSL_free(tmpext);
+ return 0;
+ }
+ return 1;
+}
+
+void X509V3_EXT_cleanup(void)
+{
+ sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
+ ext_list = NULL;
+}
+
+static void ext_list_free(X509V3_EXT_METHOD *ext)
+{
+ if (ext->ext_flags & X509V3_EXT_DYNAMIC)
+ OPENSSL_free(ext);
+}
+
+/*
+ * Legacy function: we don't need to add standard extensions any more because
+ * they are now kept in ext_dat.h.
+ */
+
+int X509V3_add_standard_extensions(void)
+{
+ return 1;
+}
+
+/* Return an extension internal structure */
+
+void *X509V3_EXT_d2i(X509_EXTENSION *ext)
+{
+ const X509V3_EXT_METHOD *method;
+ const unsigned char *p;
+ ASN1_STRING *extvalue;
+ int extlen;
+
+ if ((method = X509V3_EXT_get(ext)) == NULL)
+ return NULL;
+ extvalue = X509_EXTENSION_get_data(ext);
+ p = ASN1_STRING_get0_data(extvalue);
+ extlen = ASN1_STRING_length(extvalue);
+ if (method->it)
+ return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
+ return method->d2i(NULL, &p, extlen);
+}
+
+/*-
+ * Get critical flag and decoded version of extension from a NID.
+ * The "idx" variable returns the last found extension and can
+ * be used to retrieve multiple extensions of the same NID.
+ * However multiple extensions with the same NID is usually
+ * due to a badly encoded certificate so if idx is NULL we
+ * choke if multiple extensions exist.
+ * The "crit" variable is set to the critical value.
+ * The return value is the decoded extension or NULL on
+ * error. The actual error can have several different causes,
+ * the value of *crit reflects the cause:
+ * >= 0, extension found but not decoded (reflects critical value).
+ * -1 extension not found.
+ * -2 extension occurs more than once.
+ */
+
+void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit,
+ int *idx)
+{
+ int lastpos, i;
+ X509_EXTENSION *ex, *found_ex = NULL;
+
+ if (!x) {
+ if (idx)
+ *idx = -1;
+ if (crit)
+ *crit = -1;
+ return NULL;
+ }
+ if (idx)
+ lastpos = *idx + 1;
+ else
+ lastpos = 0;
+ if (lastpos < 0)
+ lastpos = 0;
+ for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) {
+ ex = sk_X509_EXTENSION_value(x, i);
+ if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == nid) {
+ if (idx) {
+ *idx = i;
+ found_ex = ex;
+ break;
+ } else if (found_ex) {
+ /* Found more than one */
+ if (crit)
+ *crit = -2;
+ return NULL;
+ }
+ found_ex = ex;
+ }
+ }
+ if (found_ex) {
+ /* Found it */
+ if (crit)
+ *crit = X509_EXTENSION_get_critical(found_ex);
+ return X509V3_EXT_d2i(found_ex);
+ }
+
+ /* Extension not found */
+ if (idx)
+ *idx = -1;
+ if (crit)
+ *crit = -1;
+ return NULL;
+}
+
+/*
+ * This function is a general extension append, replace and delete utility.
+ * The precise operation is governed by the 'flags' value. The 'crit' and
+ * 'value' arguments (if relevant) are the extensions internal structure.
+ */
+
+int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
+ int crit, unsigned long flags)
+{
+ int errcode, extidx = -1;
+ X509_EXTENSION *ext = NULL, *extmp;
+ STACK_OF(X509_EXTENSION) *ret = NULL;
+ unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
+
+ /*
+ * If appending we don't care if it exists, otherwise look for existing
+ * extension.
+ */
+ if (ext_op != X509V3_ADD_APPEND)
+ extidx = X509v3_get_ext_by_NID(*x, nid, -1);
+
+ /* See if extension exists */
+ if (extidx >= 0) {
+ /* If keep existing, nothing to do */
+ if (ext_op == X509V3_ADD_KEEP_EXISTING)
+ return 1;
+ /* If default then its an error */
+ if (ext_op == X509V3_ADD_DEFAULT) {
+ errcode = X509V3_R_EXTENSION_EXISTS;
+ goto err;
+ }
+ /* If delete, just delete it */
+ if (ext_op == X509V3_ADD_DELETE) {
+ extmp = sk_X509_EXTENSION_delete(*x, extidx);
+ if (extmp == NULL)
+ return -1;
+ X509_EXTENSION_free(extmp);
+ return 1;
+ }
+ } else {
+ /*
+ * If replace existing or delete, error since extension must exist
+ */
+ if ((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
+ (ext_op == X509V3_ADD_DELETE)) {
+ errcode = X509V3_R_EXTENSION_NOT_FOUND;
+ goto err;
+ }
+ }
+
+ /*
+ * If we get this far then we have to create an extension: could have
+ * some flags for alternative encoding schemes...
+ */
+
+ ext = X509V3_EXT_i2d(nid, crit, value);
+
+ if (!ext) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_ERROR_CREATING_EXTENSION);
+ return 0;
+ }
+
+ /* If extension exists replace it.. */
+ if (extidx >= 0) {
+ extmp = sk_X509_EXTENSION_value(*x, extidx);
+ X509_EXTENSION_free(extmp);
+ if (!sk_X509_EXTENSION_set(*x, extidx, ext))
+ return -1;
+ return 1;
+ }
+
+ ret = *x;
+ if (*x == NULL
+ && (ret = sk_X509_EXTENSION_new_null()) == NULL)
+ goto m_fail;
+ if (!sk_X509_EXTENSION_push(ret, ext))
+ goto m_fail;
+
+ *x = ret;
+ return 1;
+
+ m_fail:
+ /* ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); */
+ if (ret != *x)
+ sk_X509_EXTENSION_free(ret);
+ X509_EXTENSION_free(ext);
+ return -1;
+
+ err:
+ if (!(flags & X509V3_ADD_SILENT))
+ ERR_raise(ERR_LIB_X509V3, errcode);
+ return 0;
+}
diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c
new file mode 100644
index 000000000000..a51354e7fc4c
--- /dev/null
+++ b/crypto/x509/v3_ncons.c
@@ -0,0 +1,834 @@
+/*
+ * Copyright 2003-2023 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 <stdio.h>
+#include "crypto/asn1.h"
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/bn.h>
+
+#include "crypto/x509.h"
+#include "crypto/punycode.h"
+#include "ext_dat.h"
+
+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 *sub,
+ GENERAL_NAME *gen);
+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
+};
+
+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
+ * numeric constants below).
+ */
+static int ia5ncasecmp(const char *s1, const char *s2, size_t n)
+{
+ for (; n > 0; n--, s1++, s2++) {
+ if (*s1 != *s2) {
+ unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2;
+
+ /* Convert to lower case */
+ if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */)
+ c1 += 0x20;
+ if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */)
+ c2 += 0x20;
+
+ if (c1 == c2)
+ continue;
+
+ if (c1 < c2)
+ return -1;
+
+ /* c1 > c2 */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ int i;
+ CONF_VALUE tval, *val;
+ STACK_OF(GENERAL_SUBTREE) **ptree = NULL;
+ NAME_CONSTRAINTS *ncons = NULL;
+ GENERAL_SUBTREE *sub = NULL;
+
+ ncons = NAME_CONSTRAINTS_new();
+ if (ncons == NULL)
+ goto memerr;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (strncmp(val->name, "permitted", 9) == 0 && val->name[9]) {
+ ptree = &ncons->permittedSubtrees;
+ tval.name = val->name + 10;
+ } else if (strncmp(val->name, "excluded", 8) == 0 && val->name[8]) {
+ ptree = &ncons->excludedSubtrees;
+ tval.name = val->name + 9;
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX);
+ goto err;
+ }
+ tval.value = val->value;
+ sub = GENERAL_SUBTREE_new();
+ if (sub == NULL)
+ goto memerr;
+ if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1))
+ goto err;
+ if (*ptree == NULL)
+ *ptree = sk_GENERAL_SUBTREE_new_null();
+ if (*ptree == NULL || !sk_GENERAL_SUBTREE_push(*ptree, sub))
+ goto memerr;
+ sub = NULL;
+ }
+
+ return ncons;
+
+ memerr:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ err:
+ NAME_CONSTRAINTS_free(ncons);
+ GENERAL_SUBTREE_free(sub);
+
+ return NULL;
+}
+
+static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
+ BIO *bp, int ind)
+{
+ NAME_CONSTRAINTS *ncons = a;
+ do_i2r_name_constraints(method, ncons->permittedSubtrees,
+ bp, ind, "Permitted");
+ if (ncons->permittedSubtrees && ncons->excludedSubtrees)
+ BIO_puts(bp, "\n");
+ do_i2r_name_constraints(method, ncons->excludedSubtrees,
+ bp, ind, "Excluded");
+ return 1;
+}
+
+static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
+ STACK_OF(GENERAL_SUBTREE) *trees,
+ BIO *bp, int ind, const char *name)
+{
+ GENERAL_SUBTREE *tree;
+ int i;
+ if (sk_GENERAL_SUBTREE_num(trees) > 0)
+ BIO_printf(bp, "%*s%s:\n", ind, "", name);
+ for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
+ if (i > 0)
+ BIO_puts(bp, "\n");
+ tree = sk_GENERAL_SUBTREE_value(trees, i);
+ BIO_printf(bp, "%*s", ind + 2, "");
+ if (tree->base->type == GEN_IPADD)
+ print_nc_ipadd(bp, tree->base->d.ip);
+ else
+ GENERAL_NAME_print(bp, tree->base);
+ }
+ return 1;
+}
+
+static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
+{
+ /* ip->length should be 8 or 32 and len1 == len2 == 4 or len1 == len2 == 16 */
+ int len1 = ip->length >= 16 ? 16 : ip->length >= 4 ? 4 : ip->length;
+ int len2 = ip->length - len1;
+ char *ip1 = ossl_ipaddr_to_asc(ip->data, len1);
+ char *ip2 = ossl_ipaddr_to_asc(ip->data + len1, len2);
+ int ret = ip1 != NULL && ip2 != NULL
+ && BIO_printf(bp, "IP:%s/%s", ip1, ip2) > 0;
+
+ OPENSSL_free(ip1);
+ OPENSSL_free(ip2);
+ return ret;
+}
+
+#define NAME_CHECK_MAX (1 << 20)
+
+static int add_lengths(int *out, int a, int b)
+{
+ /* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */
+ if (a < 0)
+ a = 0;
+ if (b < 0)
+ b = 0;
+
+ if (a > INT_MAX - b)
+ return 0;
+ *out = a + b;
+ return 1;
+}
+
+/*-
+ * Check a certificate conforms to a specified set of constraints.
+ * Return values:
+ * X509_V_OK: All constraints obeyed.
+ * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
+ * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
+ * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
+ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type.
+ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
+ * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
+ */
+
+int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
+{
+ int r, i, name_count, constraint_count;
+ X509_NAME *nm;
+
+ nm = X509_get_subject_name(x);
+
+ /*
+ * Guard against certificates with an excessive number of names or
+ * constraints causing a computationally expensive name constraints check.
+ */
+ if (!add_lengths(&name_count, X509_NAME_entry_count(nm),
+ sk_GENERAL_NAME_num(x->altname))
+ || !add_lengths(&constraint_count,
+ sk_GENERAL_SUBTREE_num(nc->permittedSubtrees),
+ sk_GENERAL_SUBTREE_num(nc->excludedSubtrees))
+ || (name_count > 0 && constraint_count > NAME_CHECK_MAX / name_count))
+ return X509_V_ERR_UNSPECIFIED;
+
+ if (X509_NAME_entry_count(nm) > 0) {
+ GENERAL_NAME gntmp;
+ gntmp.type = GEN_DIRNAME;
+ gntmp.d.directoryName = nm;
+
+ r = nc_match(&gntmp, nc);
+
+ if (r != X509_V_OK)
+ return r;
+
+ gntmp.type = GEN_EMAIL;
+
+ /* Process any email address attributes in subject name */
+
+ for (i = -1;;) {
+ const X509_NAME_ENTRY *ne;
+
+ i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i);
+ if (i == -1)
+ break;
+ ne = X509_NAME_get_entry(nm, i);
+ gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
+ if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ r = nc_match(&gntmp, nc);
+
+ if (r != X509_V_OK)
+ return r;
+ }
+
+ }
+
+ for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i);
+ r = nc_match(gen, nc);
+ if (r != X509_V_OK)
+ return r;
+ }
+
+ return X509_V_OK;
+
+}
+
+static int cn2dnsid(ASN1_STRING *cn, unsigned char **dnsid, size_t *idlen)
+{
+ int utf8_length;
+ unsigned char *utf8_value;
+ int i;
+ int isdnsname = 0;
+
+ /* Don't leave outputs uninitialized */
+ *dnsid = NULL;
+ *idlen = 0;
+
+ /*-
+ * Per RFC 6125, DNS-IDs representing internationalized domain names appear
+ * in certificates in A-label encoded form:
+ *
+ * https://tools.ietf.org/html/rfc6125#section-6.4.2
+ *
+ * The same applies to CNs which are intended to represent DNS names.
+ * However, while in the SAN DNS-IDs are IA5Strings, as CNs they may be
+ * needlessly encoded in 16-bit Unicode. We perform a conversion to UTF-8
+ * to ensure that we get an ASCII representation of any CNs that are
+ * representable as ASCII, but just not encoded as ASCII. The UTF-8 form
+ * may contain some non-ASCII octets, and that's fine, such CNs are not
+ * valid legacy DNS names.
+ *
+ * Note, 'int' is the return type of ASN1_STRING_to_UTF8() so that's what
+ * we must use for 'utf8_length'.
+ */
+ if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, cn)) < 0)
+ return X509_V_ERR_OUT_OF_MEM;
+
+ /*
+ * Some certificates have had names that include a *trailing* NUL byte.
+ * Remove these harmless NUL characters. They would otherwise yield false
+ * alarms with the following embedded NUL check.
+ */
+ while (utf8_length > 0 && utf8_value[utf8_length - 1] == '\0')
+ --utf8_length;
+
+ /* Reject *embedded* NULs */
+ if (memchr(utf8_value, 0, utf8_length) != NULL) {
+ OPENSSL_free(utf8_value);
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ }
+
+ /*
+ * XXX: Deviation from strict DNS name syntax, also check names with '_'
+ * Check DNS name syntax, any '-' or '.' must be internal,
+ * and on either side of each '.' we can't have a '-' or '.'.
+ *
+ * If the name has just one label, we don't consider it a DNS name. This
+ * means that "CN=sometld" cannot be precluded by DNS name constraints, but
+ * that is not a problem.
+ */
+ for (i = 0; i < utf8_length; ++i) {
+ unsigned char c = utf8_value[i];
+
+ if ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '_')
+ continue;
+
+ /* Dot and hyphen cannot be first or last. */
+ if (i > 0 && i < utf8_length - 1) {
+ if (c == '-')
+ continue;
+ /*
+ * Next to a dot the preceding and following characters must not be
+ * another dot or a hyphen. Otherwise, record that the name is
+ * plausible, since it has two or more labels.
+ */
+ if (c == '.'
+ && utf8_value[i + 1] != '.'
+ && utf8_value[i - 1] != '-'
+ && utf8_value[i + 1] != '-') {
+ isdnsname = 1;
+ continue;
+ }
+ }
+ isdnsname = 0;
+ break;
+ }
+
+ if (isdnsname) {
+ *dnsid = utf8_value;
+ *idlen = (size_t)utf8_length;
+ return X509_V_OK;
+ }
+ OPENSSL_free(utf8_value);
+ return X509_V_OK;
+}
+
+/*
+ * Check CN against DNS-ID name constraints.
+ */
+int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc)
+{
+ int r, i;
+ const X509_NAME *nm = X509_get_subject_name(x);
+ ASN1_STRING stmp;
+ GENERAL_NAME gntmp;
+
+ stmp.flags = 0;
+ stmp.type = V_ASN1_IA5STRING;
+ gntmp.type = GEN_DNS;
+ gntmp.d.dNSName = &stmp;
+
+ /* Process any commonName attributes in subject name */
+
+ for (i = -1;;) {
+ X509_NAME_ENTRY *ne;
+ ASN1_STRING *cn;
+ unsigned char *idval;
+ size_t idlen;
+
+ i = X509_NAME_get_index_by_NID(nm, NID_commonName, i);
+ if (i == -1)
+ break;
+ ne = X509_NAME_get_entry(nm, i);
+ cn = X509_NAME_ENTRY_get_data(ne);
+
+ /* Only process attributes that look like host names */
+ if ((r = cn2dnsid(cn, &idval, &idlen)) != X509_V_OK)
+ return r;
+ if (idlen == 0)
+ continue;
+
+ stmp.length = idlen;
+ stmp.data = idval;
+ r = nc_match(&gntmp, nc);
+ OPENSSL_free(idval);
+ if (r != X509_V_OK)
+ return r;
+ }
+ return X509_V_OK;
+}
+
+/*
+ * Return nonzero if the GeneralSubtree has valid 'minimum' field
+ * (must be absent or 0) and valid 'maximum' field (must be absent).
+ */
+static int nc_minmax_valid(GENERAL_SUBTREE *sub) {
+ BIGNUM *bn = NULL;
+ int ok = 1;
+
+ if (sub->maximum)
+ ok = 0;
+
+ if (sub->minimum) {
+ bn = ASN1_INTEGER_to_BN(sub->minimum, NULL);
+ if (bn == NULL || !BN_is_zero(bn))
+ ok = 0;
+ BN_free(bn);
+ }
+
+ return ok;
+}
+
+static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
+{
+ GENERAL_SUBTREE *sub;
+ int i, r, match = 0;
+ int effective_type = gen->type;
+
+ /*
+ * We need to compare not gen->type field but an "effective" type because
+ * the otherName field may contain EAI email address treated specially
+ * according to RFC 8398, section 6
+ */
+ if (effective_type == GEN_OTHERNAME &&
+ (OBJ_obj2nid(gen->d.otherName->type_id) == NID_id_on_SmtpUTF8Mailbox)) {
+ effective_type = GEN_EMAIL;
+ }
+
+ /*
+ * Permitted subtrees: if any subtrees exist of matching the type at
+ * least one subtree must match.
+ */
+
+ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
+ sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
+ if (effective_type != sub->base->type
+ || (effective_type == GEN_OTHERNAME &&
+ OBJ_cmp(gen->d.otherName->type_id,
+ sub->base->d.otherName->type_id) != 0))
+ continue;
+ if (!nc_minmax_valid(sub))
+ return X509_V_ERR_SUBTREE_MINMAX;
+ /* If we already have a match don't bother trying any more */
+ if (match == 2)
+ continue;
+ if (match == 0)
+ match = 1;
+ r = nc_match_single(effective_type, gen, sub->base);
+ if (r == X509_V_OK)
+ match = 2;
+ else if (r != X509_V_ERR_PERMITTED_VIOLATION)
+ return r;
+ }
+
+ if (match == 1)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ /* Excluded subtrees: must not match any of these */
+
+ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
+ sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
+ if (effective_type != sub->base->type
+ || (effective_type == GEN_OTHERNAME &&
+ OBJ_cmp(gen->d.otherName->type_id,
+ sub->base->d.otherName->type_id) != 0))
+ continue;
+ if (!nc_minmax_valid(sub))
+ return X509_V_ERR_SUBTREE_MINMAX;
+
+ r = nc_match_single(effective_type, gen, sub->base);
+ if (r == X509_V_OK)
+ return X509_V_ERR_EXCLUDED_VIOLATION;
+ else if (r != X509_V_ERR_PERMITTED_VIOLATION)
+ return r;
+
+ }
+
+ return X509_V_OK;
+
+}
+
+static int nc_match_single(int effective_type, GENERAL_NAME *gen,
+ GENERAL_NAME *base)
+{
+ switch (gen->type) {
+ case GEN_OTHERNAME:
+ switch (effective_type) {
+ case GEN_EMAIL:
+ /*
+ * We are here only when we have SmtpUTF8 name,
+ * so we match the value of othername with base->d.rfc822Name
+ */
+ return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name);
+
+ default:
+ return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
+ }
+
+ case GEN_DIRNAME:
+ return nc_dn(gen->d.directoryName, base->d.directoryName);
+
+ case GEN_DNS:
+ return nc_dns(gen->d.dNSName, base->d.dNSName);
+
+ case GEN_EMAIL:
+ return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
+
+ case GEN_URI:
+ return nc_uri(gen->d.uniformResourceIdentifier,
+ base->d.uniformResourceIdentifier);
+
+ case GEN_IPADD:
+ return nc_ip(gen->d.iPAddress, base->d.iPAddress);
+
+ default:
+ return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
+ }
+
+}
+
+/*
+ * directoryName name constraint matching. The canonical encoding of
+ * X509_NAME makes this comparison easy. It is matched if the subtree is a
+ * subset of the name.
+ */
+
+static int nc_dn(const X509_NAME *nm, const X509_NAME *base)
+{
+ /* Ensure canonical encodings are up to date. */
+ if (nm->modified && i2d_X509_NAME(nm, NULL) < 0)
+ return X509_V_ERR_OUT_OF_MEM;
+ if (base->modified && i2d_X509_NAME(base, NULL) < 0)
+ return X509_V_ERR_OUT_OF_MEM;
+ if (base->canon_enclen > nm->canon_enclen)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ return X509_V_OK;
+}
+
+static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
+{
+ char *baseptr = (char *)base->data;
+ char *dnsptr = (char *)dns->data;
+
+ /* Empty matches everything */
+ if (base->length == 0)
+ return X509_V_OK;
+
+ if (dns->length < base->length)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ /*
+ * Otherwise can add zero or more components on the left so compare RHS
+ * and if dns is longer and expect '.' as preceding character.
+ */
+ if (dns->length > base->length) {
+ dnsptr += dns->length - base->length;
+ if (*baseptr != '.' && dnsptr[-1] != '.')
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ if (ia5ncasecmp(baseptr, dnsptr, base->length))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+}
+
+/*
+ * This function implements comparison between ASCII/U-label in emltype
+ * and A-label in base according to RFC 8398, section 6.
+ * Convert base to U-label and ASCII-parts of domain names, for base
+ * Octet-to-octet comparison of `emltype` and `base` hostname parts
+ * (ASCII-parts should be compared in case-insensitive manner)
+ */
+static int nc_email_eai(ASN1_TYPE *emltype, ASN1_IA5STRING *base)
+{
+ ASN1_UTF8STRING *eml;
+ char *baseptr = NULL;
+ const char *emlptr;
+ const char *emlat;
+ char ulabel[256];
+ size_t size = sizeof(ulabel) - 1;
+ int ret = X509_V_OK;
+ size_t emlhostlen;
+
+ /* We do not accept embedded NUL characters */
+ if (base->length > 0 && memchr(base->data, 0, base->length) != NULL)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ /* 'base' may not be NUL terminated. Create a copy that is */
+ baseptr = OPENSSL_strndup((char *)base->data, base->length);
+ if (baseptr == NULL)
+ return X509_V_ERR_OUT_OF_MEM;
+
+ if (emltype->type != V_ASN1_UTF8STRING) {
+ ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ goto end;
+ }
+
+ eml = emltype->value.utf8string;
+ emlptr = (char *)eml->data;
+ emlat = ia5memrchr(eml, '@');
+
+ if (emlat == NULL) {
+ ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ goto end;
+ }
+
+ memset(ulabel, 0, sizeof(ulabel));
+ /* Special case: initial '.' is RHS match */
+ if (*baseptr == '.') {
+ ulabel[0] = '.';
+ size -= 1;
+ if (ossl_a2ulabel(baseptr, ulabel + 1, &size) <= 0) {
+ ret = X509_V_ERR_UNSPECIFIED;
+ goto end;
+ }
+
+ if ((size_t)eml->length > strlen(ulabel)) {
+ emlptr += eml->length - (strlen(ulabel));
+ /* X509_V_OK */
+ if (ia5ncasecmp(ulabel, emlptr, strlen(ulabel)) == 0)
+ goto end;
+ }
+ ret = X509_V_ERR_PERMITTED_VIOLATION;
+ goto end;
+ }
+
+ if (ossl_a2ulabel(baseptr, ulabel, &size) <= 0) {
+ ret = X509_V_ERR_UNSPECIFIED;
+ goto end;
+ }
+ /* Just have hostname left to match: case insensitive */
+ emlptr = emlat + 1;
+ emlhostlen = IA5_OFFSET_LEN(eml, emlptr);
+ if (emlhostlen != strlen(ulabel)
+ || ia5ncasecmp(ulabel, emlptr, emlhostlen) != 0) {
+ ret = X509_V_ERR_PERMITTED_VIOLATION;
+ goto end;
+ }
+
+ end:
+ OPENSSL_free(baseptr);
+ return ret;
+}
+
+static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
+{
+ const char *baseptr = (char *)base->data;
+ const char *emlptr = (char *)eml->data;
+ const char *baseat = ia5memrchr(base, '@');
+ const char *emlat = ia5memrchr(eml, '@');
+ size_t basehostlen, emlhostlen;
+
+ if (!emlat)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ /* Special case: initial '.' is RHS match */
+ if (!baseat && base->length > 0 && (*baseptr == '.')) {
+ if (eml->length > base->length) {
+ emlptr += eml->length - base->length;
+ if (ia5ncasecmp(baseptr, emlptr, base->length) == 0)
+ return X509_V_OK;
+ }
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ /* If we have anything before '@' match local part */
+
+ if (baseat) {
+ if (baseat != baseptr) {
+ if ((baseat - baseptr) != (emlat - emlptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ if (memchr(baseptr, 0, baseat - baseptr) ||
+ memchr(emlptr, 0, emlat - emlptr))
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ /* Case sensitive match of local part */
+ if (strncmp(baseptr, emlptr, emlat - emlptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+ /* Position base after '@' */
+ baseptr = baseat + 1;
+ }
+ emlptr = emlat + 1;
+ basehostlen = IA5_OFFSET_LEN(base, baseptr);
+ emlhostlen = IA5_OFFSET_LEN(eml, emlptr);
+ /* Just have hostname left to match: case insensitive */
+ if (basehostlen != emlhostlen || ia5ncasecmp(baseptr, emlptr, emlhostlen))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+}
+
+static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
+{
+ const char *baseptr = (char *)base->data;
+ const char *hostptr = (char *)uri->data;
+ const char *p = ia5memchr(uri, (char *)uri->data, ':');
+ int hostlen;
+
+ /* Check for foo:// and skip past it */
+ if (p == NULL
+ || IA5_OFFSET_LEN(uri, p) < 3
+ || p[1] != '/'
+ || p[2] != '/')
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ hostptr = p + 3;
+
+ /* Determine length of hostname part of URI */
+
+ /* Look for a port indicator as end of hostname first */
+
+ p = ia5memchr(uri, hostptr, ':');
+ /* Otherwise look for trailing slash */
+ if (p == NULL)
+ p = ia5memchr(uri, hostptr, '/');
+
+ if (p == NULL)
+ hostlen = IA5_OFFSET_LEN(uri, hostptr);
+ else
+ hostlen = p - hostptr;
+
+ if (hostlen == 0)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ /* Special case: initial '.' is RHS match */
+ if (base->length > 0 && *baseptr == '.') {
+ if (hostlen > base->length) {
+ p = hostptr + hostlen - base->length;
+ if (ia5ncasecmp(p, baseptr, base->length) == 0)
+ return X509_V_OK;
+ }
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ if ((base->length != (int)hostlen)
+ || ia5ncasecmp(hostptr, baseptr, hostlen))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+}
+
+static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base)
+{
+ int hostlen, baselen, i;
+ unsigned char *hostptr, *baseptr, *maskptr;
+ hostptr = ip->data;
+ hostlen = ip->length;
+ baseptr = base->data;
+ baselen = base->length;
+
+ /* Invalid if not IPv4 or IPv6 */
+ if (!((hostlen == 4) || (hostlen == 16)))
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ if (!((baselen == 8) || (baselen == 32)))
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ /* Do not match IPv4 with IPv6 */
+ if (hostlen * 2 != baselen)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ maskptr = base->data + hostlen;
+
+ /* Considering possible not aligned base ipAddress */
+ /* Not checking for wrong mask definition: i.e.: 255.0.255.0 */
+ for (i = 0; i < hostlen; i++)
+ if ((hostptr[i] & maskptr[i]) != (baseptr[i] & maskptr[i]))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+}
diff --git a/crypto/x509/v3_pci.c b/crypto/x509/v3_pci.c
new file mode 100644
index 000000000000..a931e01a9c92
--- /dev/null
+++ b/crypto/x509/v3_pci.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2004-2021 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
+ */
+
+/*
+ * This file is dual-licensed and is also available under the following
+ * terms:
+ *
+ * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR 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.
+ */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext,
+ BIO *out, int indent);
+static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str);
+
+const X509V3_EXT_METHOD ossl_v3_pci =
+ { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
+ 0, 0, 0, 0,
+ 0, 0,
+ NULL, NULL,
+ (X509V3_EXT_I2R)i2r_pci,
+ (X509V3_EXT_R2I)r2i_pci,
+ NULL,
+};
+
+static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
+ BIO *out, int indent)
+{
+ BIO_printf(out, "%*sPath Length Constraint: ", indent, "");
+ if (pci->pcPathLengthConstraint)
+ i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint);
+ else
+ BIO_printf(out, "infinite");
+ BIO_puts(out, "\n");
+ BIO_printf(out, "%*sPolicy Language: ", indent, "");
+ i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
+ if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
+ BIO_printf(out, "\n%*sPolicy Text: %.*s", indent, "",
+ pci->proxyPolicy->policy->length,
+ pci->proxyPolicy->policy->data);
+ return 1;
+}
+
+static int process_pci_value(CONF_VALUE *val,
+ ASN1_OBJECT **language, ASN1_INTEGER **pathlen,
+ ASN1_OCTET_STRING **policy)
+{
+ int free_policy = 0;
+
+ if (strcmp(val->name, "language") == 0) {
+ if (*language) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ if ((*language = OBJ_txt2obj(val->value, 0)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ } else if (strcmp(val->name, "pathlen") == 0) {
+ if (*pathlen) {
+ ERR_raise(ERR_LIB_X509V3,
+ X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ if (!X509V3_get_value_int(val, pathlen)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ } else if (strcmp(val->name, "policy") == 0) {
+ unsigned char *tmp_data = NULL;
+ long val_len;
+
+ if (*policy == NULL) {
+ *policy = ASN1_OCTET_STRING_new();
+ if (*policy == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ free_policy = 1;
+ }
+ if (strncmp(val->value, "hex:", 4) == 0) {
+ unsigned char *tmp_data2 =
+ OPENSSL_hexstr2buf(val->value + 4, &val_len);
+
+ if (!tmp_data2) {
+ X509V3_conf_err(val);
+ goto err;
+ }
+
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + val_len + 1);
+ if (tmp_data) {
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length],
+ tmp_data2, val_len);
+ (*policy)->length += val_len;
+ (*policy)->data[(*policy)->length] = '\0';
+ } else {
+ OPENSSL_free(tmp_data2);
+ /*
+ * realloc failure implies the original data space is b0rked
+ * too!
+ */
+ OPENSSL_free((*policy)->data);
+ (*policy)->data = NULL;
+ (*policy)->length = 0;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ OPENSSL_free(tmp_data2);
+ } else if (strncmp(val->value, "file:", 5) == 0) {
+ unsigned char buf[2048];
+ int n;
+ BIO *b = BIO_new_file(val->value + 5, "r");
+ if (!b) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_BIO_LIB);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ while ((n = BIO_read(b, buf, sizeof(buf))) > 0
+ || (n == 0 && BIO_should_retry(b))) {
+ if (!n)
+ continue;
+
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + n + 1);
+
+ if (!tmp_data) {
+ OPENSSL_free((*policy)->data);
+ (*policy)->data = NULL;
+ (*policy)->length = 0;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ BIO_free_all(b);
+ goto err;
+ }
+
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length], buf, n);
+ (*policy)->length += n;
+ (*policy)->data[(*policy)->length] = '\0';
+ }
+ BIO_free_all(b);
+
+ if (n < 0) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_BIO_LIB);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ } else if (strncmp(val->value, "text:", 5) == 0) {
+ val_len = strlen(val->value + 5);
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + val_len + 1);
+ if (tmp_data) {
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length],
+ val->value + 5, val_len);
+ (*policy)->length += val_len;
+ (*policy)->data[(*policy)->length] = '\0';
+ } else {
+ /*
+ * realloc failure implies the original data space is b0rked
+ * too!
+ */
+ OPENSSL_free((*policy)->data);
+ (*policy)->data = NULL;
+ (*policy)->length = 0;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ } else {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ if (!tmp_data) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ }
+ return 1;
+ err:
+ if (free_policy) {
+ ASN1_OCTET_STRING_free(*policy);
+ *policy = NULL;
+ }
+ return 0;
+}
+
+static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *value)
+{
+ PROXY_CERT_INFO_EXTENSION *pci = NULL;
+ STACK_OF(CONF_VALUE) *vals;
+ ASN1_OBJECT *language = NULL;
+ ASN1_INTEGER *pathlen = NULL;
+ ASN1_OCTET_STRING *policy = NULL;
+ int i, j;
+
+ vals = X509V3_parse_list(value);
+ for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
+ CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
+
+ if (!cnf->name || (*cnf->name != '@' && !cnf->value)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ if (*cnf->name == '@') {
+ STACK_OF(CONF_VALUE) *sect;
+ int success_p = 1;
+
+ sect = X509V3_get_section(ctx, cnf->name + 1);
+ if (!sect) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SECTION);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) {
+ success_p =
+ process_pci_value(sk_CONF_VALUE_value(sect, j),
+ &language, &pathlen, &policy);
+ }
+ X509V3_section_free(ctx, sect);
+ if (!success_p)
+ goto err;
+ } else {
+ if (!process_pci_value(cnf, &language, &pathlen, &policy)) {
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+ }
+
+ /* Language is mandatory */
+ if (!language) {
+ ERR_raise(ERR_LIB_X509V3,
+ X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
+ goto err;
+ }
+ i = OBJ_obj2nid(language);
+ if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) {
+ ERR_raise(ERR_LIB_X509V3,
+ X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
+ goto err;
+ }
+
+ pci = PROXY_CERT_INFO_EXTENSION_new();
+ if (pci == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ pci->proxyPolicy->policyLanguage = language;
+ language = NULL;
+ pci->proxyPolicy->policy = policy;
+ policy = NULL;
+ pci->pcPathLengthConstraint = pathlen;
+ pathlen = NULL;
+ goto end;
+ err:
+ ASN1_OBJECT_free(language);
+ ASN1_INTEGER_free(pathlen);
+ pathlen = NULL;
+ ASN1_OCTET_STRING_free(policy);
+ policy = NULL;
+ PROXY_CERT_INFO_EXTENSION_free(pci);
+ pci = NULL;
+ end:
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ return pci;
+}
diff --git a/crypto/x509/v3_pcia.c b/crypto/x509/v3_pcia.c
new file mode 100644
index 000000000000..7f5985f5e859
--- /dev/null
+++ b/crypto/x509/v3_pcia.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2004-2016 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
+ */
+
+/*
+ * This file is dual-licensed and is also available under the following
+ * terms:
+ *
+ * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR 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.
+ */
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+ASN1_SEQUENCE(PROXY_POLICY) =
+ {
+ ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT),
+ ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(PROXY_POLICY)
+
+IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY)
+
+ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) =
+ {
+ ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER),
+ ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY)
+} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION)
+
+IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)
diff --git a/crypto/x509/v3_pcons.c b/crypto/x509/v3_pcons.c
new file mode 100644
index 000000000000..128365f572e2
--- /dev/null
+++ b/crypto/x509/v3_pcons.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2003-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD
+ *method, void *bcons, STACK_OF(CONF_VALUE)
+ *extlist);
+static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD ossl_v3_policy_constraints = {
+ NID_policy_constraints, 0,
+ ASN1_ITEM_ref(POLICY_CONSTRAINTS),
+ 0, 0, 0, 0,
+ 0, 0,
+ i2v_POLICY_CONSTRAINTS,
+ v2i_POLICY_CONSTRAINTS,
+ NULL, NULL,
+ NULL
+};
+
+ASN1_SEQUENCE(POLICY_CONSTRAINTS) = {
+ ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0),
+ ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1)
+} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
+
+static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD
+ *method, void *a, STACK_OF(CONF_VALUE)
+ *extlist)
+{
+ POLICY_CONSTRAINTS *pcons = a;
+ X509V3_add_value_int("Require Explicit Policy",
+ pcons->requireExplicitPolicy, &extlist);
+ X509V3_add_value_int("Inhibit Policy Mapping",
+ pcons->inhibitPolicyMapping, &extlist);
+ return extlist;
+}
+
+static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ POLICY_CONSTRAINTS *pcons = NULL;
+ CONF_VALUE *val;
+ int i;
+
+ if ((pcons = POLICY_CONSTRAINTS_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ val = sk_CONF_VALUE_value(values, i);
+ if (strcmp(val->name, "requireExplicitPolicy") == 0) {
+ if (!X509V3_get_value_int(val, &pcons->requireExplicitPolicy))
+ goto err;
+ } else if (strcmp(val->name, "inhibitPolicyMapping") == 0) {
+ if (!X509V3_get_value_int(val, &pcons->inhibitPolicyMapping))
+ goto err;
+ } else {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_NAME,
+ "%s", val->name);
+ goto err;
+ }
+ }
+ if (pcons->inhibitPolicyMapping == NULL
+ && pcons->requireExplicitPolicy == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION);
+ goto err;
+ }
+
+ return pcons;
+ err:
+ POLICY_CONSTRAINTS_free(pcons);
+ return NULL;
+}
diff --git a/crypto/x509/v3_pku.c b/crypto/x509/v3_pku.c
new file mode 100644
index 000000000000..8f7e7d681300
--- /dev/null
+++ b/crypto/x509/v3_pku.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method,
+ PKEY_USAGE_PERIOD *usage, BIO *out,
+ int indent);
+
+const X509V3_EXT_METHOD ossl_v3_pkey_usage_period = {
+ NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD),
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL,
+ NULL
+};
+
+ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = {
+ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0),
+ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1)
+} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD)
+
+IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
+
+static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method,
+ PKEY_USAGE_PERIOD *usage, BIO *out,
+ int indent)
+{
+ BIO_printf(out, "%*s", indent, "");
+ if (usage->notBefore) {
+ BIO_write(out, "Not Before: ", 12);
+ ASN1_GENERALIZEDTIME_print(out, usage->notBefore);
+ if (usage->notAfter)
+ BIO_write(out, ", ", 2);
+ }
+ if (usage->notAfter) {
+ BIO_write(out, "Not After: ", 11);
+ ASN1_GENERALIZEDTIME_print(out, usage->notAfter);
+ }
+ return 1;
+}
diff --git a/crypto/x509/v3_pmaps.c b/crypto/x509/v3_pmaps.c
new file mode 100644
index 000000000000..2094e9671141
--- /dev/null
+++ b/crypto/x509/v3_pmaps.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2003-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD
+ *method, void *pmps, STACK_OF(CONF_VALUE)
+ *extlist);
+
+const X509V3_EXT_METHOD ossl_v3_policy_mappings = {
+ NID_policy_mappings, 0,
+ ASN1_ITEM_ref(POLICY_MAPPINGS),
+ 0, 0, 0, 0,
+ 0, 0,
+ i2v_POLICY_MAPPINGS,
+ v2i_POLICY_MAPPINGS,
+ 0, 0,
+ NULL
+};
+
+ASN1_SEQUENCE(POLICY_MAPPING) = {
+ ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT),
+ ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT)
+} ASN1_SEQUENCE_END(POLICY_MAPPING)
+
+ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS,
+ POLICY_MAPPING)
+ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
+
+static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD
+ *method, void *a, STACK_OF(CONF_VALUE)
+ *ext_list)
+{
+ POLICY_MAPPINGS *pmaps = a;
+ POLICY_MAPPING *pmap;
+ int i;
+ char obj_tmp1[80];
+ char obj_tmp2[80];
+
+ for (i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) {
+ pmap = sk_POLICY_MAPPING_value(pmaps, i);
+ i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy);
+ i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy);
+ X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list);
+ }
+ return ext_list;
+}
+
+static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ POLICY_MAPPING *pmap = NULL;
+ ASN1_OBJECT *obj1 = NULL, *obj2 = NULL;
+ CONF_VALUE *val;
+ POLICY_MAPPINGS *pmaps;
+ const int num = sk_CONF_VALUE_num(nval);
+ int i;
+
+ if ((pmaps = sk_POLICY_MAPPING_new_reserve(NULL, num)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (!val->value || !val->name) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER,
+ "%s", val->name);
+ goto err;
+ }
+ obj1 = OBJ_txt2obj(val->name, 0);
+ obj2 = OBJ_txt2obj(val->value, 0);
+ if (!obj1 || !obj2) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER,
+ "%s", val->name);
+ goto err;
+ }
+ pmap = POLICY_MAPPING_new();
+ if (pmap == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ pmap->issuerDomainPolicy = obj1;
+ pmap->subjectDomainPolicy = obj2;
+ obj1 = obj2 = NULL;
+ sk_POLICY_MAPPING_push(pmaps, pmap); /* no failure as it was reserved */
+ }
+ return pmaps;
+ err:
+ ASN1_OBJECT_free(obj1);
+ ASN1_OBJECT_free(obj2);
+ sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free);
+ return NULL;
+}
diff --git a/crypto/x509/v3_prn.c b/crypto/x509/v3_prn.c
new file mode 100644
index 000000000000..1e4516a713c2
--- /dev/null
+++ b/crypto/x509/v3_prn.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1999-2020 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
+ */
+
+/* X509 v3 extension utilities */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+
+/* Extension printing routines */
+
+static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen,
+ unsigned long flag, int indent, int supported);
+
+/* Print out a name+value stack */
+
+void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
+ int ml)
+{
+ int i;
+ CONF_VALUE *nval;
+ if (!val)
+ return;
+ if (!ml || !sk_CONF_VALUE_num(val)) {
+ BIO_printf(out, "%*s", indent, "");
+ if (!sk_CONF_VALUE_num(val))
+ BIO_puts(out, "<EMPTY>\n");
+ }
+ for (i = 0; i < sk_CONF_VALUE_num(val); i++) {
+ if (ml) {
+ if (i > 0)
+ BIO_printf(out, "\n");
+ BIO_printf(out, "%*s", indent, "");
+ }
+ else if (i > 0)
+ BIO_printf(out, ", ");
+ nval = sk_CONF_VALUE_value(val, i);
+ if (!nval->name)
+ BIO_puts(out, nval->value);
+ else if (!nval->value)
+ BIO_puts(out, nval->name);
+#ifndef CHARSET_EBCDIC
+ else
+ BIO_printf(out, "%s:%s", nval->name, nval->value);
+#else
+ else {
+ int len;
+ char *tmp;
+ len = strlen(nval->value) + 1;
+ tmp = OPENSSL_malloc(len);
+ if (tmp != NULL) {
+ ascii2ebcdic(tmp, nval->value, len);
+ BIO_printf(out, "%s:%s", nval->name, tmp);
+ OPENSSL_free(tmp);
+ }
+ }
+#endif
+ }
+}
+
+/* Main routine: print out a general extension */
+
+int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag,
+ int indent)
+{
+ void *ext_str = NULL;
+ char *value = NULL;
+ ASN1_OCTET_STRING *extoct;
+ const unsigned char *p;
+ int extlen;
+ const X509V3_EXT_METHOD *method;
+ STACK_OF(CONF_VALUE) *nval = NULL;
+ int ok = 1;
+
+ extoct = X509_EXTENSION_get_data(ext);
+ p = ASN1_STRING_get0_data(extoct);
+ extlen = ASN1_STRING_length(extoct);
+
+ if ((method = X509V3_EXT_get(ext)) == NULL)
+ return unknown_ext_print(out, p, extlen, flag, indent, 0);
+ if (method->it)
+ ext_str = ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
+ else
+ ext_str = method->d2i(NULL, &p, extlen);
+
+ if (!ext_str)
+ return unknown_ext_print(out, p, extlen, flag, indent, 1);
+
+ if (method->i2s) {
+ if ((value = method->i2s(method, ext_str)) == NULL) {
+ ok = 0;
+ goto err;
+ }
+#ifndef CHARSET_EBCDIC
+ BIO_printf(out, "%*s%s", indent, "", value);
+#else
+ {
+ int len;
+ char *tmp;
+ len = strlen(value) + 1;
+ tmp = OPENSSL_malloc(len);
+ if (tmp != NULL) {
+ ascii2ebcdic(tmp, value, len);
+ BIO_printf(out, "%*s%s", indent, "", tmp);
+ OPENSSL_free(tmp);
+ }
+ }
+#endif
+ } else if (method->i2v) {
+ if ((nval = method->i2v(method, ext_str, NULL)) == NULL) {
+ ok = 0;
+ goto err;
+ }
+ X509V3_EXT_val_prn(out, nval, indent,
+ method->ext_flags & X509V3_EXT_MULTILINE);
+ } else if (method->i2r) {
+ if (!method->i2r(method, ext_str, out, indent))
+ ok = 0;
+ } else
+ ok = 0;
+
+ err:
+ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+ OPENSSL_free(value);
+ if (method->it)
+ ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it));
+ else
+ method->ext_free(ext_str);
+ return ok;
+}
+
+int X509V3_extensions_print(BIO *bp, const char *title,
+ const STACK_OF(X509_EXTENSION) *exts,
+ unsigned long flag, int indent)
+{
+ int i, j;
+
+ if (sk_X509_EXTENSION_num(exts) <= 0)
+ return 1;
+
+ if (title) {
+ BIO_printf(bp, "%*s%s:\n", indent, "", title);
+ indent += 4;
+ }
+
+ for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ex;
+
+ ex = sk_X509_EXTENSION_value(exts, i);
+ obj = X509_EXTENSION_get_object(ex);
+ if ((flag & X509_FLAG_EXTENSIONS_ONLY_KID) != 0
+ && OBJ_obj2nid(obj) != NID_subject_key_identifier
+ && OBJ_obj2nid(obj) != NID_authority_key_identifier)
+ continue;
+ if (indent && BIO_printf(bp, "%*s", indent, "") <= 0)
+ return 0;
+ i2a_ASN1_OBJECT(bp, obj);
+ j = X509_EXTENSION_get_critical(ex);
+ if (BIO_printf(bp, ": %s\n", j ? "critical" : "") <= 0)
+ return 0;
+ if (!X509V3_EXT_print(bp, ex, flag, indent + 4)) {
+ BIO_printf(bp, "%*s", indent + 4, "");
+ ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex));
+ }
+ if (BIO_write(bp, "\n", 1) <= 0)
+ return 0;
+ }
+ return 1;
+}
+
+static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen,
+ unsigned long flag, int indent, int supported)
+{
+ switch (flag & X509V3_EXT_UNKNOWN_MASK) {
+
+ case X509V3_EXT_DEFAULT:
+ return 0;
+
+ case X509V3_EXT_ERROR_UNKNOWN:
+ if (supported)
+ BIO_printf(out, "%*s<Parse Error>", indent, "");
+ else
+ BIO_printf(out, "%*s<Not Supported>", indent, "");
+ return 1;
+
+ case X509V3_EXT_PARSE_UNKNOWN:
+ return ASN1_parse_dump(out, ext, extlen, indent, -1);
+ case X509V3_EXT_DUMP_UNKNOWN:
+ return BIO_dump_indent(out, (const char *)ext, extlen, indent);
+
+ default:
+ return 1;
+ }
+}
+
+#ifndef OPENSSL_NO_STDIO
+int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent)
+{
+ BIO *bio_tmp;
+ int ret;
+
+ if ((bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL)
+ return 0;
+ ret = X509V3_EXT_print(bio_tmp, ext, flag, indent);
+ BIO_free(bio_tmp);
+ return ret;
+}
+#endif
diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c
new file mode 100644
index 000000000000..6461189179f4
--- /dev/null
+++ b/crypto/x509/v3_purp.c
@@ -0,0 +1,1066 @@
+/*
+ * Copyright 1999-2023 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include "crypto/x509.h"
+#include "internal/tsan_assist.h"
+#include "x509_local.h"
+
+static int check_ssl_ca(const X509 *x);
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int purpose_smime(const X509 *x, int require_ca);
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca);
+
+static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
+static void xptable_free(X509_PURPOSE *p);
+
+static X509_PURPOSE xstandard[] = {
+ {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0,
+ check_purpose_ssl_client, "SSL client", "sslclient", NULL},
+ {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
+ check_purpose_ssl_server, "SSL server", "sslserver", NULL},
+ {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
+ check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
+ {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign,
+ "S/MIME signing", "smimesign", NULL},
+ {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0,
+ check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
+ {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign,
+ "CRL signing", "crlsign", NULL},
+ {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check_purpose,
+ "Any Purpose", "any",
+ NULL},
+ {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, check_purpose_ocsp_helper,
+ "OCSP helper", "ocsphelper", NULL},
+ {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0,
+ check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign",
+ NULL},
+};
+
+#define X509_PURPOSE_COUNT OSSL_NELEM(xstandard)
+
+static STACK_OF(X509_PURPOSE) *xptable = NULL;
+
+static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
+{
+ return (*a)->purpose - (*b)->purpose;
+}
+
+/*
+ * As much as I'd like to make X509_check_purpose use a "const" X509* I really
+ * can't because it does recalculate hashes and do other non-const things.
+ * If id == -1 it just calls x509v3_cache_extensions() for its side-effect.
+ * Returns 1 on success, 0 if x does not allow purpose, -1 on (internal) error.
+ */
+int X509_check_purpose(X509 *x, int id, int require_ca)
+{
+ int idx;
+ const X509_PURPOSE *pt;
+
+ if (!ossl_x509v3_cache_extensions(x))
+ return -1;
+ if (id == -1)
+ return 1;
+
+ idx = X509_PURPOSE_get_by_id(id);
+ if (idx == -1)
+ return -1;
+ pt = X509_PURPOSE_get0(idx);
+ return pt->check_purpose(pt, x, require_ca);
+}
+
+int X509_PURPOSE_set(int *p, int purpose)
+{
+ if (X509_PURPOSE_get_by_id(purpose) == -1) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE);
+ return 0;
+ }
+ *p = purpose;
+ return 1;
+}
+
+int X509_PURPOSE_get_count(void)
+{
+ if (!xptable)
+ return X509_PURPOSE_COUNT;
+ return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
+}
+
+X509_PURPOSE *X509_PURPOSE_get0(int idx)
+{
+ if (idx < 0)
+ return NULL;
+ if (idx < (int)X509_PURPOSE_COUNT)
+ return xstandard + idx;
+ return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
+}
+
+int X509_PURPOSE_get_by_sname(const char *sname)
+{
+ int i;
+ X509_PURPOSE *xptmp;
+ for (i = 0; i < X509_PURPOSE_get_count(); i++) {
+ xptmp = X509_PURPOSE_get0(i);
+ if (strcmp(xptmp->sname, sname) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/* Returns -1 on error, else an index => 0 in standard/extended purpose table */
+int X509_PURPOSE_get_by_id(int purpose)
+{
+ X509_PURPOSE tmp;
+ int idx;
+
+ if (purpose >= X509_PURPOSE_MIN && purpose <= X509_PURPOSE_MAX)
+ return purpose - X509_PURPOSE_MIN;
+ if (xptable == NULL)
+ return -1;
+ tmp.purpose = purpose;
+ idx = sk_X509_PURPOSE_find(xptable, &tmp);
+ 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),
+ const char *name, const char *sname, void *arg)
+{
+ int idx;
+ X509_PURPOSE *ptmp;
+
+ /* This is set according to what we change: application can't set it */
+ flags &= ~X509_PURPOSE_DYNAMIC;
+ /* This will always be set for application modified trust entries */
+ flags |= X509_PURPOSE_DYNAMIC_NAME;
+ /* Get existing entry if any */
+ idx = X509_PURPOSE_get_by_id(id);
+ /* Need a new entry */
+ if (idx == -1) {
+ if ((ptmp = OPENSSL_malloc(sizeof(*ptmp))) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ptmp->flags = X509_PURPOSE_DYNAMIC;
+ } else
+ ptmp = X509_PURPOSE_get0(idx);
+
+ /* OPENSSL_free existing name if dynamic */
+ if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(ptmp->name);
+ OPENSSL_free(ptmp->sname);
+ }
+ /* Dup supplied name */
+ ptmp->name = OPENSSL_strdup(name);
+ ptmp->sname = OPENSSL_strdup(sname);
+ if (ptmp->name == NULL|| ptmp->sname == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* Keep the dynamic flag of existing entry */
+ ptmp->flags &= X509_PURPOSE_DYNAMIC;
+ /* Set all other flags */
+ ptmp->flags |= flags;
+
+ ptmp->purpose = id;
+ ptmp->trust = trust;
+ ptmp->check_purpose = ck;
+ ptmp->usr_data = arg;
+
+ /* If its a new entry manage the dynamic table */
+ if (idx == -1) {
+ if (xptable == NULL
+ && (xptable = sk_X509_PURPOSE_new(xp_cmp)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ 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)
+{
+ if (p == NULL)
+ return;
+ if (p->flags & X509_PURPOSE_DYNAMIC) {
+ if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(p->name);
+ OPENSSL_free(p->sname);
+ }
+ OPENSSL_free(p);
+ }
+}
+
+void X509_PURPOSE_cleanup(void)
+{
+ sk_X509_PURPOSE_pop_free(xptable, xptable_free);
+ xptable = NULL;
+}
+
+int X509_PURPOSE_get_id(const X509_PURPOSE *xp)
+{
+ return xp->purpose;
+}
+
+char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp)
+{
+ return xp->name;
+}
+
+char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp)
+{
+ return xp->sname;
+}
+
+int X509_PURPOSE_get_trust(const X509_PURPOSE *xp)
+{
+ return xp->trust;
+}
+
+static int nid_cmp(const int *a, const int *b)
+{
+ return *a - *b;
+}
+
+DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid);
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid);
+
+int X509_supported_extension(X509_EXTENSION *ex)
+{
+ /*
+ * This table is a list of the NIDs of supported extensions: that is
+ * those which are used by the verify process. If an extension is
+ * critical and doesn't appear in this list then the verify process will
+ * normally reject the certificate. The list must be kept in numerical
+ * order because it will be searched using bsearch.
+ */
+ static const int supported_nids[] = {
+ NID_netscape_cert_type, /* 71 */
+ NID_key_usage, /* 83 */
+ 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_id_pkix_OCSP_noCheck, /* 369 */
+ NID_policy_constraints, /* 401 */
+ NID_proxyCertInfo, /* 663 */
+ NID_name_constraints, /* 666 */
+ NID_policy_mappings, /* 747 */
+ NID_inhibit_any_policy /* 748 */
+ };
+
+ int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
+
+ if (ex_nid == NID_undef)
+ return 0;
+
+ if (OBJ_bsearch_nid(&ex_nid, supported_nids, OSSL_NELEM(supported_nids)))
+ return 1;
+ return 0;
+}
+
+/* Returns 1 on success, 0 if x is invalid, -1 on (internal) error. */
+static int setup_dp(const X509 *x, DIST_POINT *dp)
+{
+ const X509_NAME *iname = NULL;
+ int i;
+
+ if (dp->distpoint == NULL && sk_GENERAL_NAME_num(dp->CRLissuer) <= 0) {
+ ERR_raise(ERR_LIB_X509, X509_R_INVALID_DISTPOINT);
+ return 0;
+ }
+ if (dp->reasons != NULL) {
+ if (dp->reasons->length > 0)
+ dp->dp_reasons = dp->reasons->data[0];
+ if (dp->reasons->length > 1)
+ dp->dp_reasons |= (dp->reasons->data[1] << 8);
+ dp->dp_reasons &= CRLDP_ALL_REASONS;
+ } else {
+ dp->dp_reasons = CRLDP_ALL_REASONS;
+ }
+ if (dp->distpoint == NULL || dp->distpoint->type != 1)
+ return 1;
+
+ /* Handle name fragment given by nameRelativeToCRLIssuer */
+ /*
+ * Note that the below way of determining iname is not really compliant
+ * with https://tools.ietf.org/html/rfc5280#section-4.2.1.13
+ * According to it, sk_GENERAL_NAME_num(dp->CRLissuer) MUST be <= 1
+ * and any CRLissuer could be of type different to GEN_DIRNAME.
+ */
+ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+
+ if (gen->type == GEN_DIRNAME) {
+ iname = gen->d.directoryName;
+ break;
+ }
+ }
+ if (iname == NULL)
+ iname = X509_get_issuer_name(x);
+ return DIST_POINT_set_dpname(dp->distpoint, iname) ? 1 : -1;
+}
+
+/* Return 1 on success, 0 if x is invalid, -1 on (internal) error. */
+static int setup_crldp(X509 *x)
+{
+ int i;
+
+ x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &i, NULL);
+ if (x->crldp == NULL && i != -1)
+ return 0;
+
+ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
+ int res = setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+
+ if (res < 1)
+ return res;
+ }
+ return 1;
+}
+
+/* Check that issuer public key algorithm matches subject signature algorithm */
+static int check_sig_alg_match(const EVP_PKEY *issuer_key, const X509 *subject)
+{
+ int subj_sig_nid;
+
+ if (issuer_key == NULL)
+ return X509_V_ERR_NO_ISSUER_PUBLIC_KEY;
+ if (OBJ_find_sigid_algs(OBJ_obj2nid(subject->cert_info.signature.algorithm),
+ NULL, &subj_sig_nid) == 0)
+ return X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM;
+ if (EVP_PKEY_is_a(issuer_key, OBJ_nid2sn(subj_sig_nid))
+ || (EVP_PKEY_is_a(issuer_key, "RSA") && subj_sig_nid == NID_rsassaPss))
+ return X509_V_OK;
+ return X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH;
+}
+
+#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
+#define ku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_KUSAGE) != 0 && ((x)->ex_kusage & (usage)) == 0)
+#define xku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_XKUSAGE) != 0 && ((x)->ex_xkusage & (usage)) == 0)
+#define ns_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_NSCERT) != 0 && ((x)->ex_nscert & (usage)) == 0)
+
+/*
+ * Cache info on various X.509v3 extensions and further derived information,
+ * e.g., if cert 'x' is self-issued, in x->ex_flags and other internal fields.
+ * x->sha1_hash is filled in, or else EXFLAG_NO_FINGERPRINT is set in x->flags.
+ * X509_SIG_INFO_VALID is set in x->flags if x->siginf was filled successfully.
+ * Set EXFLAG_INVALID and return 0 in case the certificate is invalid.
+ */
+int ossl_x509v3_cache_extensions(X509 *x)
+{
+ BASIC_CONSTRAINTS *bs;
+ PROXY_CERT_INFO_EXTENSION *pci;
+ ASN1_BIT_STRING *usage;
+ ASN1_BIT_STRING *ns;
+ EXTENDED_KEY_USAGE *extusage;
+ int i;
+ int res;
+
+#ifdef tsan_ld_acq
+ /* Fast lock-free check, see end of the function for details. */
+ if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached))
+ return (x->ex_flags & EXFLAG_INVALID) == 0;
+#endif
+
+ if (!CRYPTO_THREAD_write_lock(x->lock))
+ return 0;
+ if (x->ex_flags & EXFLAG_SET) { /* Cert has already been processed */
+ CRYPTO_THREAD_unlock(x->lock);
+ return (x->ex_flags & EXFLAG_INVALID) == 0;
+ }
+
+ /* Cache the SHA1 digest of the cert */
+ if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
+ x->ex_flags |= EXFLAG_NO_FINGERPRINT;
+
+ ERR_set_mark();
+
+ /* V1 should mean no extensions ... */
+ if (X509_get_version(x) == X509_VERSION_1)
+ x->ex_flags |= EXFLAG_V1;
+
+ /* Handle basic constraints */
+ x->ex_pathlen = -1;
+ if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL)) != NULL) {
+ if (bs->ca)
+ x->ex_flags |= EXFLAG_CA;
+ if (bs->pathlen != NULL) {
+ /*
+ * The error case !bs->ca is checked by check_chain()
+ * in case ctx->param->flags & X509_V_FLAG_X509_STRICT
+ */
+ if (bs->pathlen->type == V_ASN1_NEG_INTEGER) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN);
+ x->ex_flags |= EXFLAG_INVALID;
+ } else {
+ x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
+ }
+ }
+ BASIC_CONSTRAINTS_free(bs);
+ x->ex_flags |= EXFLAG_BCONS;
+ } else if (i != -1) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+
+ /* Handle proxy certificates */
+ if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &i, NULL)) != NULL) {
+ if (x->ex_flags & EXFLAG_CA
+ || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
+ || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+ if (pci->pcPathLengthConstraint != NULL)
+ x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
+ else
+ x->ex_pcpathlen = -1;
+ PROXY_CERT_INFO_EXTENSION_free(pci);
+ x->ex_flags |= EXFLAG_PROXY;
+ } else if (i != -1) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+
+ /* Handle (basic) key usage */
+ if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL)) != NULL) {
+ x->ex_kusage = 0;
+ if (usage->length > 0) {
+ x->ex_kusage = usage->data[0];
+ if (usage->length > 1)
+ x->ex_kusage |= usage->data[1] << 8;
+ }
+ x->ex_flags |= EXFLAG_KUSAGE;
+ ASN1_BIT_STRING_free(usage);
+ /* Check for empty key usage according to RFC 5280 section 4.2.1.3 */
+ if (x->ex_kusage == 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE);
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+ } else if (i != -1) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+
+ /* Handle extended key usage */
+ x->ex_xkusage = 0;
+ if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) {
+ x->ex_flags |= EXFLAG_XKUSAGE;
+ for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
+ switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
+ case NID_server_auth:
+ x->ex_xkusage |= XKU_SSL_SERVER;
+ break;
+ case NID_client_auth:
+ x->ex_xkusage |= XKU_SSL_CLIENT;
+ break;
+ case NID_email_protect:
+ x->ex_xkusage |= XKU_SMIME;
+ break;
+ case NID_code_sign:
+ x->ex_xkusage |= XKU_CODE_SIGN;
+ break;
+ case NID_ms_sgc:
+ case NID_ns_sgc:
+ x->ex_xkusage |= XKU_SGC;
+ break;
+ case NID_OCSP_sign:
+ x->ex_xkusage |= XKU_OCSP_SIGN;
+ break;
+ case NID_time_stamp:
+ x->ex_xkusage |= XKU_TIMESTAMP;
+ break;
+ case NID_dvcs:
+ x->ex_xkusage |= XKU_DVCS;
+ break;
+ case NID_anyExtendedKeyUsage:
+ x->ex_xkusage |= XKU_ANYEKU;
+ break;
+ default:
+ /* Ignore unknown extended key usage */
+ break;
+ }
+ }
+ sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
+ } else if (i != -1) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+
+ /* Handle legacy Netscape extension */
+ if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &i, NULL)) != NULL) {
+ if (ns->length > 0)
+ x->ex_nscert = ns->data[0];
+ else
+ x->ex_nscert = 0;
+ x->ex_flags |= EXFLAG_NSCERT;
+ ASN1_BIT_STRING_free(ns);
+ } else if (i != -1) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+
+ /* Handle subject key identifier and issuer/authority key identifier */
+ x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &i, NULL);
+ if (x->skid == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+
+ x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &i, NULL);
+ if (x->akid == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+
+ /* Check if subject name matches issuer */
+ if (X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)) == 0) {
+ x->ex_flags |= EXFLAG_SI; /* Cert is self-issued */
+ if (X509_check_akid(x, x->akid) == X509_V_OK /* SKID matches AKID */
+ /* .. and the signature alg matches the PUBKEY alg: */
+ && check_sig_alg_match(X509_get0_pubkey(x), x) == X509_V_OK)
+ x->ex_flags |= EXFLAG_SS; /* indicate self-signed */
+ /* This is very related to ossl_x509_likely_issued(x, x) == X509_V_OK */
+ }
+
+ /* Handle subject alternative names and various other extensions */
+ x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &i, NULL);
+ if (x->altname == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+ x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
+ if (x->nc == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+
+ /* Handle CRL distribution point entries */
+ res = setup_crldp(x);
+ if (res == 0)
+ x->ex_flags |= EXFLAG_INVALID;
+ else if (res < 0)
+ goto err;
+
+#ifndef OPENSSL_NO_RFC3779
+ x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &i, NULL);
+ if (x->rfc3779_addr == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+ x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &i, NULL);
+ if (x->rfc3779_asid == NULL && i != -1)
+ x->ex_flags |= EXFLAG_INVALID;
+#endif
+ for (i = 0; i < X509_get_ext_count(x); i++) {
+ X509_EXTENSION *ex = X509_get_ext(x, i);
+ int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
+
+ if (nid == NID_freshest_crl)
+ x->ex_flags |= EXFLAG_FRESHEST;
+ if (!X509_EXTENSION_get_critical(ex))
+ continue;
+ if (!X509_supported_extension(ex)) {
+ x->ex_flags |= EXFLAG_CRITICAL;
+ break;
+ }
+ switch (nid) {
+ case NID_basic_constraints:
+ x->ex_flags |= EXFLAG_BCONS_CRITICAL;
+ break;
+ case NID_authority_key_identifier:
+ x->ex_flags |= EXFLAG_AKID_CRITICAL;
+ break;
+ case NID_subject_key_identifier:
+ x->ex_flags |= EXFLAG_SKID_CRITICAL;
+ break;
+ case NID_subject_alt_name:
+ x->ex_flags |= EXFLAG_SAN_CRITICAL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Set x->siginf, ignoring errors due to unsupported algos */
+ (void)ossl_x509_init_sig_info(x);
+
+ x->ex_flags |= EXFLAG_SET; /* Indicate that cert has been processed */
+#ifdef tsan_st_rel
+ tsan_st_rel((TSAN_QUALIFIER int *)&x->ex_cached, 1);
+ /*
+ * Above store triggers fast lock-free check in the beginning of the
+ * function. But one has to ensure that the structure is "stable", i.e.
+ * all stores are visible on all processors. Hence the release fence.
+ */
+#endif
+ ERR_pop_to_mark();
+ if ((x->ex_flags & (EXFLAG_INVALID | EXFLAG_NO_FINGERPRINT)) == 0) {
+ CRYPTO_THREAD_unlock(x->lock);
+ return 1;
+ }
+ if ((x->ex_flags & EXFLAG_INVALID) != 0)
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE);
+ /* If computing sha1_hash failed the error queue already reflects this. */
+
+ err:
+ x->ex_flags |= EXFLAG_SET; /* indicate that cert has been processed */
+ CRYPTO_THREAD_unlock(x->lock);
+ return 0;
+}
+
+/*-
+ * CA checks common to all purposes
+ * return codes:
+ * 0 not a CA
+ * 1 is a CA
+ * 2 Only possible in older versions of openSSL when basicConstraints are absent
+ * new versions will not return this value. May be a CA
+ * 3 basicConstraints absent but self-signed V1.
+ * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
+ * 5 Netscape specific CA Flags present
+ */
+
+static int check_ca(const X509 *x)
+{
+ /* keyUsage if present should allow cert signing */
+ if (ku_reject(x, KU_KEY_CERT_SIGN))
+ return 0;
+ if ((x->ex_flags & EXFLAG_BCONS) != 0) {
+ /* If basicConstraints says not a CA then say so */
+ return (x->ex_flags & EXFLAG_CA) != 0;
+ } else {
+ /* We support V1 roots for... uh, I don't really know why. */
+ if ((x->ex_flags & V1_ROOT) == V1_ROOT)
+ return 3;
+ /*
+ * If key usage present it must have certSign so tolerate it
+ */
+ else if (x->ex_flags & EXFLAG_KUSAGE)
+ return 4;
+ /* Older certificates could have Netscape-specific CA types */
+ else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA)
+ return 5;
+ /* Can this still be regarded a CA certificate? I doubt it. */
+ return 0;
+ }
+}
+
+void X509_set_proxy_flag(X509 *x)
+{
+ if (CRYPTO_THREAD_write_lock(x->lock)) {
+ x->ex_flags |= EXFLAG_PROXY;
+ CRYPTO_THREAD_unlock(x->lock);
+ }
+}
+
+void X509_set_proxy_pathlen(X509 *x, long l)
+{
+ x->ex_pcpathlen = l;
+}
+
+int X509_check_ca(X509 *x)
+{
+ /* Note 0 normally means "not a CA" - but in this case means error. */
+ if (!ossl_x509v3_cache_extensions(x))
+ return 0;
+
+ return check_ca(x);
+}
+
+/* Check SSL CA: common checks for SSL client and server. */
+static int check_ssl_ca(const X509 *x)
+{
+ int ca_ret = check_ca(x);
+
+ if (ca_ret == 0)
+ return 0;
+ /* Check nsCertType if present */
+ return ca_ret != 5 || (x->ex_nscert & NS_SSL_CA) != 0;
+}
+
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ if (xku_reject(x, XKU_SSL_CLIENT))
+ return 0;
+ if (require_ca)
+ return check_ssl_ca(x);
+ /* We need to do digital signatures or key agreement */
+ if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT))
+ return 0;
+ /* nsCertType if present should allow SSL client use */
+ if (ns_reject(x, NS_SSL_CLIENT))
+ return 0;
+ return 1;
+}
+
+/*
+ * Key usage needed for TLS/SSL server: digital signature, encipherment or
+ * key agreement. The ssl code can check this more thoroughly for individual
+ * key types.
+ */
+#define KU_TLS \
+ KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT
+
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC))
+ return 0;
+ if (require_ca)
+ return check_ssl_ca(x);
+
+ if (ns_reject(x, NS_SSL_SERVER))
+ return 0;
+ if (ku_reject(x, KU_TLS))
+ return 0;
+
+ return 1;
+
+}
+
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ int ret;
+ ret = check_purpose_ssl_server(xp, x, require_ca);
+ if (!ret || require_ca)
+ return ret;
+ /* We need to encipher or Netscape complains */
+ if (ku_reject(x, KU_KEY_ENCIPHERMENT))
+ return 0;
+ return ret;
+}
+
+/* common S/MIME checks */
+static int purpose_smime(const X509 *x, int require_ca)
+{
+ if (xku_reject(x, XKU_SMIME))
+ return 0;
+ if (require_ca) {
+ int ca_ret;
+ ca_ret = check_ca(x);
+ if (ca_ret == 0)
+ return 0;
+ /* Check nsCertType if present */
+ if (ca_ret != 5 || x->ex_nscert & NS_SMIME_CA)
+ return ca_ret;
+ else
+ return 0;
+ }
+ if (x->ex_flags & EXFLAG_NSCERT) {
+ if (x->ex_nscert & NS_SMIME)
+ return 1;
+ /* Workaround for some buggy certificates */
+ if (x->ex_nscert & NS_SSL_CLIENT)
+ return 2;
+ return 0;
+ }
+ return 1;
+}
+
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ int ret;
+ ret = purpose_smime(x, require_ca);
+ if (!ret || require_ca)
+ return ret;
+ if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION))
+ return 0;
+ return ret;
+}
+
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ int ret;
+ ret = purpose_smime(x, require_ca);
+ if (!ret || require_ca)
+ return ret;
+ if (ku_reject(x, KU_KEY_ENCIPHERMENT))
+ return 0;
+ return ret;
+}
+
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ if (require_ca) {
+ int ca_ret;
+ if ((ca_ret = check_ca(x)) != 2)
+ return ca_ret;
+ else
+ return 0;
+ }
+ if (ku_reject(x, KU_CRL_SIGN))
+ return 0;
+ return 1;
+}
+
+/*
+ * OCSP helper: this is *not* a full OCSP check. It just checks that each CA
+ * is valid. Additional checks must be made on the chain.
+ */
+static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ /*
+ * Must be a valid CA. Should we really support the "I don't know" value
+ * (2)?
+ */
+ if (require_ca)
+ return check_ca(x);
+ /* Leaf certificate is checked in OCSP_verify() */
+ return 1;
+}
+
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ int i_ext;
+
+ /* If ca is true we must return if this is a valid CA certificate. */
+ if (require_ca)
+ return check_ca(x);
+
+ /*
+ * Check the optional key usage field:
+ * if Key Usage is present, it must be one of digitalSignature
+ * and/or nonRepudiation (other values are not consistent and shall
+ * be rejected).
+ */
+ if ((x->ex_flags & EXFLAG_KUSAGE)
+ && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
+ !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
+ return 0;
+
+ /* Only time stamp key usage is permitted and it's required. */
+ if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
+ return 0;
+
+ /* Extended Key Usage MUST be critical */
+ 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))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x,
+ int require_ca)
+{
+ return 1;
+}
+
+/*-
+ * Various checks to see if one certificate potentially issued the second.
+ * This can be used to prune a set of possible issuer certificates which
+ * have been looked up using some simple method such as by subject name.
+ * These are:
+ * 1. issuer_name(subject) == subject_name(issuer)
+ * 2. If akid(subject) exists, it matches the respective issuer fields.
+ * 3. subject signature algorithm == issuer public key algorithm
+ * 4. If key_usage(issuer) exists, it allows for signing subject.
+ * Note that this does not include actually checking the signature.
+ * Returns 0 for OK, or positive for reason for mismatch
+ * where reason codes match those for X509_verify_cert().
+ */
+int X509_check_issued(X509 *issuer, X509 *subject)
+{
+ int ret;
+
+ if ((ret = ossl_x509_likely_issued(issuer, subject)) != X509_V_OK)
+ return ret;
+ return ossl_x509_signing_allowed(issuer, subject);
+}
+
+/* do the checks 1., 2., and 3. as described above for X509_check_issued() */
+int ossl_x509_likely_issued(X509 *issuer, X509 *subject)
+{
+ int ret;
+
+ if (X509_NAME_cmp(X509_get_subject_name(issuer),
+ X509_get_issuer_name(subject)) != 0)
+ return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+
+ /* set issuer->skid and subject->akid */
+ if (!ossl_x509v3_cache_extensions(issuer)
+ || !ossl_x509v3_cache_extensions(subject))
+ return X509_V_ERR_UNSPECIFIED;
+
+ ret = X509_check_akid(issuer, subject->akid);
+ if (ret != X509_V_OK)
+ return ret;
+
+ /* Check if the subject signature alg matches the issuer's PUBKEY alg */
+ return check_sig_alg_match(X509_get0_pubkey(issuer), subject);
+}
+
+/*-
+ * Check if certificate I<issuer> is allowed to issue certificate I<subject>
+ * according to the B<keyUsage> field of I<issuer> if present
+ * depending on any proxyCertInfo extension of I<subject>.
+ * Returns 0 for OK, or positive for reason for rejection
+ * where reason codes match those for X509_verify_cert().
+ */
+int ossl_x509_signing_allowed(const X509 *issuer, const X509 *subject)
+{
+ if (subject->ex_flags & EXFLAG_PROXY) {
+ if (ku_reject(issuer, KU_DIGITAL_SIGNATURE))
+ return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+ } else if (ku_reject(issuer, KU_KEY_CERT_SIGN))
+ return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+ return X509_V_OK;
+}
+
+int X509_check_akid(const X509 *issuer, const AUTHORITY_KEYID *akid)
+{
+ if (akid == NULL)
+ return X509_V_OK;
+
+ /* Check key ids (if present) */
+ if (akid->keyid && issuer->skid &&
+ ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid))
+ return X509_V_ERR_AKID_SKID_MISMATCH;
+ /* Check serial number */
+ if (akid->serial &&
+ ASN1_INTEGER_cmp(X509_get0_serialNumber(issuer), akid->serial))
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ /* Check issuer name */
+ if (akid->issuer) {
+ /*
+ * Ugh, for some peculiar reason AKID includes SEQUENCE OF
+ * GeneralName. So look for a DirName. There may be more than one but
+ * we only take any notice of the first.
+ */
+ GENERAL_NAMES *gens;
+ GENERAL_NAME *gen;
+ X509_NAME *nm = NULL;
+ int i;
+ gens = akid->issuer;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if (gen->type == GEN_DIRNAME) {
+ nm = gen->d.dirn;
+ break;
+ }
+ }
+ if (nm != NULL && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)) != 0)
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ }
+ 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, 0);
+ return x->ex_flags;
+}
+
+uint32_t X509_get_key_usage(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return 0;
+ 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 */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return 0;
+ 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 */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return NULL;
+ return x->skid;
+}
+
+const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return NULL;
+ return (x->akid != NULL ? x->akid->keyid : NULL);
+}
+
+const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return NULL;
+ return (x->akid != NULL ? x->akid->issuer : NULL);
+}
+
+const ASN1_INTEGER *X509_get0_authority_serial(X509 *x)
+{
+ /* Call for side-effect of computing hash and caching extensions */
+ if (X509_check_purpose(x, -1, 0) != 1)
+ return NULL;
+ return (x->akid != NULL ? x->akid->serial : NULL);
+}
+
+long X509_get_pathlen(X509 *x)
+{
+ /* Called for side effect of caching extensions */
+ if (X509_check_purpose(x, -1, 0) != 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, 0) != 1
+ || (x->ex_flags & EXFLAG_PROXY) == 0)
+ return -1;
+ return x->ex_pcpathlen;
+}
diff --git a/crypto/x509/v3_san.c b/crypto/x509/v3_san.c
new file mode 100644
index 000000000000..d4999f1fc6c7
--- /dev/null
+++ b/crypto/x509/v3_san.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include "crypto/x509.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/bio.h>
+#include "ext_dat.h"
+
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p);
+static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens);
+static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
+static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
+
+const X509V3_EXT_METHOD ossl_v3_alt[3] = {
+ {NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
+ (X509V3_EXT_V2I)v2i_subject_alt,
+ NULL, NULL, NULL},
+
+ {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
+ (X509V3_EXT_V2I)v2i_issuer_alt,
+ NULL, NULL, NULL},
+
+ {NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
+ NULL, NULL, NULL, NULL},
+};
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+ GENERAL_NAMES *gens,
+ STACK_OF(CONF_VALUE) *ret)
+{
+ int i;
+ GENERAL_NAME *gen;
+ STACK_OF(CONF_VALUE) *tmpret = NULL, *origret = ret;
+
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ /*
+ * i2v_GENERAL_NAME allocates ret if it is NULL. If something goes
+ * wrong we need to free the stack - but only if it was empty when we
+ * originally entered this function.
+ */
+ tmpret = i2v_GENERAL_NAME(method, gen, ret);
+ if (tmpret == NULL) {
+ if (origret == NULL)
+ sk_CONF_VALUE_pop_free(ret, X509V3_conf_free);
+ return NULL;
+ }
+ ret = tmpret;
+ }
+ if (ret == NULL)
+ return sk_CONF_VALUE_new_null();
+ return ret;
+}
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
+ GENERAL_NAME *gen,
+ STACK_OF(CONF_VALUE) *ret)
+{
+ char othername[300];
+ char oline[256], *tmp;
+
+ switch (gen->type) {
+ case GEN_OTHERNAME:
+ switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
+ case NID_id_on_SmtpUTF8Mailbox:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !x509v3_add_len_value_uchar("othername: SmtpUTF8Mailbox:",
+ gen->d.otherName->value->value.utf8string->data,
+ gen->d.otherName->value->value.utf8string->length,
+ &ret))
+ return NULL;
+ break;
+ case NID_XmppAddr:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !x509v3_add_len_value_uchar("othername: XmppAddr:",
+ gen->d.otherName->value->value.utf8string->data,
+ gen->d.otherName->value->value.utf8string->length,
+ &ret))
+ return NULL;
+ break;
+ case NID_SRVName:
+ if (gen->d.otherName->value->type != V_ASN1_IA5STRING
+ || !x509v3_add_len_value_uchar("othername: SRVName:",
+ gen->d.otherName->value->value.ia5string->data,
+ gen->d.otherName->value->value.ia5string->length,
+ &ret))
+ return NULL;
+ break;
+ case NID_ms_upn:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !x509v3_add_len_value_uchar("othername: UPN:",
+ gen->d.otherName->value->value.utf8string->data,
+ gen->d.otherName->value->value.utf8string->length,
+ &ret))
+ return NULL;
+ break;
+ case NID_NAIRealm:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !x509v3_add_len_value_uchar("othername: NAIRealm:",
+ gen->d.otherName->value->value.utf8string->data,
+ gen->d.otherName->value->value.utf8string->length,
+ &ret))
+ return NULL;
+ break;
+ default:
+ if (OBJ_obj2txt(oline, sizeof(oline), gen->d.otherName->type_id, 0) > 0)
+ BIO_snprintf(othername, sizeof(othername), "othername: %s:",
+ oline);
+ else
+ OPENSSL_strlcpy(othername, "othername:", sizeof(othername));
+
+ /* check if the value is something printable */
+ if (gen->d.otherName->value->type == V_ASN1_IA5STRING) {
+ if (x509v3_add_len_value_uchar(othername,
+ gen->d.otherName->value->value.ia5string->data,
+ gen->d.otherName->value->value.ia5string->length,
+ &ret))
+ return ret;
+ }
+ if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ if (x509v3_add_len_value_uchar(othername,
+ gen->d.otherName->value->value.utf8string->data,
+ gen->d.otherName->value->value.utf8string->length,
+ &ret))
+ return ret;
+ }
+ if (!X509V3_add_value(othername, "<unsupported>", &ret))
+ return NULL;
+ break;
+ }
+ break;
+
+ case GEN_X400:
+ if (!X509V3_add_value("X400Name", "<unsupported>", &ret))
+ return NULL;
+ break;
+
+ case GEN_EDIPARTY:
+ if (!X509V3_add_value("EdiPartyName", "<unsupported>", &ret))
+ return NULL;
+ break;
+
+ case GEN_EMAIL:
+ if (!x509v3_add_len_value_uchar("email", gen->d.ia5->data,
+ gen->d.ia5->length, &ret))
+ return NULL;
+ break;
+
+ case GEN_DNS:
+ if (!x509v3_add_len_value_uchar("DNS", gen->d.ia5->data,
+ gen->d.ia5->length, &ret))
+ return NULL;
+ break;
+
+ case GEN_URI:
+ if (!x509v3_add_len_value_uchar("URI", gen->d.ia5->data,
+ gen->d.ia5->length, &ret))
+ return NULL;
+ break;
+
+ case GEN_DIRNAME:
+ if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) == NULL
+ || !X509V3_add_value("DirName", oline, &ret))
+ return NULL;
+ break;
+
+ case GEN_IPADD:
+ tmp = ossl_ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL || !X509V3_add_value("IP Address", tmp, &ret))
+ ret = NULL;
+ OPENSSL_free(tmp);
+ break;
+
+ case GEN_RID:
+ i2t_ASN1_OBJECT(oline, 256, gen->d.rid);
+ if (!X509V3_add_value("Registered ID", oline, &ret))
+ return NULL;
+ break;
+ }
+ return ret;
+}
+
+int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
+{
+ char *tmp;
+ int nid;
+
+ switch (gen->type) {
+ case GEN_OTHERNAME:
+ nid = OBJ_obj2nid(gen->d.otherName->type_id);
+ /* Validate the types are as we expect before we use them */
+ if ((nid == NID_SRVName
+ && gen->d.otherName->value->type != V_ASN1_IA5STRING)
+ || (nid != NID_SRVName
+ && gen->d.otherName->value->type != V_ASN1_UTF8STRING)) {
+ BIO_printf(out, "othername:<unsupported>");
+ break;
+ }
+
+ switch (nid) {
+ case NID_id_on_SmtpUTF8Mailbox:
+ BIO_printf(out, "othername:SmtpUTF8Mailbox:%.*s",
+ gen->d.otherName->value->value.utf8string->length,
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_XmppAddr:
+ BIO_printf(out, "othername:XmppAddr:%.*s",
+ gen->d.otherName->value->value.utf8string->length,
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_SRVName:
+ BIO_printf(out, "othername:SRVName:%.*s",
+ gen->d.otherName->value->value.ia5string->length,
+ gen->d.otherName->value->value.ia5string->data);
+ break;
+ case NID_ms_upn:
+ BIO_printf(out, "othername:UPN:%.*s",
+ gen->d.otherName->value->value.utf8string->length,
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_NAIRealm:
+ BIO_printf(out, "othername:NAIRealm:%.*s",
+ gen->d.otherName->value->value.utf8string->length,
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ default:
+ BIO_printf(out, "othername:<unsupported>");
+ break;
+ }
+ break;
+
+ case GEN_X400:
+ BIO_printf(out, "X400Name:<unsupported>");
+ break;
+
+ case GEN_EDIPARTY:
+ /* Maybe fix this: it is supported now */
+ BIO_printf(out, "EdiPartyName:<unsupported>");
+ break;
+
+ case GEN_EMAIL:
+ BIO_printf(out, "email:");
+ ASN1_STRING_print(out, gen->d.ia5);
+ break;
+
+ case GEN_DNS:
+ BIO_printf(out, "DNS:");
+ ASN1_STRING_print(out, gen->d.ia5);
+ break;
+
+ case GEN_URI:
+ BIO_printf(out, "URI:");
+ ASN1_STRING_print(out, gen->d.ia5);
+ break;
+
+ case GEN_DIRNAME:
+ BIO_printf(out, "DirName:");
+ X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE);
+ break;
+
+ case GEN_IPADD:
+ tmp = ossl_ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL)
+ return 0;
+ BIO_printf(out, "IP Address:%s", tmp);
+ OPENSSL_free(tmp);
+ break;
+
+ case GEN_RID:
+ BIO_printf(out, "Registered ID:");
+ i2a_ASN1_OBJECT(out, gen->d.rid);
+ break;
+ }
+ return 1;
+}
+
+static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ const int num = sk_CONF_VALUE_num(nval);
+ GENERAL_NAMES *gens = sk_GENERAL_NAME_new_reserve(NULL, num);
+ int i;
+
+ if (gens == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ sk_GENERAL_NAME_free(gens);
+ return NULL;
+ }
+ for (i = 0; i < num; i++) {
+ CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i);
+
+ if (!ossl_v3_name_cmp(cnf->name, "issuer")
+ && cnf->value && strcmp(cnf->value, "copy") == 0) {
+ if (!copy_issuer(ctx, gens))
+ goto err;
+ } else {
+ GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf);
+
+ if (gen == NULL)
+ goto err;
+ sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
+ }
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+/* Append subject altname of issuer to issuer alt name of subject */
+
+static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
+{
+ GENERAL_NAMES *ialt = NULL;
+ GENERAL_NAME *gen;
+ X509_EXTENSION *ext;
+ int i, num;
+
+ if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+ return 1;
+ if (!ctx || !ctx->issuer_cert) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS);
+ goto err;
+ }
+ i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1);
+ if (i < 0)
+ return 1;
+ if ((ext = X509_get_ext(ctx->issuer_cert, i)) == NULL
+ || (ialt = X509V3_EXT_d2i(ext)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_ISSUER_DECODE_ERROR);
+ goto err;
+ }
+
+ num = sk_GENERAL_NAME_num(ialt);
+ if (!sk_GENERAL_NAME_reserve(gens, num)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ for (i = 0; i < num; i++) {
+ gen = sk_GENERAL_NAME_value(ialt, i);
+ sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
+ }
+ sk_GENERAL_NAME_free(ialt);
+
+ return 1;
+
+ err:
+ sk_GENERAL_NAME_free(ialt);
+ return 0;
+
+}
+
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ GENERAL_NAMES *gens;
+ CONF_VALUE *cnf;
+ const int num = sk_CONF_VALUE_num(nval);
+ int i;
+
+ gens = sk_GENERAL_NAME_new_reserve(NULL, num);
+ if (gens == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ sk_GENERAL_NAME_free(gens);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if (ossl_v3_name_cmp(cnf->name, "email") == 0
+ && cnf->value && strcmp(cnf->value, "copy") == 0) {
+ if (!copy_email(ctx, gens, 0))
+ goto err;
+ } else if (ossl_v3_name_cmp(cnf->name, "email") == 0
+ && cnf->value && strcmp(cnf->value, "move") == 0) {
+ if (!copy_email(ctx, gens, 1))
+ goto err;
+ } else {
+ GENERAL_NAME *gen;
+ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
+ goto err;
+ sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
+ }
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+/*
+ * Copy any email addresses in a certificate or request to GENERAL_NAMES
+ */
+
+static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
+{
+ X509_NAME *nm;
+ ASN1_IA5STRING *email = NULL;
+ X509_NAME_ENTRY *ne;
+ GENERAL_NAME *gen = NULL;
+ int i = -1;
+
+ if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+ return 1;
+ if (ctx == NULL
+ || (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
+ return 0;
+ }
+ /* Find the subject name */
+ nm = ctx->subject_cert != NULL ?
+ X509_get_subject_name(ctx->subject_cert) :
+ X509_REQ_get_subject_name(ctx->subject_req);
+
+ /* Now add any email address(es) to STACK */
+ while ((i = X509_NAME_get_index_by_NID(nm,
+ NID_pkcs9_emailAddress, i)) >= 0) {
+ ne = X509_NAME_get_entry(nm, i);
+ email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne));
+ if (move_p) {
+ X509_NAME_delete_entry(nm, i);
+ X509_NAME_ENTRY_free(ne);
+ i--;
+ }
+ if (email == NULL || (gen = GENERAL_NAME_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ gen->d.ia5 = email;
+ email = NULL;
+ gen->type = GEN_EMAIL;
+ if (!sk_GENERAL_NAME_push(gens, gen)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ gen = NULL;
+ }
+
+ return 1;
+
+ err:
+ GENERAL_NAME_free(gen);
+ ASN1_IA5STRING_free(email);
+ return 0;
+
+}
+
+GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ GENERAL_NAME *gen;
+ GENERAL_NAMES *gens;
+ CONF_VALUE *cnf;
+ const int num = sk_CONF_VALUE_num(nval);
+ int i;
+
+ gens = sk_GENERAL_NAME_new_reserve(NULL, num);
+ if (gens == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ sk_GENERAL_NAME_free(gens);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
+ goto err;
+ sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, CONF_VALUE *cnf)
+{
+ return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0);
+}
+
+GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, int gen_type, const char *value,
+ int is_nc)
+{
+ char is_string = 0;
+ GENERAL_NAME *gen = NULL;
+
+ if (!value) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE);
+ return NULL;
+ }
+
+ if (out)
+ gen = out;
+ else {
+ gen = GENERAL_NAME_new();
+ if (gen == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ }
+
+ switch (gen_type) {
+ case GEN_URI:
+ case GEN_EMAIL:
+ case GEN_DNS:
+ is_string = 1;
+ break;
+
+ case GEN_RID:
+ {
+ ASN1_OBJECT *obj;
+ if ((obj = OBJ_txt2obj(value, 0)) == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_BAD_OBJECT,
+ "value=%s", value);
+ goto err;
+ }
+ gen->d.rid = obj;
+ }
+ break;
+
+ case GEN_IPADD:
+ if (is_nc)
+ gen->d.ip = a2i_IPADDRESS_NC(value);
+ else
+ gen->d.ip = a2i_IPADDRESS(value);
+ if (gen->d.ip == NULL) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_BAD_IP_ADDRESS,
+ "value=%s", value);
+ goto err;
+ }
+ break;
+
+ case GEN_DIRNAME:
+ if (!do_dirname(gen, value, ctx)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_DIRNAME_ERROR);
+ goto err;
+ }
+ break;
+
+ case GEN_OTHERNAME:
+ if (!do_othername(gen, value, ctx)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_OTHERNAME_ERROR);
+ goto err;
+ }
+ break;
+ default:
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_TYPE);
+ goto err;
+ }
+
+ if (is_string) {
+ if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL ||
+ !ASN1_STRING_set(gen->d.ia5, (unsigned char *)value,
+ strlen(value))) {
+ ASN1_IA5STRING_free(gen->d.ia5);
+ gen->d.ia5 = NULL;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ gen->type = gen_type;
+
+ return gen;
+
+ err:
+ if (!out)
+ GENERAL_NAME_free(gen);
+ return NULL;
+}
+
+GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc)
+{
+ int type;
+
+ char *name, *value;
+
+ name = cnf->name;
+ value = cnf->value;
+
+ if (!value) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE);
+ return NULL;
+ }
+
+ if (!ossl_v3_name_cmp(name, "email"))
+ type = GEN_EMAIL;
+ else if (!ossl_v3_name_cmp(name, "URI"))
+ type = GEN_URI;
+ else if (!ossl_v3_name_cmp(name, "DNS"))
+ type = GEN_DNS;
+ else if (!ossl_v3_name_cmp(name, "RID"))
+ type = GEN_RID;
+ else if (!ossl_v3_name_cmp(name, "IP"))
+ type = GEN_IPADD;
+ else if (!ossl_v3_name_cmp(name, "dirName"))
+ type = GEN_DIRNAME;
+ else if (!ossl_v3_name_cmp(name, "otherName"))
+ type = GEN_OTHERNAME;
+ else {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_OPTION,
+ "name=%s", name);
+ return NULL;
+ }
+
+ return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc);
+
+}
+
+static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
+{
+ char *objtmp = NULL, *p;
+ int objlen;
+
+ if ((p = strchr(value, ';')) == NULL)
+ return 0;
+ if ((gen->d.otherName = OTHERNAME_new()) == NULL)
+ return 0;
+ /*
+ * Free this up because we will overwrite it. no need to free type_id
+ * because it is static
+ */
+ ASN1_TYPE_free(gen->d.otherName->value);
+ if ((gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)) == NULL)
+ goto err;
+ objlen = p - value;
+ objtmp = OPENSSL_strndup(value, objlen);
+ if (objtmp == NULL)
+ goto err;
+ gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0);
+ OPENSSL_free(objtmp);
+ if (!gen->d.otherName->type_id)
+ goto err;
+ return 1;
+
+ err:
+ OTHERNAME_free(gen->d.otherName);
+ gen->d.otherName = NULL;
+ return 0;
+}
+
+static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
+{
+ int ret = 0;
+ STACK_OF(CONF_VALUE) *sk = NULL;
+ X509_NAME *nm;
+
+ if ((nm = X509_NAME_new()) == NULL)
+ goto err;
+ sk = X509V3_get_section(ctx, value);
+ if (!sk) {
+ ERR_raise_data(ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND,
+ "section=%s", value);
+ goto err;
+ }
+ /* FIXME: should allow other character types... */
+ ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC);
+ if (!ret)
+ goto err;
+ gen->d.dirn = nm;
+
+err:
+ if (ret == 0)
+ X509_NAME_free(nm);
+ X509V3_section_free(ctx, sk);
+ return ret;
+}
diff --git a/crypto/x509/v3_skid.c b/crypto/x509/v3_skid.c
new file mode 100644
index 000000000000..18223f2ef496
--- /dev/null
+++ b/crypto/x509/v3_skid.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+#include "ext_dat.h"
+
+static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str);
+const X509V3_EXT_METHOD ossl_v3_skey_id = {
+ NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
+ 0, 0, 0, 0,
+ (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING,
+ (X509V3_EXT_S2I)s2i_skey_id,
+ 0, 0, 0, 0,
+ NULL
+};
+
+char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
+ const ASN1_OCTET_STRING *oct)
+{
+ return OPENSSL_buf2hexstr(oct->data, oct->length);
+}
+
+ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, const char *str)
+{
+ ASN1_OCTET_STRING *oct;
+ long length;
+
+ if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if ((oct->data = OPENSSL_hexstr2buf(str, &length)) == NULL) {
+ ASN1_OCTET_STRING_free(oct);
+ return NULL;
+ }
+
+ oct->length = length;
+
+ return oct;
+
+}
+
+ASN1_OCTET_STRING *ossl_x509_pubkey_hash(X509_PUBKEY *pubkey)
+{
+ ASN1_OCTET_STRING *oct;
+ const unsigned char *pk;
+ int pklen;
+ unsigned char pkey_dig[EVP_MAX_MD_SIZE];
+ unsigned int diglen;
+ const char *propq;
+ OSSL_LIB_CTX *libctx;
+ EVP_MD *md;
+
+ if (pubkey == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
+ return NULL;
+ }
+ if (!ossl_x509_PUBKEY_get0_libctx(&libctx, &propq, pubkey))
+ return NULL;
+ if ((md = EVP_MD_fetch(libctx, SN_sha1, propq)) == NULL)
+ return NULL;
+ if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
+ EVP_MD_free(md);
+ return NULL;
+ }
+
+ X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
+ if (EVP_Digest(pk, pklen, pkey_dig, &diglen, md, NULL)
+ && ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
+ EVP_MD_free(md);
+ return oct;
+ }
+
+ EVP_MD_free(md);
+ ASN1_OCTET_STRING_free(oct);
+ return NULL;
+}
+
+static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str)
+{
+ if (strcmp(str, "none") == 0)
+ return ASN1_OCTET_STRING_new(); /* dummy */
+
+ if (strcmp(str, "hash") != 0)
+ return s2i_ASN1_OCTET_STRING(method, ctx /* not used */, str);
+
+ if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+ return ASN1_OCTET_STRING_new();
+ if (ctx == NULL
+ || (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
+ return NULL;
+ }
+
+ return ossl_x509_pubkey_hash(ctx->subject_cert != NULL ?
+ ctx->subject_cert->cert_info.key :
+ ctx->subject_req->req_info.pubkey);
+}
diff --git a/crypto/x509/v3_sxnet.c b/crypto/x509/v3_sxnet.c
new file mode 100644
index 000000000000..70f5db636c4b
--- /dev/null
+++ b/crypto/x509/v3_sxnet.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 1999-2024 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+/* Support for Thawte strong extranet extension */
+
+#define SXNET_TEST
+
+static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out,
+ int indent);
+#ifdef SXNET_TEST
+static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+#endif
+const X509V3_EXT_METHOD ossl_v3_sxnet = {
+ NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET),
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+#ifdef SXNET_TEST
+ (X509V3_EXT_V2I)sxnet_v2i,
+#else
+ 0,
+#endif
+ (X509V3_EXT_I2R)sxnet_i2r,
+ 0,
+ NULL
+};
+
+ASN1_SEQUENCE(SXNETID) = {
+ ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER),
+ ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(SXNETID)
+
+IMPLEMENT_ASN1_FUNCTIONS(SXNETID)
+
+ASN1_SEQUENCE(SXNET) = {
+ ASN1_SIMPLE(SXNET, version, ASN1_INTEGER),
+ ASN1_SEQUENCE_OF(SXNET, ids, SXNETID)
+} ASN1_SEQUENCE_END(SXNET)
+
+IMPLEMENT_ASN1_FUNCTIONS(SXNET)
+
+static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out,
+ int indent)
+{
+ int64_t v;
+ char *tmp;
+ SXNETID *id;
+ int i;
+
+ /*
+ * Since we add 1 to the version number to display it, we don't support
+ * LONG_MAX since that would cause on overflow.
+ */
+ if (!ASN1_INTEGER_get_int64(&v, sx->version)
+ || v >= LONG_MAX
+ || v < LONG_MIN) {
+ BIO_printf(out, "%*sVersion: <unsupported>", indent, "");
+ } else {
+ long vl = (long)v;
+
+ BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", vl + 1, vl);
+ }
+ for (i = 0; i < sk_SXNETID_num(sx->ids); i++) {
+ id = sk_SXNETID_value(sx->ids, i);
+ tmp = i2s_ASN1_INTEGER(NULL, id->zone);
+ if (tmp == NULL)
+ return 0;
+ BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp);
+ OPENSSL_free(tmp);
+ ASN1_STRING_print(out, id->user);
+ }
+ return 1;
+}
+
+#ifdef SXNET_TEST
+
+/*
+ * NBB: this is used for testing only. It should *not* be used for anything
+ * else because it will just take static IDs from the configuration file and
+ * they should really be separate values for each user.
+ */
+
+static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ CONF_VALUE *cnf;
+ SXNET *sx = NULL;
+ int i;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if (!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) {
+ SXNET_free(sx);
+ return NULL;
+ }
+ }
+ return sx;
+}
+
+#endif
+
+/* Strong Extranet utility functions */
+
+/* Add an id given the zone as an ASCII number */
+
+int SXNET_add_id_asc(SXNET **psx, const char *zone, const char *user, int userlen)
+{
+ ASN1_INTEGER *izone;
+
+ if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE);
+ return 0;
+ }
+ if (!SXNET_add_id_INTEGER(psx, izone, user, userlen)) {
+ ASN1_INTEGER_free(izone);
+ return 0;
+ }
+ return 1;
+}
+
+/* Add an id given the zone as an unsigned long */
+
+int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, const char *user,
+ int userlen)
+{
+ ASN1_INTEGER *izone;
+
+ if ((izone = ASN1_INTEGER_new()) == NULL
+ || !ASN1_INTEGER_set(izone, lzone)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ ASN1_INTEGER_free(izone);
+ return 0;
+ }
+ if (!SXNET_add_id_INTEGER(psx, izone, user, userlen)) {
+ ASN1_INTEGER_free(izone);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Add an id given the zone as an ASN1_INTEGER. Note this version uses the
+ * passed integer and doesn't make a copy so don't free it up afterwards.
+ */
+
+int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, const char *user,
+ int userlen)
+{
+ SXNET *sx = NULL;
+ SXNETID *id = NULL;
+
+ if (psx == NULL || zone == NULL || user == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
+ return 0;
+ }
+ if (userlen == -1)
+ userlen = strlen(user);
+ if (userlen > 64) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_USER_TOO_LONG);
+ return 0;
+ }
+ if (*psx == NULL) {
+ if ((sx = SXNET_new()) == NULL)
+ goto err;
+ if (!ASN1_INTEGER_set(sx->version, 0))
+ goto err;
+ } else
+ sx = *psx;
+ if (SXNET_get_id_INTEGER(sx, zone)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_DUPLICATE_ZONE_ID);
+ if (*psx == NULL)
+ SXNET_free(sx);
+ return 0;
+ }
+
+ if ((id = SXNETID_new()) == NULL)
+ goto err;
+ if (userlen == -1)
+ userlen = strlen(user);
+
+ if (!ASN1_OCTET_STRING_set(id->user, (const unsigned char *)user, userlen))
+ goto err;
+ if (!sk_SXNETID_push(sx->ids, id))
+ goto err;
+ ASN1_INTEGER_free(id->zone);
+ id->zone = zone;
+ *psx = sx;
+ return 1;
+
+ err:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ SXNETID_free(id);
+ if (*psx == NULL)
+ SXNET_free(sx);
+ return 0;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, const char *zone)
+{
+ ASN1_INTEGER *izone;
+ ASN1_OCTET_STRING *oct;
+
+ if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE);
+ return NULL;
+ }
+ oct = SXNET_get_id_INTEGER(sx, izone);
+ ASN1_INTEGER_free(izone);
+ return oct;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone)
+{
+ ASN1_INTEGER *izone;
+ ASN1_OCTET_STRING *oct;
+
+ if ((izone = ASN1_INTEGER_new()) == NULL
+ || !ASN1_INTEGER_set(izone, lzone)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ ASN1_INTEGER_free(izone);
+ return NULL;
+ }
+ oct = SXNET_get_id_INTEGER(sx, izone);
+ ASN1_INTEGER_free(izone);
+ return oct;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone)
+{
+ SXNETID *id;
+ int i;
+ for (i = 0; i < sk_SXNETID_num(sx->ids); i++) {
+ id = sk_SXNETID_value(sx->ids, i);
+ if (!ASN1_INTEGER_cmp(id->zone, zone))
+ return id->user;
+ }
+ return NULL;
+}
diff --git a/crypto/x509/v3_tlsf.c b/crypto/x509/v3_tlsf.c
new file mode 100644
index 000000000000..3a457fa57bee
--- /dev/null
+++ b/crypto/x509/v3_tlsf.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2015-2022 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 "e_os.h"
+#include "internal/cryptlib.h"
+#include <stdio.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+#include "x509_local.h"
+
+static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+ TLS_FEATURE *tls_feature,
+ STACK_OF(CONF_VALUE) *ext_list);
+static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+
+ASN1_ITEM_TEMPLATE(TLS_FEATURE) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, TLS_FEATURE, ASN1_INTEGER)
+static_ASN1_ITEM_TEMPLATE_END(TLS_FEATURE)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE)
+
+const X509V3_EXT_METHOD ossl_v3_tls_feature = {
+ NID_tlsfeature, 0,
+ ASN1_ITEM_ref(TLS_FEATURE),
+ 0, 0, 0, 0,
+ 0, 0,
+ (X509V3_EXT_I2V)i2v_TLS_FEATURE,
+ (X509V3_EXT_V2I)v2i_TLS_FEATURE,
+ 0, 0,
+ NULL
+};
+
+
+typedef struct {
+ long num;
+ const char *name;
+} TLS_FEATURE_NAME;
+
+static TLS_FEATURE_NAME tls_feature_tbl[] = {
+ { 5, "status_request" },
+ { 17, "status_request_v2" }
+};
+
+/*
+ * i2v_TLS_FEATURE converts the TLS_FEATURE structure tls_feature into the
+ * STACK_OF(CONF_VALUE) structure ext_list. STACK_OF(CONF_VALUE) is the format
+ * used by the CONF library to represent a multi-valued extension. ext_list is
+ * returned.
+ */
+static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+ TLS_FEATURE *tls_feature,
+ STACK_OF(CONF_VALUE) *ext_list)
+{
+ int i;
+ size_t j;
+ ASN1_INTEGER *ai;
+ long tlsextid;
+ for (i = 0; i < sk_ASN1_INTEGER_num(tls_feature); i++) {
+ ai = sk_ASN1_INTEGER_value(tls_feature, i);
+ tlsextid = ASN1_INTEGER_get(ai);
+ for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
+ if (tlsextid == tls_feature_tbl[j].num)
+ break;
+ if (j < OSSL_NELEM(tls_feature_tbl))
+ X509V3_add_value(NULL, tls_feature_tbl[j].name, &ext_list);
+ else
+ X509V3_add_value_int(NULL, ai, &ext_list);
+ }
+ return ext_list;
+}
+
+/*
+ * v2i_TLS_FEATURE converts the multi-valued extension nval into a TLS_FEATURE
+ * structure, which is returned if the conversion is successful. In case of
+ * error, NULL is returned.
+ */
+static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ TLS_FEATURE *tlsf;
+ char *extval, *endptr;
+ ASN1_INTEGER *ai = NULL;
+ CONF_VALUE *val;
+ int i;
+ size_t j;
+ long tlsextid;
+
+ if ((tlsf = sk_ASN1_INTEGER_new_null()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (val->value)
+ extval = val->value;
+ else
+ extval = val->name;
+
+ for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
+ if (OPENSSL_strcasecmp(extval, tls_feature_tbl[j].name) == 0)
+ break;
+ if (j < OSSL_NELEM(tls_feature_tbl))
+ tlsextid = tls_feature_tbl[j].num;
+ else {
+ tlsextid = strtol(extval, &endptr, 10);
+ if (((*endptr) != '\0') || (extval == endptr) || (tlsextid < 0) ||
+ (tlsextid > 65535)) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX);
+ X509V3_conf_add_error_name_value(val);
+ goto err;
+ }
+ }
+
+ if ((ai = ASN1_INTEGER_new()) == NULL
+ || !ASN1_INTEGER_set(ai, tlsextid)
+ || sk_ASN1_INTEGER_push(tlsf, ai) <= 0) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* So it doesn't get purged if an error occurs next time around */
+ ai = NULL;
+ }
+ return tlsf;
+
+ err:
+ sk_ASN1_INTEGER_pop_free(tlsf, ASN1_INTEGER_free);
+ ASN1_INTEGER_free(ai);
+ return NULL;
+}
diff --git a/crypto/x509/v3_utf8.c b/crypto/x509/v3_utf8.c
new file mode 100644
index 000000000000..1c4f79c4cd9b
--- /dev/null
+++ b/crypto/x509/v3_utf8.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020-2021 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 <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+/*
+ * Subject Sign Tool (1.2.643.100.111) The name of the tool used to signs the subject (UTF8String)
+ * This extention is required to obtain the status of a qualified certificate at Russian Federation.
+ * RFC-style description is available here: https://tools.ietf.org/html/draft-deremin-rfc4491-bis-04#section-5
+ * Russian Federal Law 63 "Digital Sign" is available here: http://www.consultant.ru/document/cons_doc_LAW_112701/
+ */
+
+
+const X509V3_EXT_METHOD ossl_v3_utf8_list[1] = {
+ EXT_UTF8STRING(NID_subjectSignTool),
+};
+
+char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
+ ASN1_UTF8STRING *utf8)
+{
+ char *tmp;
+
+ if (utf8 == NULL || utf8->length == 0) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if ((tmp = OPENSSL_malloc(utf8->length + 1)) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memcpy(tmp, utf8->data, utf8->length);
+ tmp[utf8->length] = 0;
+ return tmp;
+}
+
+ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, const char *str)
+{
+ ASN1_UTF8STRING *utf8;
+ if (str == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
+ return NULL;
+ }
+ if ((utf8 = ASN1_UTF8STRING_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (!ASN1_STRING_set((ASN1_STRING *)utf8, str, strlen(str))) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ ASN1_UTF8STRING_free(utf8);
+ return NULL;
+ }
+#ifdef CHARSET_EBCDIC
+ ebcdic2ascii(utf8->data, utf8->data, utf8->length);
+#endif /* CHARSET_EBCDIC */
+ return utf8;
+}
diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c
new file mode 100644
index 000000000000..56ee36d4521e
--- /dev/null
+++ b/crypto/x509/v3_utl.c
@@ -0,0 +1,1386 @@
+/*
+ * Copyright 1999-2024 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
+ */
+
+/* X509 v3 extension utilities */
+
+#include "e_os.h"
+#include "internal/cryptlib.h"
+#include <stdio.h>
+#include <string.h>
+#include "crypto/ctype.h"
+#include <openssl/conf.h>
+#include <openssl/crypto.h>
+#include <openssl/x509v3.h>
+#include "crypto/x509.h"
+#include <openssl/bn.h>
+#include "ext_dat.h"
+#include "x509_local.h"
+
+static char *strip_spaces(char *name);
+static int sk_strcmp(const char *const *a, const char *const *b);
+static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
+ GENERAL_NAMES *gens);
+static void str_free(OPENSSL_STRING str);
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email);
+
+static int ipv4_from_asc(unsigned char *v4, const char *in);
+static int ipv6_from_asc(unsigned char *v6, const char *in);
+static int ipv6_cb(const char *elem, int len, void *usr);
+static int ipv6_hex(unsigned char *out, const char *in, int inlen);
+
+/* Add a CONF_VALUE name value pair to stack */
+
+static int x509v3_add_len_value(const char *name, const char *value,
+ size_t vallen, STACK_OF(CONF_VALUE) **extlist)
+{
+ CONF_VALUE *vtmp = NULL;
+ char *tname = NULL, *tvalue = NULL;
+ int sk_allocated = (*extlist == NULL);
+
+ if (name != NULL && (tname = OPENSSL_strdup(name)) == NULL)
+ goto err;
+ if (value != NULL) {
+ /* We don't allow embeded NUL characters */
+ if (memchr(value, 0, vallen) != NULL)
+ goto err;
+ tvalue = OPENSSL_strndup(value, vallen);
+ if (tvalue == NULL)
+ goto err;
+ }
+ if ((vtmp = OPENSSL_malloc(sizeof(*vtmp))) == NULL)
+ goto err;
+ if (sk_allocated && (*extlist = sk_CONF_VALUE_new_null()) == NULL)
+ goto err;
+ vtmp->section = NULL;
+ vtmp->name = tname;
+ vtmp->value = tvalue;
+ if (!sk_CONF_VALUE_push(*extlist, vtmp))
+ goto err;
+ return 1;
+ err:
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ if (sk_allocated) {
+ sk_CONF_VALUE_free(*extlist);
+ *extlist = NULL;
+ }
+ OPENSSL_free(vtmp);
+ OPENSSL_free(tname);
+ OPENSSL_free(tvalue);
+ return 0;
+}
+
+int X509V3_add_value(const char *name, const char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509v3_add_len_value(name, value,
+ value != NULL ? strlen((const char *)value) : 0,
+ extlist);
+}
+
+int X509V3_add_value_uchar(const char *name, const unsigned char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509v3_add_len_value(name, (const char *)value,
+ value != NULL ? strlen((const char *)value) : 0,
+ extlist);
+}
+
+int x509v3_add_len_value_uchar(const char *name, const unsigned char *value,
+ size_t vallen, STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509v3_add_len_value(name, (const char *)value, vallen, extlist);
+}
+
+/* Free function for STACK_OF(CONF_VALUE) */
+
+void X509V3_conf_free(CONF_VALUE *conf)
+{
+ if (!conf)
+ return;
+ OPENSSL_free(conf->name);
+ OPENSSL_free(conf->value);
+ OPENSSL_free(conf->section);
+ OPENSSL_free(conf);
+}
+
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ if (asn1_bool)
+ return X509V3_add_value(name, "TRUE", extlist);
+ return X509V3_add_value(name, "FALSE", extlist);
+}
+
+int X509V3_add_value_bool_nf(const char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ if (asn1_bool)
+ return X509V3_add_value(name, "TRUE", extlist);
+ return 1;
+}
+
+static char *bignum_to_string(const BIGNUM *bn)
+{
+ char *tmp, *ret;
+ size_t len;
+
+ /*
+ * Display large numbers in hex and small numbers in decimal. Converting to
+ * decimal takes quadratic time and is no more useful than hex for large
+ * numbers.
+ */
+ if (BN_num_bits(bn) < 128)
+ return BN_bn2dec(bn);
+
+ tmp = BN_bn2hex(bn);
+ if (tmp == NULL)
+ return NULL;
+
+ len = strlen(tmp) + 3;
+ ret = OPENSSL_malloc(len);
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(tmp);
+ return NULL;
+ }
+
+ /* Prepend "0x", but place it after the "-" if negative. */
+ if (tmp[0] == '-') {
+ OPENSSL_strlcpy(ret, "-0x", len);
+ OPENSSL_strlcat(ret, tmp + 1, len);
+ } else {
+ OPENSSL_strlcpy(ret, "0x", len);
+ OPENSSL_strlcat(ret, tmp, len);
+ }
+ OPENSSL_free(tmp);
+ return ret;
+}
+
+char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, const ASN1_ENUMERATED *a)
+{
+ BIGNUM *bntmp = NULL;
+ char *strtmp = NULL;
+
+ if (!a)
+ return NULL;
+ if ((bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) == NULL
+ || (strtmp = bignum_to_string(bntmp)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ BN_free(bntmp);
+ return strtmp;
+}
+
+char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, const ASN1_INTEGER *a)
+{
+ BIGNUM *bntmp = NULL;
+ char *strtmp = NULL;
+
+ if (!a)
+ return NULL;
+ if ((bntmp = ASN1_INTEGER_to_BN(a, NULL)) == NULL
+ || (strtmp = bignum_to_string(bntmp)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ BN_free(bntmp);
+ return strtmp;
+}
+
+ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, const char *value)
+{
+ BIGNUM *bn = NULL;
+ ASN1_INTEGER *aint;
+ int isneg, ishex;
+ int ret;
+
+ if (value == NULL) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
+ return NULL;
+ }
+ bn = BN_new();
+ if (bn == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (value[0] == '-') {
+ value++;
+ isneg = 1;
+ } else {
+ isneg = 0;
+ }
+
+ if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
+ value += 2;
+ ishex = 1;
+ } else {
+ ishex = 0;
+ }
+
+ if (ishex)
+ ret = BN_hex2bn(&bn, value);
+ else
+ ret = BN_dec2bn(&bn, value);
+
+ if (!ret || value[ret]) {
+ BN_free(bn);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_BN_DEC2BN_ERROR);
+ return NULL;
+ }
+
+ if (isneg && BN_is_zero(bn))
+ isneg = 0;
+
+ aint = BN_to_ASN1_INTEGER(bn, NULL);
+ BN_free(bn);
+ if (!aint) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
+ return NULL;
+ }
+ if (isneg)
+ aint->type |= V_ASN1_NEG;
+ return aint;
+}
+
+int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ char *strtmp;
+ int ret;
+
+ if (!aint)
+ return 1;
+ if ((strtmp = i2s_ASN1_INTEGER(NULL, aint)) == NULL)
+ return 0;
+ ret = X509V3_add_value(name, strtmp, extlist);
+ OPENSSL_free(strtmp);
+ return ret;
+}
+
+int X509V3_get_value_bool(const CONF_VALUE *value, int *asn1_bool)
+{
+ const char *btmp;
+
+ if ((btmp = value->value) == NULL)
+ goto err;
+ if (strcmp(btmp, "TRUE") == 0
+ || strcmp(btmp, "true") == 0
+ || strcmp(btmp, "Y") == 0
+ || strcmp(btmp, "y") == 0
+ || strcmp(btmp, "YES") == 0
+ || strcmp(btmp, "yes") == 0) {
+ *asn1_bool = 0xff;
+ return 1;
+ }
+ if (strcmp(btmp, "FALSE") == 0
+ || strcmp(btmp, "false") == 0
+ || strcmp(btmp, "N") == 0
+ || strcmp(btmp, "n") == 0
+ || strcmp(btmp, "NO") == 0
+ || strcmp(btmp, "no") == 0) {
+ *asn1_bool = 0;
+ return 1;
+ }
+ err:
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_BOOLEAN_STRING);
+ X509V3_conf_add_error_name_value(value);
+ return 0;
+}
+
+int X509V3_get_value_int(const CONF_VALUE *value, ASN1_INTEGER **aint)
+{
+ ASN1_INTEGER *itmp;
+
+ if ((itmp = s2i_ASN1_INTEGER(NULL, value->value)) == NULL) {
+ X509V3_conf_add_error_name_value(value);
+ return 0;
+ }
+ *aint = itmp;
+ return 1;
+}
+
+#define HDR_NAME 1
+#define HDR_VALUE 2
+
+/*
+ * #define DEBUG
+ */
+
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line)
+{
+ char *p, *q, c;
+ char *ntmp, *vtmp;
+ STACK_OF(CONF_VALUE) *values = NULL;
+ char *linebuf;
+ int state;
+
+ /* We are going to modify the line so copy it first */
+ linebuf = OPENSSL_strdup(line);
+ if (linebuf == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ state = HDR_NAME;
+ ntmp = NULL;
+ /* Go through all characters */
+ for (p = linebuf, q = linebuf; (c = *p) && (c != '\r') && (c != '\n');
+ p++) {
+
+ switch (state) {
+ case HDR_NAME:
+ if (c == ':') {
+ state = HDR_VALUE;
+ *p = 0;
+ ntmp = strip_spaces(q);
+ if (!ntmp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
+ goto err;
+ }
+ q = p + 1;
+ } else if (c == ',') {
+ *p = 0;
+ ntmp = strip_spaces(q);
+ q = p + 1;
+ if (!ntmp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, NULL, &values)) {
+ goto err;
+ }
+ }
+ break;
+
+ case HDR_VALUE:
+ if (c == ',') {
+ state = HDR_NAME;
+ *p = 0;
+ vtmp = strip_spaces(q);
+ if (!vtmp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, vtmp, &values)) {
+ goto err;
+ }
+ ntmp = NULL;
+ q = p + 1;
+ }
+
+ }
+ }
+
+ if (state == HDR_VALUE) {
+ vtmp = strip_spaces(q);
+ if (!vtmp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, vtmp, &values)) {
+ goto err;
+ }
+ } else {
+ ntmp = strip_spaces(q);
+ if (!ntmp) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, NULL, &values)) {
+ goto err;
+ }
+ }
+ OPENSSL_free(linebuf);
+ return values;
+
+ err:
+ OPENSSL_free(linebuf);
+ sk_CONF_VALUE_pop_free(values, X509V3_conf_free);
+ return NULL;
+
+}
+
+/* Delete leading and trailing spaces from a string */
+static char *strip_spaces(char *name)
+{
+ char *p, *q;
+
+ /* Skip over leading spaces */
+ p = name;
+ while (*p && ossl_isspace(*p))
+ p++;
+ if (*p == '\0')
+ return NULL;
+ q = p + strlen(p) - 1;
+ while ((q != p) && ossl_isspace(*q))
+ q--;
+ if (p != q)
+ q[1] = 0;
+ if (*p == '\0')
+ return NULL;
+ return p;
+}
+
+
+/*
+ * V2I name comparison function: returns zero if 'name' matches cmp or cmp.*
+ */
+
+int ossl_v3_name_cmp(const char *name, const char *cmp)
+{
+ int len, ret;
+ char c;
+
+ len = strlen(cmp);
+ if ((ret = strncmp(name, cmp, len)))
+ return ret;
+ c = name[len];
+ if (!c || (c == '.'))
+ return 0;
+ return 1;
+}
+
+static int sk_strcmp(const char *const *a, const char *const *b)
+{
+ return strcmp(*a, *b);
+}
+
+STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x)
+{
+ GENERAL_NAMES *gens;
+ STACK_OF(OPENSSL_STRING) *ret;
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ ret = get_email(X509_get_subject_name(x), gens);
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return ret;
+}
+
+STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x)
+{
+ AUTHORITY_INFO_ACCESS *info;
+ STACK_OF(OPENSSL_STRING) *ret = NULL;
+ int i;
+
+ info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL);
+ if (!info)
+ return NULL;
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
+ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
+ if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) {
+ if (ad->location->type == GEN_URI) {
+ if (!append_ia5
+ (&ret, ad->location->d.uniformResourceIdentifier))
+ break;
+ }
+ }
+ }
+ AUTHORITY_INFO_ACCESS_free(info);
+ return ret;
+}
+
+STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x)
+{
+ GENERAL_NAMES *gens;
+ STACK_OF(X509_EXTENSION) *exts;
+ STACK_OF(OPENSSL_STRING) *ret;
+
+ exts = X509_REQ_get_extensions(x);
+ gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL);
+ ret = get_email(X509_REQ_get_subject_name(x), gens);
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ return ret;
+}
+
+static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
+ GENERAL_NAMES *gens)
+{
+ STACK_OF(OPENSSL_STRING) *ret = NULL;
+ X509_NAME_ENTRY *ne;
+ const ASN1_IA5STRING *email;
+ GENERAL_NAME *gen;
+ int i = -1;
+
+ /* Now add any email address(es) to STACK */
+ /* First supplied X509_NAME */
+ while ((i = X509_NAME_get_index_by_NID(name,
+ NID_pkcs9_emailAddress, i)) >= 0) {
+ ne = X509_NAME_get_entry(name, i);
+ email = X509_NAME_ENTRY_get_data(ne);
+ if (!append_ia5(&ret, email))
+ return NULL;
+ }
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if (gen->type != GEN_EMAIL)
+ continue;
+ if (!append_ia5(&ret, gen->d.ia5))
+ return NULL;
+ }
+ return ret;
+}
+
+static void str_free(OPENSSL_STRING str)
+{
+ OPENSSL_free(str);
+}
+
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email)
+{
+ char *emtmp;
+
+ /* First some sanity checks */
+ if (email->type != V_ASN1_IA5STRING)
+ return 1;
+ if (email->data == NULL || email->length == 0)
+ return 1;
+ if (memchr(email->data, 0, email->length) != NULL)
+ return 1;
+ if (*sk == NULL)
+ *sk = sk_OPENSSL_STRING_new(sk_strcmp);
+ if (*sk == NULL)
+ return 0;
+
+ emtmp = OPENSSL_strndup((char *)email->data, email->length);
+ if (emtmp == NULL) {
+ X509_email_free(*sk);
+ *sk = NULL;
+ return 0;
+ }
+
+ /* Don't add duplicates */
+ if (sk_OPENSSL_STRING_find(*sk, emtmp) != -1) {
+ OPENSSL_free(emtmp);
+ return 1;
+ }
+ if (!sk_OPENSSL_STRING_push(*sk, emtmp)) {
+ OPENSSL_free(emtmp); /* free on push failure */
+ X509_email_free(*sk);
+ *sk = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void X509_email_free(STACK_OF(OPENSSL_STRING) *sk)
+{
+ sk_OPENSSL_STRING_pop_free(sk, str_free);
+}
+
+typedef int (*equal_fn) (const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len,
+ unsigned int flags);
+
+/* Skip pattern prefix to match "wildcard" subject */
+static void skip_prefix(const unsigned char **p, size_t *plen,
+ size_t subject_len,
+ unsigned int flags)
+{
+ const unsigned char *pattern = *p;
+ size_t pattern_len = *plen;
+
+ /*
+ * If subject starts with a leading '.' followed by more octets, and
+ * pattern is longer, compare just an equal-length suffix with the
+ * full subject (starting at the '.'), provided the prefix contains
+ * no NULs.
+ */
+ if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0)
+ return;
+
+ while (pattern_len > subject_len && *pattern) {
+ if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) &&
+ *pattern == '.')
+ break;
+ ++pattern;
+ --pattern_len;
+ }
+
+ /* Skip if entire prefix acceptable */
+ if (pattern_len == subject_len) {
+ *p = pattern;
+ *plen = pattern_len;
+ }
+}
+
+/* Compare while ASCII ignoring case. */
+static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len,
+ unsigned int flags)
+{
+ skip_prefix(&pattern, &pattern_len, subject_len, flags);
+ if (pattern_len != subject_len)
+ return 0;
+ while (pattern_len != 0) {
+ unsigned char l = *pattern;
+ unsigned char r = *subject;
+
+ /* The pattern must not contain NUL characters. */
+ if (l == 0)
+ return 0;
+ if (l != r) {
+ if ('A' <= l && l <= 'Z')
+ l = (l - 'A') + 'a';
+ if ('A' <= r && r <= 'Z')
+ r = (r - 'A') + 'a';
+ if (l != r)
+ return 0;
+ }
+ ++pattern;
+ ++subject;
+ --pattern_len;
+ }
+ return 1;
+}
+
+/* Compare using memcmp. */
+static int equal_case(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len,
+ unsigned int flags)
+{
+ skip_prefix(&pattern, &pattern_len, subject_len, flags);
+ if (pattern_len != subject_len)
+ return 0;
+ return !memcmp(pattern, subject, pattern_len);
+}
+
+/*
+ * RFC 5280, section 7.5, requires that only the domain is compared in a
+ * case-insensitive manner.
+ */
+static int equal_email(const unsigned char *a, size_t a_len,
+ const unsigned char *b, size_t b_len,
+ unsigned int unused_flags)
+{
+ size_t i = a_len;
+
+ if (a_len != b_len)
+ return 0;
+ /*
+ * We search backwards for the '@' character, so that we do not have to
+ * deal with quoted local-parts. The domain part is compared in a
+ * case-insensitive manner.
+ */
+ while (i > 0) {
+ --i;
+ if (a[i] == '@' || b[i] == '@') {
+ if (!equal_nocase(a + i, a_len - i, b + i, a_len - i, 0))
+ return 0;
+ break;
+ }
+ }
+ if (i == 0)
+ i = a_len;
+ return equal_case(a, i, b, i, 0);
+}
+
+/*
+ * Compare the prefix and suffix with the subject, and check that the
+ * characters in-between are valid.
+ */
+static int wildcard_match(const unsigned char *prefix, size_t prefix_len,
+ const unsigned char *suffix, size_t suffix_len,
+ const unsigned char *subject, size_t subject_len,
+ unsigned int flags)
+{
+ const unsigned char *wildcard_start;
+ const unsigned char *wildcard_end;
+ const unsigned char *p;
+ int allow_multi = 0;
+ int allow_idna = 0;
+
+ if (subject_len < prefix_len + suffix_len)
+ return 0;
+ if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags))
+ return 0;
+ wildcard_start = subject + prefix_len;
+ wildcard_end = subject + (subject_len - suffix_len);
+ if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags))
+ return 0;
+ /*
+ * If the wildcard makes up the entire first label, it must match at
+ * least one character.
+ */
+ if (prefix_len == 0 && *suffix == '.') {
+ if (wildcard_start == wildcard_end)
+ return 0;
+ allow_idna = 1;
+ if (flags & X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS)
+ allow_multi = 1;
+ }
+ /* IDNA labels cannot match partial wildcards */
+ if (!allow_idna &&
+ subject_len >= 4 && OPENSSL_strncasecmp((char *)subject, "xn--", 4) == 0)
+ return 0;
+ /* The wildcard may match a literal '*' */
+ if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*')
+ return 1;
+ /*
+ * Check that the part matched by the wildcard contains only
+ * permitted characters and only matches a single label unless
+ * allow_multi is set.
+ */
+ for (p = wildcard_start; p != wildcard_end; ++p)
+ if (!(('0' <= *p && *p <= '9') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('a' <= *p && *p <= 'z') ||
+ *p == '-' || (allow_multi && *p == '.')))
+ return 0;
+ return 1;
+}
+
+#define LABEL_START (1 << 0)
+#define LABEL_END (1 << 1)
+#define LABEL_HYPHEN (1 << 2)
+#define LABEL_IDNA (1 << 3)
+
+static const unsigned char *valid_star(const unsigned char *p, size_t len,
+ unsigned int flags)
+{
+ const unsigned char *star = 0;
+ size_t i;
+ int state = LABEL_START;
+ int dots = 0;
+
+ for (i = 0; i < len; ++i) {
+ /*
+ * Locate first and only legal wildcard, either at the start
+ * or end of a non-IDNA first and not final label.
+ */
+ if (p[i] == '*') {
+ int atstart = (state & LABEL_START);
+ int atend = (i == len - 1 || p[i + 1] == '.');
+ /*-
+ * At most one wildcard per pattern.
+ * No wildcards in IDNA labels.
+ * No wildcards after the first label.
+ */
+ if (star != NULL || (state & LABEL_IDNA) != 0 || dots)
+ return NULL;
+ /* Only full-label '*.example.com' wildcards? */
+ if ((flags & X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS)
+ && (!atstart || !atend))
+ return NULL;
+ /* No 'foo*bar' wildcards */
+ if (!atstart && !atend)
+ return NULL;
+ star = &p[i];
+ state &= ~LABEL_START;
+ } else if (('a' <= p[i] && p[i] <= 'z')
+ || ('A' <= p[i] && p[i] <= 'Z')
+ || ('0' <= p[i] && p[i] <= '9')) {
+ if ((state & LABEL_START) != 0
+ && len - i >= 4 && OPENSSL_strncasecmp((char *)&p[i], "xn--", 4) == 0)
+ state |= LABEL_IDNA;
+ state &= ~(LABEL_HYPHEN | LABEL_START);
+ } else if (p[i] == '.') {
+ if ((state & (LABEL_HYPHEN | LABEL_START)) != 0)
+ return NULL;
+ state = LABEL_START;
+ ++dots;
+ } else if (p[i] == '-') {
+ /* no domain/subdomain starts with '-' */
+ if ((state & LABEL_START) != 0)
+ return NULL;
+ state |= LABEL_HYPHEN;
+ } else {
+ return NULL;
+ }
+ }
+
+ /*
+ * The final label must not end in a hyphen or ".", and
+ * there must be at least two dots after the star.
+ */
+ if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 || dots < 2)
+ return NULL;
+ return star;
+}
+
+/* Compare using wildcards. */
+static int equal_wildcard(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len,
+ unsigned int flags)
+{
+ const unsigned char *star = NULL;
+
+ /*
+ * Subject names starting with '.' can only match a wildcard pattern
+ * via a subject sub-domain pattern suffix match.
+ */
+ if (!(subject_len > 1 && subject[0] == '.'))
+ star = valid_star(pattern, pattern_len, flags);
+ if (star == NULL)
+ return equal_nocase(pattern, pattern_len,
+ subject, subject_len, flags);
+ return wildcard_match(pattern, star - pattern,
+ star + 1, (pattern + pattern_len) - star - 1,
+ subject, subject_len, flags);
+}
+
+/*
+ * Compare an ASN1_STRING to a supplied string. If they match return 1. If
+ * cmp_type > 0 only compare if string matches the type, otherwise convert it
+ * to UTF8.
+ */
+
+static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal,
+ unsigned int flags, const char *b, size_t blen,
+ char **peername)
+{
+ int rv = 0;
+
+ if (!a->data || !a->length)
+ return 0;
+ if (cmp_type > 0) {
+ if (cmp_type != a->type)
+ return 0;
+ if (cmp_type == V_ASN1_IA5STRING)
+ rv = equal(a->data, a->length, (unsigned char *)b, blen, flags);
+ else if (a->length == (int)blen && !memcmp(a->data, b, blen))
+ rv = 1;
+ if (rv > 0 && peername != NULL) {
+ *peername = OPENSSL_strndup((char *)a->data, a->length);
+ if (*peername == NULL)
+ return -1;
+ }
+ } else {
+ int astrlen;
+ unsigned char *astr;
+ astrlen = ASN1_STRING_to_UTF8(&astr, a);
+ if (astrlen < 0) {
+ /*
+ * -1 could be an internal malloc failure or a decoding error from
+ * malformed input; we can't distinguish.
+ */
+ return -1;
+ }
+ rv = equal(astr, astrlen, (unsigned char *)b, blen, flags);
+ if (rv > 0 && peername != NULL) {
+ *peername = OPENSSL_strndup((char *)astr, astrlen);
+ if (*peername == NULL) {
+ OPENSSL_free(astr);
+ return -1;
+ }
+ }
+ OPENSSL_free(astr);
+ }
+ return rv;
+}
+
+static int do_x509_check(X509 *x, const char *chk, size_t chklen,
+ unsigned int flags, int check_type, char **peername)
+{
+ GENERAL_NAMES *gens = NULL;
+ const X509_NAME *name = NULL;
+ int i;
+ int cnid = NID_undef;
+ int alt_type;
+ int san_present = 0;
+ int rv = 0;
+ equal_fn equal;
+
+ /* See below, this flag is internal-only */
+ flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS;
+ if (check_type == GEN_EMAIL) {
+ cnid = NID_pkcs9_emailAddress;
+ alt_type = V_ASN1_IA5STRING;
+ equal = equal_email;
+ } else if (check_type == GEN_DNS) {
+ cnid = NID_commonName;
+ /* Implicit client-side DNS sub-domain pattern */
+ if (chklen > 1 && chk[0] == '.')
+ flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS;
+ alt_type = V_ASN1_IA5STRING;
+ if (flags & X509_CHECK_FLAG_NO_WILDCARDS)
+ equal = equal_nocase;
+ else
+ equal = equal_wildcard;
+ } else {
+ alt_type = V_ASN1_OCTET_STRING;
+ equal = equal_case;
+ }
+
+ if (chklen == 0)
+ chklen = strlen(chk);
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ if (gens) {
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ GENERAL_NAME *gen;
+ ASN1_STRING *cstr;
+
+ gen = sk_GENERAL_NAME_value(gens, i);
+ switch (gen->type) {
+ default:
+ continue;
+ case GEN_OTHERNAME:
+ switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
+ default:
+ continue;
+ case NID_id_on_SmtpUTF8Mailbox:
+ /*-
+ * https://datatracker.ietf.org/doc/html/rfc8398#section-3
+ *
+ * Due to name constraint compatibility reasons described
+ * in Section 6, SmtpUTF8Mailbox subjectAltName MUST NOT
+ * be used unless the local-part of the email address
+ * contains non-ASCII characters. When the local-part is
+ * ASCII, rfc822Name subjectAltName MUST be used instead
+ * of SmtpUTF8Mailbox. This is compatible with legacy
+ * software that supports only rfc822Name (and not
+ * SmtpUTF8Mailbox). [...]
+ *
+ * SmtpUTF8Mailbox is encoded as UTF8String.
+ *
+ * If it is not a UTF8String then that is unexpected, and
+ * we ignore the invalid SAN (neither set san_present nor
+ * consider it a candidate for equality). This does mean
+ * that the subject CN may be considered, as would be the
+ * case when the malformed SmtpUtf8Mailbox SAN is instead
+ * simply absent.
+ *
+ * When CN-ID matching is not desirable, applications can
+ * choose to turn it off, doing so is at this time a best
+ * practice.
+ */
+ if (check_type != GEN_EMAIL
+ || gen->d.otherName->value->type != V_ASN1_UTF8STRING)
+ continue;
+ alt_type = 0;
+ cstr = gen->d.otherName->value->value.utf8string;
+ break;
+ }
+ break;
+ case GEN_EMAIL:
+ if (check_type != GEN_EMAIL)
+ continue;
+ cstr = gen->d.rfc822Name;
+ break;
+ case GEN_DNS:
+ if (check_type != GEN_DNS)
+ continue;
+ cstr = gen->d.dNSName;
+ break;
+ case GEN_IPADD:
+ if (check_type != GEN_IPADD)
+ continue;
+ cstr = gen->d.iPAddress;
+ break;
+ }
+ san_present = 1;
+ /* Positive on success, negative on error! */
+ if ((rv = do_check_string(cstr, alt_type, equal, flags,
+ chk, chklen, peername)) != 0)
+ break;
+ }
+ GENERAL_NAMES_free(gens);
+ if (rv != 0)
+ return rv;
+ if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT))
+ return 0;
+ }
+
+ /* We're done if CN-ID is not pertinent */
+ if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT))
+ return 0;
+
+ i = -1;
+ name = X509_get_subject_name(x);
+ while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) {
+ const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i);
+ const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne);
+
+ /* Positive on success, negative on error! */
+ if ((rv = do_check_string(str, -1, equal, flags,
+ chk, chklen, peername)) != 0)
+ return rv;
+ }
+ return 0;
+}
+
+int X509_check_host(X509 *x, const char *chk, size_t chklen,
+ unsigned int flags, char **peername)
+{
+ if (chk == NULL)
+ return -2;
+ /*
+ * Embedded NULs are disallowed, except as the last character of a
+ * string of length 2 or more (tolerate caller including terminating
+ * NUL in string length).
+ */
+ if (chklen == 0)
+ chklen = strlen(chk);
+ else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen))
+ return -2;
+ if (chklen > 1 && chk[chklen - 1] == '\0')
+ --chklen;
+ return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername);
+}
+
+int X509_check_email(X509 *x, const char *chk, size_t chklen,
+ unsigned int flags)
+{
+ if (chk == NULL)
+ return -2;
+ /*
+ * Embedded NULs are disallowed, except as the last character of a
+ * string of length 2 or more (tolerate caller including terminating
+ * NUL in string length).
+ */
+ if (chklen == 0)
+ chklen = strlen((char *)chk);
+ else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen))
+ return -2;
+ if (chklen > 1 && chk[chklen - 1] == '\0')
+ --chklen;
+ return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL);
+}
+
+int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+{
+ if (chk == NULL)
+ return -2;
+ return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL);
+}
+
+int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
+{
+ unsigned char ipout[16];
+ size_t iplen;
+
+ if (ipasc == NULL)
+ return -2;
+ iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
+ if (iplen == 0)
+ return -2;
+ return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL);
+}
+
+char *ossl_ipaddr_to_asc(unsigned char *p, int len)
+{
+ /*
+ * 40 is enough space for the longest IPv6 address + nul terminator byte
+ * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX\0
+ */
+ char buf[40], *out;
+ int i = 0, remain = 0, bytes = 0;
+
+ switch (len) {
+ case 4: /* IPv4 */
+ BIO_snprintf(buf, sizeof(buf), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ break;
+ case 16: /* IPv6 */
+ for (out = buf, i = 8, remain = sizeof(buf);
+ i-- > 0 && bytes >= 0;
+ remain -= bytes, out += bytes) {
+ const char *template = (i > 0 ? "%X:" : "%X");
+
+ bytes = BIO_snprintf(out, remain, template, p[0] << 8 | p[1]);
+ p += 2;
+ }
+ break;
+ default:
+ BIO_snprintf(buf, sizeof(buf), "<invalid length=%d>", len);
+ break;
+ }
+ return OPENSSL_strdup(buf);
+}
+
+/*
+ * Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible
+ * with RFC3280.
+ */
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
+{
+ unsigned char ipout[16];
+ ASN1_OCTET_STRING *ret;
+ int iplen;
+
+ /* If string contains a ':' assume IPv6 */
+
+ iplen = ossl_a2i_ipadd(ipout, ipasc);
+
+ if (!iplen)
+ return NULL;
+
+ ret = ASN1_OCTET_STRING_new();
+ if (ret == NULL)
+ return NULL;
+ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen)) {
+ ASN1_OCTET_STRING_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc)
+{
+ ASN1_OCTET_STRING *ret = NULL;
+ unsigned char ipout[32];
+ char *iptmp = NULL, *p;
+ int iplen1, iplen2;
+
+ p = strchr(ipasc, '/');
+ if (p == NULL)
+ return NULL;
+ iptmp = OPENSSL_strdup(ipasc);
+ if (iptmp == NULL)
+ return NULL;
+ p = iptmp + (p - ipasc);
+ *p++ = 0;
+
+ iplen1 = ossl_a2i_ipadd(ipout, iptmp);
+
+ if (!iplen1)
+ goto err;
+
+ iplen2 = ossl_a2i_ipadd(ipout + iplen1, p);
+
+ OPENSSL_free(iptmp);
+ iptmp = NULL;
+
+ if (!iplen2 || (iplen1 != iplen2))
+ goto err;
+
+ ret = ASN1_OCTET_STRING_new();
+ if (ret == NULL)
+ goto err;
+ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2))
+ goto err;
+
+ return ret;
+
+ err:
+ OPENSSL_free(iptmp);
+ ASN1_OCTET_STRING_free(ret);
+ return NULL;
+}
+
+int ossl_a2i_ipadd(unsigned char *ipout, const char *ipasc)
+{
+ /* If string contains a ':' assume IPv6 */
+
+ if (strchr(ipasc, ':')) {
+ if (!ipv6_from_asc(ipout, ipasc))
+ return 0;
+ return 16;
+ } else {
+ if (!ipv4_from_asc(ipout, ipasc))
+ return 0;
+ return 4;
+ }
+}
+
+static int ipv4_from_asc(unsigned char *v4, const char *in)
+{
+ const char *p;
+ int a0, a1, a2, a3, n;
+
+ if (sscanf(in, "%d.%d.%d.%d%n", &a0, &a1, &a2, &a3, &n) != 4)
+ return 0;
+ if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
+ || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
+ return 0;
+ p = in + n;
+ if (!(*p == '\0' || ossl_isspace(*p)))
+ return 0;
+ v4[0] = a0;
+ v4[1] = a1;
+ v4[2] = a2;
+ v4[3] = a3;
+ return 1;
+}
+
+typedef struct {
+ /* Temporary store for IPV6 output */
+ unsigned char tmp[16];
+ /* Total number of bytes in tmp */
+ int total;
+ /* The position of a zero (corresponding to '::') */
+ int zero_pos;
+ /* Number of zeroes */
+ int zero_cnt;
+} IPV6_STAT;
+
+static int ipv6_from_asc(unsigned char *v6, const char *in)
+{
+ IPV6_STAT v6stat;
+
+ v6stat.total = 0;
+ v6stat.zero_pos = -1;
+ v6stat.zero_cnt = 0;
+ /*
+ * Treat the IPv6 representation as a list of values separated by ':'.
+ * The presence of a '::' will parse as one, two or three zero length
+ * elements.
+ */
+ if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat))
+ return 0;
+
+ /* Now for some sanity checks */
+
+ if (v6stat.zero_pos == -1) {
+ /* If no '::' must have exactly 16 bytes */
+ if (v6stat.total != 16)
+ return 0;
+ } else {
+ /* If '::' must have less than 16 bytes */
+ if (v6stat.total == 16)
+ return 0;
+ /* More than three zeroes is an error */
+ if (v6stat.zero_cnt > 3) {
+ return 0;
+ /* Can only have three zeroes if nothing else present */
+ } else if (v6stat.zero_cnt == 3) {
+ if (v6stat.total > 0)
+ return 0;
+ } else if (v6stat.zero_cnt == 2) {
+ /* Can only have two zeroes if at start or end */
+ if ((v6stat.zero_pos != 0)
+ && (v6stat.zero_pos != v6stat.total))
+ return 0;
+ } else {
+ /* Can only have one zero if *not* start or end */
+ if ((v6stat.zero_pos == 0)
+ || (v6stat.zero_pos == v6stat.total))
+ return 0;
+ }
+ }
+
+ /* Format result */
+
+ if (v6stat.zero_pos >= 0) {
+ /* Copy initial part */
+ memcpy(v6, v6stat.tmp, v6stat.zero_pos);
+ /* Zero middle */
+ memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total);
+ /* Copy final part */
+ if (v6stat.total != v6stat.zero_pos)
+ memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
+ v6stat.tmp + v6stat.zero_pos,
+ v6stat.total - v6stat.zero_pos);
+ } else {
+ memcpy(v6, v6stat.tmp, 16);
+ }
+
+ return 1;
+}
+
+static int ipv6_cb(const char *elem, int len, void *usr)
+{
+ IPV6_STAT *s = usr;
+
+ /* Error if 16 bytes written */
+ if (s->total == 16)
+ return 0;
+ if (len == 0) {
+ /* Zero length element, corresponds to '::' */
+ if (s->zero_pos == -1)
+ s->zero_pos = s->total;
+ /* If we've already got a :: its an error */
+ else if (s->zero_pos != s->total)
+ return 0;
+ s->zero_cnt++;
+ } else {
+ /* If more than 4 characters could be final a.b.c.d form */
+ if (len > 4) {
+ /* Need at least 4 bytes left */
+ if (s->total > 12)
+ return 0;
+ /* Must be end of string */
+ if (elem[len])
+ return 0;
+ if (!ipv4_from_asc(s->tmp + s->total, elem))
+ return 0;
+ s->total += 4;
+ } else {
+ if (!ipv6_hex(s->tmp + s->total, elem, len))
+ return 0;
+ s->total += 2;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Convert a string of up to 4 hex digits into the corresponding IPv6 form.
+ */
+
+static int ipv6_hex(unsigned char *out, const char *in, int inlen)
+{
+ unsigned char c;
+ unsigned int num = 0;
+ int x;
+
+ if (inlen > 4)
+ return 0;
+ while (inlen--) {
+ c = *in++;
+ num <<= 4;
+ x = OPENSSL_hexchar2int(c);
+ if (x < 0)
+ return 0;
+ num |= (char)x;
+ }
+ out[0] = num >> 8;
+ out[1] = num & 0xff;
+ return 1;
+}
+
+int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk,
+ unsigned long chtype)
+{
+ CONF_VALUE *v;
+ int i, mval, spec_char, plus_char;
+ char *p, *type;
+
+ if (!nm)
+ return 0;
+
+ for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
+ v = sk_CONF_VALUE_value(dn_sk, i);
+ type = v->name;
+ /*
+ * Skip past any leading X. X: X, etc to allow for multiple instances
+ */
+ for (p = type; *p; p++) {
+#ifndef CHARSET_EBCDIC
+ spec_char = ((*p == ':') || (*p == ',') || (*p == '.'));
+#else
+ spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[','])
+ || (*p == os_toascii['.']));
+#endif
+ if (spec_char) {
+ p++;
+ if (*p)
+ type = p;
+ break;
+ }
+ }
+#ifndef CHARSET_EBCDIC
+ plus_char = (*type == '+');
+#else
+ plus_char = (*type == os_toascii['+']);
+#endif
+ if (plus_char) {
+ mval = -1;
+ type++;
+ } else {
+ mval = 0;
+ }
+ if (!X509_NAME_add_entry_by_txt(nm, type, chtype,
+ (unsigned char *)v->value, -1, -1,
+ mval))
+ return 0;
+
+ }
+ return 1;
+}
diff --git a/crypto/x509/v3err.c b/crypto/x509/v3err.c
new file mode 100644
index 000000000000..6f38034c1afe
--- /dev/null
+++ b/crypto/x509/v3err.c
@@ -0,0 +1,147 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2021 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 <openssl/err.h>
+#include <openssl/x509v3err.h>
+#include "crypto/x509v3err.h"
+
+#ifndef OPENSSL_NO_ERR
+
+static const ERR_STRING_DATA X509V3_str_reasons[] = {
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_IP_ADDRESS), "bad ip address"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_OBJECT), "bad object"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_DEC2BN_ERROR), "bn dec2bn error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_TO_ASN1_INTEGER_ERROR),
+ "bn to asn1 integer error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DIRNAME_ERROR), "dirname error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DISTPOINT_ALREADY_SET),
+ "distpoint already set"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DUPLICATE_ZONE_ID),
+ "duplicate zone id"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EMPTY_KEY_USAGE), "empty key usage"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CONVERTING_ZONE),
+ "error converting zone"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CREATING_EXTENSION),
+ "error creating extension"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_IN_EXTENSION),
+ "error in extension"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXPECTED_A_SECTION_NAME),
+ "expected a section name"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_EXISTS),
+ "extension exists"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NAME_ERROR),
+ "extension name error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NOT_FOUND),
+ "extension not found"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED),
+ "extension setting not supported"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_VALUE_ERROR),
+ "extension value error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ILLEGAL_EMPTY_EXTENSION),
+ "illegal empty extension"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG),
+ "incorrect policy syntax tag"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASNUMBER),
+ "invalid asnumber"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASRANGE), "invalid asrange"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_BOOLEAN_STRING),
+ "invalid boolean string"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_CERTIFICATE),
+ "invalid certificate"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EMPTY_NAME),
+ "invalid empty name"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EXTENSION_STRING),
+ "invalid extension string"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_INHERITANCE),
+ "invalid inheritance"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_IPADDRESS),
+ "invalid ipaddress"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_MULTIPLE_RDNS),
+ "invalid multiple rdns"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NAME), "invalid name"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_ARGUMENT),
+ "invalid null argument"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_VALUE),
+ "invalid null value"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBER), "invalid number"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBERS), "invalid numbers"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OBJECT_IDENTIFIER),
+ "invalid object identifier"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OPTION), "invalid option"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_POLICY_IDENTIFIER),
+ "invalid policy identifier"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PROXY_POLICY_SETTING),
+ "invalid proxy policy setting"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PURPOSE), "invalid purpose"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SAFI), "invalid safi"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SECTION), "invalid section"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SYNTAX), "invalid syntax"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ISSUER_DECODE_ERROR),
+ "issuer decode error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "missing value"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS),
+ "need organization and numbers"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEGATIVE_PATHLEN),
+ "negative pathlen"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_CONFIG_DATABASE),
+ "no config database"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_CERTIFICATE),
+ "no issuer certificate"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_DETAILS),
+ "no issuer details"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_POLICY_IDENTIFIER),
+ "no policy identifier"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED),
+ "no proxy cert policy language defined"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PUBLIC_KEY), "no public key"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_SUBJECT_DETAILS),
+ "no subject details"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OPERATION_NOT_DEFINED),
+ "operation not defined"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OTHERNAME_ERROR), "othername error"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED),
+ "policy language already defined"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH),
+ "policy path length"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED),
+ "policy path length already defined"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY),
+ "policy when proxy language requires no policy"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_SECTION_NOT_FOUND),
+ "section not found"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS),
+ "unable to get issuer details"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID),
+ "unable to get issuer keyid"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT),
+ "unknown bit string argument"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION),
+ "unknown extension"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION_NAME),
+ "unknown extension name"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_OPTION), "unknown option"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_OPTION),
+ "unsupported option"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_TYPE),
+ "unsupported type"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_USER_TOO_LONG), "user too long"},
+ {0, NULL}
+};
+
+#endif
+
+int ossl_err_load_X509V3_strings(void)
+{
+#ifndef OPENSSL_NO_ERR
+ if (ERR_reason_error_string(X509V3_str_reasons[0].error) == NULL)
+ ERR_load_strings_const(X509V3_str_reasons);
+#endif
+ return 1;
+}
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
index cc9f9d19099d..6a541d7980a3 100644
--- a/crypto/x509/x509_att.c
+++ b/crypto/x509/x509_att.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -15,6 +15,7 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "crypto/x509.h"
#include "x509_local.h"
int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
@@ -70,22 +71,23 @@ X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc)
return ret;
}
-STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
- X509_ATTRIBUTE *attr)
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr)
{
X509_ATTRIBUTE *new_attr = NULL;
STACK_OF(X509_ATTRIBUTE) *sk = NULL;
if (x == NULL) {
- X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_PASSED_NULL_PARAMETER);
- goto err2;
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
}
if (*x == NULL) {
if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL)
goto err;
- } else
+ } else {
sk = *x;
+ }
if ((new_attr = X509_ATTRIBUTE_dup(attr)) == NULL)
goto err2;
@@ -95,25 +97,76 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
*x = sk;
return sk;
err:
- X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
err2:
X509_ATTRIBUTE_free(new_attr);
- sk_X509_ATTRIBUTE_free(sk);
+ if (*x == NULL)
+ sk_X509_ATTRIBUTE_free(sk);
return NULL;
}
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr)
+{
+ if (x == NULL || attr == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if (*x != NULL && X509at_get_attr_by_OBJ(*x, attr->object, -1) != -1) {
+ ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE);
+ return NULL;
+ }
+
+ return ossl_x509at_add1_attr(x, attr);
+}
+
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x,
+ const ASN1_OBJECT *obj,
+ int type,
+ const unsigned char *bytes,
+ int len)
+{
+ X509_ATTRIBUTE *attr;
+ STACK_OF(X509_ATTRIBUTE) *ret;
+
+ attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len);
+ if (attr == NULL)
+ return 0;
+ ret = ossl_x509at_add1_attr(x, attr);
+ X509_ATTRIBUTE_free(attr);
+ return ret;
+}
+
STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE)
**x, const ASN1_OBJECT *obj,
int type,
const unsigned char *bytes,
int len)
{
+ if (x == NULL || obj == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if (*x != NULL && X509at_get_attr_by_OBJ(*x, obj, -1) != -1) {
+ ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE);
+ return NULL;
+ }
+
+ return ossl_x509at_add1_attr_by_OBJ(x, obj, type, bytes, len);
+}
+
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x,
+ int nid, int type,
+ const unsigned char *bytes,
+ int len)
+{
X509_ATTRIBUTE *attr;
STACK_OF(X509_ATTRIBUTE) *ret;
- attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len);
- if (!attr)
+
+ attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len);
+ if (attr == NULL)
return 0;
- ret = X509at_add1_attr(x, attr);
+ ret = ossl_x509at_add1_attr(x, attr);
X509_ATTRIBUTE_free(attr);
return ret;
}
@@ -123,12 +176,31 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE)
const unsigned char *bytes,
int len)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if (*x != NULL && X509at_get_attr_by_NID(*x, nid, -1) != -1) {
+ ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE);
+ return NULL;
+ }
+
+ return ossl_x509at_add1_attr_by_NID(x, nid, type, bytes, len);
+}
+
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x,
+ const char *attrname,
+ int type,
+ const unsigned char *bytes,
+ int len)
+{
X509_ATTRIBUTE *attr;
STACK_OF(X509_ATTRIBUTE) *ret;
- attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len);
- if (!attr)
+
+ attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len);
+ if (attr == NULL)
return 0;
- ret = X509at_add1_attr(x, attr);
+ ret = ossl_x509at_add1_attr(x, attr);
X509_ATTRIBUTE_free(attr);
return ret;
}
@@ -165,6 +237,23 @@ void *X509at_get0_data_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *x,
return X509_ATTRIBUTE_get0_data(at, 0, type, NULL);
}
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_dup(const STACK_OF(X509_ATTRIBUTE) *x)
+{
+ int i, n;
+ STACK_OF(X509_ATTRIBUTE) *sk = NULL;
+
+ n = sk_X509_ATTRIBUTE_num(x);
+ for (i = 0; i < n; ++i) {
+ X509_ATTRIBUTE *attr = sk_X509_ATTRIBUTE_value(x, i);
+
+ if (X509at_add1_attr(&sk, attr) == NULL) {
+ sk_X509_ATTRIBUTE_pop_free(sk, X509_ATTRIBUTE_free);
+ return NULL;
+ }
+ }
+ return sk;
+}
+
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
int atrtype, const void *data,
int len)
@@ -174,7 +263,7 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
obj = OBJ_nid2obj(nid);
if (obj == NULL) {
- X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_NID, X509_R_UNKNOWN_NID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_NID);
return NULL;
}
ret = X509_ATTRIBUTE_create_by_OBJ(attr, obj, atrtype, data, len);
@@ -192,8 +281,7 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
if ((attr == NULL) || (*attr == NULL)) {
if ((ret = X509_ATTRIBUTE_new()) == NULL) {
- X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ,
- ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
} else
@@ -223,9 +311,8 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
obj = OBJ_txt2obj(atrname, 0);
if (obj == NULL) {
- X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_TXT,
- X509_R_INVALID_FIELD_NAME);
- ERR_add_error_data(2, "name=", atrname);
+ ERR_raise_data(ERR_LIB_X509, X509_R_INVALID_FIELD_NAME,
+ "name=%s", atrname);
return NULL;
}
nattr = X509_ATTRIBUTE_create_by_OBJ(attr, obj, type, bytes, len);
@@ -254,7 +341,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype,
OBJ_obj2nid(attr->object));
if (!stmp) {
- X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_ASN1_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
return 0;
}
atype = stmp->type;
@@ -287,7 +374,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
goto err;
return 1;
err:
- X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
ASN1_TYPE_free(ttmp);
ASN1_STRING_free(stmp);
return 0;
@@ -317,7 +404,7 @@ void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
if (atrtype == V_ASN1_BOOLEAN
|| atrtype == V_ASN1_NULL
|| atrtype != ASN1_TYPE_get(ttmp)) {
- X509err(X509_F_X509_ATTRIBUTE_GET0_DATA, X509_R_WRONG_TYPE);
+ ERR_raise(ERR_LIB_X509, X509_R_WRONG_TYPE);
return NULL;
}
return ttmp->value.ptr;
diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
index 3724a118f343..f2c3a568198d 100644
--- a/crypto/x509/x509_cmp.c
+++ b/crypto/x509/x509_cmp.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -13,6 +13,7 @@
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <openssl/core_names.h>
#include "crypto/x509.h"
int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
@@ -20,11 +21,15 @@ int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
int i;
const X509_CINF *ai, *bi;
+ if (b == NULL)
+ return a != NULL;
+ if (a == NULL)
+ return -1;
ai = &a->cert_info;
bi = &b->cert_info;
i = ASN1_INTEGER_cmp(&ai->serialNumber, &bi->serialNumber);
- if (i)
- return i;
+ if (i != 0)
+ return i < 0 ? -1 : 1;
return X509_NAME_cmp(ai->issuer, bi->issuer);
}
@@ -35,13 +40,18 @@ unsigned long X509_issuer_and_serial_hash(X509 *a)
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
unsigned char md[16];
char *f = NULL;
+ EVP_MD *digest = NULL;
if (ctx == NULL)
goto err;
f = X509_NAME_oneline(a->cert_info.issuer, NULL, 0);
if (f == NULL)
goto err;
- if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL))
+ digest = EVP_MD_fetch(a->libctx, SN_md5, a->propq);
+ if (digest == NULL)
+ goto err;
+
+ if (!EVP_DigestInit_ex(ctx, digest, NULL))
goto err;
if (!EVP_DigestUpdate(ctx, (unsigned char *)f, strlen(f)))
goto err;
@@ -56,6 +66,7 @@ unsigned long X509_issuer_and_serial_hash(X509 *a)
) & 0xffffffffL;
err:
OPENSSL_free(f);
+ EVP_MD_free(digest);
EVP_MD_CTX_free(ctx);
return ret;
}
@@ -78,7 +89,15 @@ int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b)
int X509_CRL_match(const X509_CRL *a, const X509_CRL *b)
{
- return memcmp(a->sha1_hash, b->sha1_hash, 20);
+ int rv;
+
+ if ((a->flags & EXFLAG_NO_FINGERPRINT) == 0
+ && (b->flags & EXFLAG_NO_FINGERPRINT) == 0)
+ rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+ else
+ return -2;
+
+ return rv < 0 ? -1 : rv > 0;
}
X509_NAME *X509_get_issuer_name(const X509 *a)
@@ -88,7 +107,7 @@ X509_NAME *X509_get_issuer_name(const X509 *a)
unsigned long X509_issuer_name_hash(X509 *x)
{
- return X509_NAME_hash(x->cert_info.issuer);
+ return X509_NAME_hash_ex(x->cert_info.issuer, NULL, NULL, NULL);
}
#ifndef OPENSSL_NO_MD5
@@ -115,7 +134,7 @@ const ASN1_INTEGER *X509_get0_serialNumber(const X509 *a)
unsigned long X509_subject_name_hash(X509 *x)
{
- return X509_NAME_hash(x->cert_info.subject);
+ return X509_NAME_hash_ex(x->cert_info.subject, NULL, NULL, NULL);
}
#ifndef OPENSSL_NO_MD5
@@ -140,7 +159,7 @@ int X509_cmp(const X509 *a, const X509 *b)
if (a == b) /* for efficiency */
return 0;
- /* try to make sure hash is valid */
+ /* attempt to compute cert hash */
(void)X509_check_purpose((X509 *)a, -1, 0);
(void)X509_check_purpose((X509 *)b, -1, 0);
@@ -148,7 +167,7 @@ int X509_cmp(const X509 *a, const X509 *b)
&& (b->ex_flags & EXFLAG_NO_FINGERPRINT) == 0)
rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
if (rv != 0)
- return rv;
+ return rv < 0 ? -1 : 1;
/* Check for match against stored encoding too */
if (!a->cert_info.enc.modified && !b->cert_info.enc.modified) {
@@ -156,53 +175,140 @@ int X509_cmp(const X509 *a, const X509 *b)
return -1;
if (a->cert_info.enc.len > b->cert_info.enc.len)
return 1;
- return memcmp(a->cert_info.enc.enc, b->cert_info.enc.enc,
- a->cert_info.enc.len);
+ rv = memcmp(a->cert_info.enc.enc,
+ b->cert_info.enc.enc, a->cert_info.enc.len);
}
- return rv;
+ return rv < 0 ? -1 : rv > 0;
+}
+
+int ossl_x509_add_cert_new(STACK_OF(X509) **p_sk, X509 *cert, int flags)
+{
+ if (*p_sk == NULL && (*p_sk = sk_X509_new_null()) == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return X509_add_cert(*p_sk, cert, flags);
+}
+
+int X509_add_cert(STACK_OF(X509) *sk, X509 *cert, int flags)
+{
+ if (sk == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (cert == NULL)
+ return 0;
+ if ((flags & X509_ADD_FLAG_NO_DUP) != 0) {
+ /*
+ * not using sk_X509_set_cmp_func() and sk_X509_find()
+ * because this re-orders the certs on the stack
+ */
+ int i;
+
+ for (i = 0; i < sk_X509_num(sk); i++) {
+ if (X509_cmp(sk_X509_value(sk, i), cert) == 0)
+ return 1;
+ }
+ }
+ if ((flags & X509_ADD_FLAG_NO_SS) != 0) {
+ int ret = X509_self_signed(cert, 0);
+
+ if (ret != 0)
+ return ret > 0 ? 1 : 0;
+ }
+ if (!sk_X509_insert(sk, cert,
+ (flags & X509_ADD_FLAG_PREPEND) != 0 ? 0 : -1)) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if ((flags & X509_ADD_FLAG_UP_REF) != 0)
+ (void)X509_up_ref(cert);
+ return 1;
+}
+
+int X509_add_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs, int flags)
+/* compiler would allow 'const' for the certs, yet they may get up-ref'ed */
+{
+ if (sk == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ return ossl_x509_add_certs_new(&sk, certs, flags);
+}
+
+int ossl_x509_add_certs_new(STACK_OF(X509) **p_sk, STACK_OF(X509) *certs,
+ int flags)
+/* compiler would allow 'const' for the certs, yet they may get up-ref'ed */
+{
+ int n = sk_X509_num(certs /* may be NULL */);
+ int i;
+
+ for (i = 0; i < n; i++) {
+ int j = (flags & X509_ADD_FLAG_PREPEND) == 0 ? i : n - 1 - i;
+ /* if prepend, add certs in reverse order to keep original order */
+
+ if (!ossl_x509_add_cert_new(p_sk, sk_X509_value(certs, j), flags))
+ return 0;
+ }
+ return 1;
}
int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
{
int ret;
- /* Ensure canonical encoding is present and up to date */
+ if (b == NULL)
+ return a != NULL;
+ if (a == NULL)
+ return -1;
- if (!a->canon_enc || a->modified) {
+ /* Ensure canonical encoding is present and up to date */
+ if (a->canon_enc == NULL || a->modified) {
ret = i2d_X509_NAME((X509_NAME *)a, NULL);
if (ret < 0)
return -2;
}
- if (!b->canon_enc || b->modified) {
+ if (b->canon_enc == NULL || b->modified) {
ret = i2d_X509_NAME((X509_NAME *)b, NULL);
if (ret < 0)
return -2;
}
ret = a->canon_enclen - b->canon_enclen;
+ if (ret == 0 && a->canon_enclen == 0)
+ return 0;
- if (ret != 0 || a->canon_enclen == 0)
- return ret;
-
- return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen);
+ if (ret == 0) {
+ if (a->canon_enc == NULL || b->canon_enc == NULL)
+ return -2;
+ ret = memcmp(a->canon_enc, b->canon_enc, a->canon_enclen);
+ }
+ return ret < 0 ? -1 : ret > 0;
}
-unsigned long X509_NAME_hash(X509_NAME *x)
+unsigned long X509_NAME_hash_ex(const X509_NAME *x, OSSL_LIB_CTX *libctx,
+ const char *propq, int *ok)
{
unsigned long ret = 0;
unsigned char md[SHA_DIGEST_LENGTH];
+ EVP_MD *sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
+ int i2d_ret;
/* Make sure X509_NAME structure contains valid cached encoding */
- i2d_X509_NAME(x, NULL);
- if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(),
- NULL))
- return 0;
-
- ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
- ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
- ) & 0xffffffffL;
+ i2d_ret = i2d_X509_NAME(x, NULL);
+ if (ok != NULL)
+ *ok = 0;
+ if (i2d_ret >= 0 && sha1 != NULL
+ && EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, sha1, NULL)) {
+ ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
+ ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
+ ) & 0xffffffffL;
+ if (ok != NULL)
+ *ok = 1;
+ }
+ EVP_MD_free(sha1);
return ret;
}
@@ -211,34 +317,38 @@ unsigned long X509_NAME_hash(X509_NAME *x)
* I now DER encode the name and hash it. Since I cache the DER encoding,
* this is reasonably efficient.
*/
-
-unsigned long X509_NAME_hash_old(X509_NAME *x)
+unsigned long X509_NAME_hash_old(const X509_NAME *x)
{
+ EVP_MD *md5 = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_MD5, "-fips");
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
unsigned long ret = 0;
unsigned char md[16];
- if (md_ctx == NULL)
- return ret;
+ if (md5 == NULL || md_ctx == NULL)
+ goto end;
/* Make sure X509_NAME structure contains valid cached encoding */
- i2d_X509_NAME(x, NULL);
- EVP_MD_CTX_set_flags(md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- if (EVP_DigestInit_ex(md_ctx, EVP_md5(), NULL)
+ if (i2d_X509_NAME(x, NULL) < 0)
+ goto end;
+
+ if (EVP_DigestInit_ex(md_ctx, md5, NULL)
&& EVP_DigestUpdate(md_ctx, x->bytes->data, x->bytes->length)
&& EVP_DigestFinal_ex(md_ctx, md, NULL))
ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
) & 0xffffffffL;
+
+ end:
EVP_MD_CTX_free(md_ctx);
+ EVP_MD_free(md5);
return ret;
}
#endif
/* Search a stack of X509 for a match */
-X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name,
- ASN1_INTEGER *serial)
+X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, const X509_NAME *name,
+ const ASN1_INTEGER *serial)
{
int i;
X509 x, *x509 = NULL;
@@ -247,7 +357,7 @@ X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name,
return NULL;
x.cert_info.serialNumber = *serial;
- x.cert_info.issuer = name;
+ x.cert_info.issuer = (X509_NAME *)name; /* won't modify it */
for (i = 0; i < sk_X509_num(sk); i++) {
x509 = sk_X509_value(sk, i);
@@ -257,7 +367,7 @@ X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name,
return NULL;
}
-X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name)
+X509 *X509_find_by_subject(STACK_OF(X509) *sk, const X509_NAME *name)
{
X509 *x509;
int i;
@@ -290,27 +400,24 @@ int X509_check_private_key(const X509 *x, const EVP_PKEY *k)
int ret;
xk = X509_get0_pubkey(x);
+ if (xk == NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+ return 0;
+ }
- if (xk)
- ret = EVP_PKEY_cmp(xk, k);
- else
- ret = -2;
-
- switch (ret) {
- case 1:
- break;
+ switch (ret = EVP_PKEY_eq(xk, k)) {
case 0:
- X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_KEY_VALUES_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH);
break;
case -1:
- X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_KEY_TYPE_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH);
break;
case -2:
- X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_UNKNOWN_KEY_TYPE);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE);
+ break;
}
- if (ret > 0)
- return 1;
- return 0;
+
+ return ret > 0;
}
/*
@@ -323,13 +430,18 @@ int X509_check_private_key(const X509 *x, const EVP_PKEY *k)
static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
{
- const EC_GROUP *grp = NULL;
+ char curve_name[80];
+ size_t curve_name_len;
int curve_nid;
- if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_EC)
- grp = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey));
- if (!grp)
+
+ if (pkey == NULL || !EVP_PKEY_is_a(pkey, "EC"))
return X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
- curve_nid = EC_GROUP_get_curve_name(grp);
+
+ if (!EVP_PKEY_get_group_name(pkey, curve_name, sizeof(curve_name),
+ &curve_name_len))
+ return X509_V_ERR_SUITE_B_INVALID_CURVE;
+
+ curve_nid = OBJ_txt2nid(curve_name);
/* Check curve is consistent with LOS */
if (curve_nid == NID_secp384r1) { /* P-384 */
/*
@@ -346,9 +458,9 @@ static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY))
return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
- } else
+ } else {
return X509_V_ERR_SUITE_B_INVALID_CURVE;
-
+ }
return X509_V_OK;
}
@@ -366,9 +478,9 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
if (x == NULL) {
x = sk_X509_value(chain, 0);
i = 1;
- } else
+ } else {
i = 0;
-
+ }
pk = X509_get0_pubkey(x);
/*
@@ -380,7 +492,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
if (chain == NULL)
return check_suite_b(pk, -1, &tflags);
- if (X509_get_version(x) != 2) {
+ if (X509_get_version(x) != X509_VERSION_3) {
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
/* Correct error depth */
i = 0;
@@ -397,7 +509,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
for (; i < sk_X509_num(chain); i++) {
sign_nid = X509_get_signature_nid(x);
x = sk_X509_value(chain, i);
- if (X509_get_version(x) != 2) {
+ if (X509_get_version(x) != X509_VERSION_3) {
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
goto end;
}
@@ -449,6 +561,7 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
}
#endif
+
/*
* Not strictly speaking an "up_ref" as a STACK doesn't have a reference
* count but it has the same effect by duping the STACK and upping the ref of
@@ -456,20 +569,22 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
*/
STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain)
{
- STACK_OF(X509) *ret;
+ STACK_OF(X509) *ret = sk_X509_dup(chain);
int i;
- ret = sk_X509_dup(chain);
+
if (ret == NULL)
return NULL;
for (i = 0; i < sk_X509_num(ret); i++) {
X509 *x = sk_X509_value(ret, i);
+
if (!X509_up_ref(x))
goto err;
}
return ret;
+
err:
while (i-- > 0)
- X509_free (sk_X509_value(ret, i));
+ X509_free(sk_X509_value(ret, i));
sk_X509_free(ret);
return NULL;
}
diff --git a/crypto/x509/x509_d2.c b/crypto/x509/x509_d2.c
index 099ffda1e15c..62aceb7acade 100644
--- a/crypto/x509/x509_d2.c
+++ b/crypto/x509/x509_d2.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -12,46 +12,100 @@
#include <openssl/crypto.h>
#include <openssl/x509.h>
-int X509_STORE_set_default_paths(X509_STORE *ctx)
+int X509_STORE_set_default_paths_ex(X509_STORE *ctx, OSSL_LIB_CTX *libctx,
+ const char *propq)
{
X509_LOOKUP *lookup;
lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file());
if (lookup == NULL)
return 0;
- X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
+ X509_LOOKUP_load_file_ex(lookup, NULL, X509_FILETYPE_DEFAULT, libctx, propq);
lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir());
if (lookup == NULL)
return 0;
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+ lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_store());
+ if (lookup == NULL)
+ return 0;
+ X509_LOOKUP_add_store_ex(lookup, NULL, libctx, propq);
+
/* clear any errors */
ERR_clear_error();
return 1;
}
+int X509_STORE_set_default_paths(X509_STORE *ctx)
+{
+ return X509_STORE_set_default_paths_ex(ctx, NULL, NULL);
+}
-int X509_STORE_load_locations(X509_STORE *ctx, const char *file,
- const char *path)
+int X509_STORE_load_file_ex(X509_STORE *ctx, const char *file,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509_LOOKUP *lookup;
+
+ if (file == NULL
+ || (lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file())) == NULL
+ || X509_LOOKUP_load_file_ex(lookup, file, X509_FILETYPE_PEM, libctx,
+ propq) <= 0)
+ return 0;
+
+ return 1;
+}
+
+int X509_STORE_load_file(X509_STORE *ctx, const char *file)
+{
+ return X509_STORE_load_file_ex(ctx, file, NULL, NULL);
+}
+
+int X509_STORE_load_path(X509_STORE *ctx, const char *path)
+{
+ X509_LOOKUP *lookup;
+
+ if (path == NULL
+ || (lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir())) == NULL
+ || X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) <= 0)
+ return 0;
+
+ return 1;
+}
+
+int X509_STORE_load_store_ex(X509_STORE *ctx, const char *uri,
+ OSSL_LIB_CTX *libctx, const char *propq)
{
X509_LOOKUP *lookup;
- if (file != NULL) {
- lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file());
- if (lookup == NULL)
- return 0;
- if (X509_LOOKUP_load_file(lookup, file, X509_FILETYPE_PEM) != 1)
- return 0;
- }
- if (path != NULL) {
- lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir());
- if (lookup == NULL)
- return 0;
- if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1)
- return 0;
- }
- if ((path == NULL) && (file == NULL))
+ if (uri == NULL
+ || (lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_store())) == NULL
+ || X509_LOOKUP_add_store_ex(lookup, uri, libctx, propq) == 0)
+ return 0;
+
+ return 1;
+}
+
+int X509_STORE_load_store(X509_STORE *ctx, const char *uri)
+{
+ return X509_STORE_load_store_ex(ctx, uri, NULL, NULL);
+}
+
+int X509_STORE_load_locations_ex(X509_STORE *ctx, const char *file,
+ const char *path, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ if (file == NULL && path == NULL)
+ return 0;
+ if (file != NULL && !X509_STORE_load_file_ex(ctx, file, libctx, propq))
+ return 0;
+ if (path != NULL && !X509_STORE_load_path(ctx, path))
return 0;
return 1;
}
+
+int X509_STORE_load_locations(X509_STORE *ctx, const char *file,
+ const char *path)
+{
+ return X509_STORE_load_locations_ex(ctx, file, path, NULL, NULL);
+}
diff --git a/crypto/x509/x509_def.c b/crypto/x509/x509_def.c
index bfa8d7d8522a..b8bdcb484195 100644
--- a/crypto/x509/x509_def.c
+++ b/crypto/x509/x509_def.c
@@ -1,7 +1,7 @@
/*
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c
index bdd1e67cd3fd..37467935c997 100644
--- a/crypto/x509/x509_err.c
+++ b/crypto/x509/x509_err.c
@@ -1,8 +1,8 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -10,107 +10,10 @@
#include <openssl/err.h>
#include <openssl/x509err.h>
+#include "crypto/x509err.h"
#ifndef OPENSSL_NO_ERR
-static const ERR_STRING_DATA X509_str_functs[] = {
- {ERR_PACK(ERR_LIB_X509, X509_F_ADD_CERT_DIR, 0), "add_cert_dir"},
- {ERR_PACK(ERR_LIB_X509, X509_F_BUILD_CHAIN, 0), "build_chain"},
- {ERR_PACK(ERR_LIB_X509, X509_F_BY_FILE_CTRL, 0), "by_file_ctrl"},
- {ERR_PACK(ERR_LIB_X509, X509_F_CHECK_NAME_CONSTRAINTS, 0),
- "check_name_constraints"},
- {ERR_PACK(ERR_LIB_X509, X509_F_CHECK_POLICY, 0), "check_policy"},
- {ERR_PACK(ERR_LIB_X509, X509_F_DANE_I2D, 0), "dane_i2d"},
- {ERR_PACK(ERR_LIB_X509, X509_F_DIR_CTRL, 0), "dir_ctrl"},
- {ERR_PACK(ERR_LIB_X509, X509_F_GET_CERT_BY_SUBJECT, 0),
- "get_cert_by_subject"},
- {ERR_PACK(ERR_LIB_X509, X509_F_I2D_X509_AUX, 0), "i2d_X509_AUX"},
- {ERR_PACK(ERR_LIB_X509, X509_F_LOOKUP_CERTS_SK, 0), "lookup_certs_sk"},
- {ERR_PACK(ERR_LIB_X509, X509_F_NETSCAPE_SPKI_B64_DECODE, 0),
- "NETSCAPE_SPKI_b64_decode"},
- {ERR_PACK(ERR_LIB_X509, X509_F_NETSCAPE_SPKI_B64_ENCODE, 0),
- "NETSCAPE_SPKI_b64_encode"},
- {ERR_PACK(ERR_LIB_X509, X509_F_NEW_DIR, 0), "new_dir"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509AT_ADD1_ATTR, 0), "X509at_add1_attr"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509V3_ADD_EXT, 0), "X509v3_add_ext"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_CREATE_BY_NID, 0),
- "X509_ATTRIBUTE_create_by_NID"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ, 0),
- "X509_ATTRIBUTE_create_by_OBJ"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_CREATE_BY_TXT, 0),
- "X509_ATTRIBUTE_create_by_txt"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_GET0_DATA, 0),
- "X509_ATTRIBUTE_get0_data"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_SET1_DATA, 0),
- "X509_ATTRIBUTE_set1_data"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_CHECK_PRIVATE_KEY, 0),
- "X509_check_private_key"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_DIFF, 0), "X509_CRL_diff"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_METHOD_NEW, 0),
- "X509_CRL_METHOD_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_PRINT_FP, 0), "X509_CRL_print_fp"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_EXTENSION_CREATE_BY_NID, 0),
- "X509_EXTENSION_create_by_NID"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_EXTENSION_CREATE_BY_OBJ, 0),
- "X509_EXTENSION_create_by_OBJ"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_GET_PUBKEY_PARAMETERS, 0),
- "X509_get_pubkey_parameters"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_LOAD_CERT_CRL_FILE, 0),
- "X509_load_cert_crl_file"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_LOAD_CERT_FILE, 0),
- "X509_load_cert_file"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_LOAD_CRL_FILE, 0),
- "X509_load_crl_file"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_LOOKUP_METH_NEW, 0),
- "X509_LOOKUP_meth_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_LOOKUP_NEW, 0), "X509_LOOKUP_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ADD_ENTRY, 0),
- "X509_NAME_add_entry"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_CANON, 0), "x509_name_canon"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_CREATE_BY_NID, 0),
- "X509_NAME_ENTRY_create_by_NID"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_CREATE_BY_TXT, 0),
- "X509_NAME_ENTRY_create_by_txt"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_SET_OBJECT, 0),
- "X509_NAME_ENTRY_set_object"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ONELINE, 0), "X509_NAME_oneline"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_PRINT, 0), "X509_NAME_print"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_OBJECT_NEW, 0), "X509_OBJECT_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_PRINT_EX_FP, 0), "X509_print_ex_fp"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_DECODE, 0),
- "x509_pubkey_decode"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_GET, 0), "X509_PUBKEY_get"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_GET0, 0), "X509_PUBKEY_get0"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_SET, 0), "X509_PUBKEY_set"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_CHECK_PRIVATE_KEY, 0),
- "X509_REQ_check_private_key"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_PRINT_EX, 0), "X509_REQ_print_ex"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_PRINT_FP, 0), "X509_REQ_print_fp"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_TO_X509, 0), "X509_REQ_to_X509"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_ADD_CERT, 0),
- "X509_STORE_add_cert"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_ADD_CRL, 0),
- "X509_STORE_add_crl"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_ADD_LOOKUP, 0),
- "X509_STORE_add_lookup"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_GET1_ISSUER, 0),
- "X509_STORE_CTX_get1_issuer"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_INIT, 0),
- "X509_STORE_CTX_init"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_NEW, 0),
- "X509_STORE_CTX_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_PURPOSE_INHERIT, 0),
- "X509_STORE_CTX_purpose_inherit"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_NEW, 0), "X509_STORE_new"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_TO_X509_REQ, 0), "X509_to_X509_REQ"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_ADD, 0), "X509_TRUST_add"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_SET, 0), "X509_TRUST_set"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_CERT, 0), "X509_verify_cert"},
- {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_PARAM_NEW, 0),
- "X509_VERIFY_PARAM_new"},
- {0, NULL}
-};
-
static const ERR_STRING_DATA X509_str_reasons[] = {
{ERR_PACK(ERR_LIB_X509, 0, X509_R_AKID_MISMATCH), "akid mismatch"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_BAD_SELECTOR), "bad selector"},
@@ -118,15 +21,24 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
{ERR_PACK(ERR_LIB_X509, 0, X509_R_BASE64_DECODE_ERROR),
"base64 decode error"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CANT_CHECK_DH_KEY), "cant check dh key"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERTIFICATE_VERIFICATION_FAILED),
+ "certificate verification failed"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE),
"cert already in hash table"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE),
"crl verify failure"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_DUPLICATE_ATTRIBUTE),
+ "duplicate attribute"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_ERROR_GETTING_MD_BY_NID),
+ "error getting md by nid"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_ERROR_USING_SIGINF_SET),
+ "error using siginf set"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_IDP_MISMATCH), "idp mismatch"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_ATTRIBUTES),
"invalid attributes"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DIRECTORY), "invalid directory"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DISTPOINT), "invalid distpoint"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_FIELD_NAME),
"invalid field name"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_TRUST), "invalid trust"},
@@ -162,6 +74,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_NID), "unknown nid"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_PURPOSE_ID),
"unknown purpose id"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_SIGID_ALGS),
+ "unknown sigid algs"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_TRUST_ID), "unknown trust id"},
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNSUPPORTED_ALGORITHM),
"unsupported algorithm"},
@@ -172,13 +86,11 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
#endif
-int ERR_load_X509_strings(void)
+int ossl_err_load_X509_strings(void)
{
#ifndef OPENSSL_NO_ERR
- if (ERR_func_error_string(X509_str_functs[0].error) == NULL) {
- ERR_load_strings_const(X509_str_functs);
+ if (ERR_reason_error_string(X509_str_reasons[0].error) == NULL)
ERR_load_strings_const(X509_str_reasons);
- }
#endif
return 1;
}
diff --git a/crypto/x509/x509_ext.c b/crypto/x509/x509_ext.c
index 4cdab724eadf..a7b85857bdad 100644
--- a/crypto/x509/x509_ext.c
+++ b/crypto/x509/x509_ext.c
@@ -1,7 +1,7 @@
/*
* Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
diff --git a/crypto/x509/x509_local.h b/crypto/x509/x509_local.h
index 10807e1def04..6d602e1d8ef5 100644
--- a/crypto/x509/x509_local.h
+++ b/crypto/x509/x509_local.h
@@ -1,7 +1,7 @@
/*
- * Copyright 2014-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -9,6 +9,9 @@
#include "internal/refcount.h"
+#define X509V3_conf_add_error_name_value(val) \
+ ERR_add_error_data(4, "name=", (val)->name, ", value=", (val)->value)
+
/*
* This structure holds all parameters associated with a verify operation by
* including an X509_VERIFY_PARAM structure in related structures the
@@ -36,7 +39,7 @@ struct X509_VERIFY_PARAM_st {
};
/* No error callback if depth < 0 */
-int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth);
+int ossl_x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth);
/* a sequence of these are used */
struct x509_attributes_st {
@@ -64,7 +67,7 @@ struct x509_crl_method_st {
int (*crl_init) (X509_CRL *crl);
int (*crl_free) (X509_CRL *crl);
int (*crl_lookup) (X509_CRL *crl, X509_REVOKED **ret,
- ASN1_INTEGER *ser, X509_NAME *issuer);
+ const ASN1_INTEGER *ser, const X509_NAME *issuer);
int (*crl_verify) (X509_CRL *crl, EVP_PKEY *pk);
};
@@ -77,15 +80,21 @@ struct x509_lookup_method_st {
int (*ctrl) (X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
char **ret);
int (*get_by_subject) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
- X509_NAME *name, X509_OBJECT *ret);
+ const X509_NAME *name, X509_OBJECT *ret);
int (*get_by_issuer_serial) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
- X509_NAME *name, ASN1_INTEGER *serial,
+ const X509_NAME *name,
+ const ASN1_INTEGER *serial,
X509_OBJECT *ret);
int (*get_by_fingerprint) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
const unsigned char *bytes, int len,
X509_OBJECT *ret);
int (*get_by_alias) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
const char *str, int len, X509_OBJECT *ret);
+ int (*get_by_subject_ex) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret,
+ OSSL_LIB_CTX *libctx, const char *propq);
+ int (*ctrl_ex) (X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
+ char **ret, OSSL_LIB_CTX *libctx, const char *propq);
};
/* This is the functions plus an instance of the local variables. */
@@ -128,8 +137,11 @@ struct x509_store_st {
int (*cert_crl) (X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x);
/* Check policy status of the chain */
int (*check_policy) (X509_STORE_CTX *ctx);
- STACK_OF(X509) *(*lookup_certs) (X509_STORE_CTX *ctx, X509_NAME *nm);
- STACK_OF(X509_CRL) *(*lookup_crls) (X509_STORE_CTX *ctx, X509_NAME *nm);
+ STACK_OF(X509) *(*lookup_certs) (X509_STORE_CTX *ctx,
+ const X509_NAME *nm);
+ /* cannot constify 'ctx' param due to lookup_certs_sk() in x509_vfy.c */
+ STACK_OF(X509_CRL) *(*lookup_crls) (const X509_STORE_CTX *ctx,
+ const X509_NAME *nm);
int (*cleanup) (X509_STORE_CTX *ctx);
CRYPTO_EX_DATA ex_data;
CRYPTO_REF_COUNT references;
@@ -143,7 +155,5 @@ DEFINE_STACK_OF(BY_DIR_ENTRY)
typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
-void x509_set_signature_info(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
- const ASN1_STRING *sig);
-int x509_likely_issued(X509 *issuer, X509 *subject);
-int x509_signing_allowed(const X509 *issuer, const X509 *subject);
+int ossl_x509_likely_issued(X509 *issuer, X509 *subject);
+int ossl_x509_signing_allowed(const X509 *issuer, const X509 *subject);
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index 641a41c35c78..d8927bda0706 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -20,7 +20,7 @@ X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method)
X509_LOOKUP *ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL) {
- X509err(X509_F_X509_LOOKUP_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
@@ -71,29 +71,49 @@ int X509_LOOKUP_shutdown(X509_LOOKUP *ctx)
return 1;
}
-int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
- char **ret)
+int X509_LOOKUP_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
+ char **ret, OSSL_LIB_CTX *libctx, const char *propq)
{
if (ctx->method == NULL)
return -1;
+ if (ctx->method->ctrl_ex != NULL)
+ return ctx->method->ctrl_ex(ctx, cmd, argc, argl, ret, libctx, propq);
if (ctx->method->ctrl != NULL)
return ctx->method->ctrl(ctx, cmd, argc, argl, ret);
+ return 1;
+}
+
+int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
+ char **ret)
+{
+ return X509_LOOKUP_ctrl_ex(ctx, cmd, argc, argl, ret, NULL, NULL);
+}
+
+int X509_LOOKUP_by_subject_ex(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ if (ctx->skip
+ || ctx->method == NULL
+ || (ctx->method->get_by_subject == NULL
+ && ctx->method->get_by_subject_ex == NULL))
+ return 0;
+ if (ctx->method->get_by_subject_ex != NULL)
+ return ctx->method->get_by_subject_ex(ctx, type, name, ret, libctx,
+ propq);
else
- return 1;
+ return ctx->method->get_by_subject(ctx, type, name, ret);
}
int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
- X509_NAME *name, X509_OBJECT *ret)
+ const X509_NAME *name, X509_OBJECT *ret)
{
- if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL))
- return 0;
- if (ctx->skip)
- return 0;
- return ctx->method->get_by_subject(ctx, type, name, ret);
+ return X509_LOOKUP_by_subject_ex(ctx, type, name, ret, NULL, NULL);
}
int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
- X509_NAME *name, ASN1_INTEGER *serial,
+ const X509_NAME *name,
+ const ASN1_INTEGER *serial,
X509_OBJECT *ret)
{
if ((ctx->method == NULL) || (ctx->method->get_by_issuer_serial == NULL))
@@ -162,34 +182,33 @@ X509_STORE *X509_STORE_new(void)
X509_STORE *ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
if ((ret->objs = sk_X509_OBJECT_new(x509_object_cmp)) == NULL) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
ret->cache = 1;
if ((ret->get_cert_methods = sk_X509_LOOKUP_new_null()) == NULL) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if ((ret->param = X509_VERIFY_PARAM_new()) == NULL) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data)) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
ret->lock = CRYPTO_THREAD_lock_new();
if (ret->lock == NULL) {
- X509err(X509_F_X509_STORE_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
-
ret->references = 1;
return ret;
@@ -237,7 +256,7 @@ int X509_STORE_up_ref(X509_STORE *vfy)
if (CRYPTO_UP_REF(&vfy->references, &i, vfy->lock) <= 0)
return 0;
- REF_PRINT_COUNT("X509_STORE", a);
+ REF_PRINT_COUNT("X509_STORE", vfy);
REF_ASSERT_ISNT(i < 2);
return ((i > 1) ? 1 : 0);
}
@@ -258,7 +277,7 @@ X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m)
/* a new one */
lu = X509_LOOKUP_new(m);
if (lu == NULL) {
- X509err(X509_F_X509_STORE_ADD_LOOKUP, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
@@ -266,14 +285,14 @@ X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m)
if (sk_X509_LOOKUP_push(v->get_cert_methods, lu))
return lu;
/* malloc failed */
- X509err(X509_F_X509_STORE_ADD_LOOKUP, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
X509_LOOKUP_free(lu);
return NULL;
}
X509_OBJECT *X509_STORE_CTX_get_obj_by_subject(X509_STORE_CTX *vs,
X509_LOOKUP_TYPE type,
- X509_NAME *name)
+ const X509_NAME *name)
{
X509_OBJECT *ret = X509_OBJECT_new();
@@ -286,10 +305,12 @@ X509_OBJECT *X509_STORE_CTX_get_obj_by_subject(X509_STORE_CTX *vs,
return ret;
}
-int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, X509_LOOKUP_TYPE type,
- X509_NAME *name, X509_OBJECT *ret)
+/* Also fill the cache with all matching certificates */
+int X509_STORE_CTX_get_by_subject(const X509_STORE_CTX *vs,
+ X509_LOOKUP_TYPE type,
+ const X509_NAME *name, X509_OBJECT *ret)
{
- X509_STORE *store = vs->ctx;
+ X509_STORE *store = vs->store;
X509_LOOKUP *lu;
X509_OBJECT stmp, *tmp;
int i, j;
@@ -300,15 +321,17 @@ int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, X509_LOOKUP_TYPE type,
stmp.type = X509_LU_NONE;
stmp.data.ptr = NULL;
+ if (!X509_STORE_lock(store))
+ return 0;
- X509_STORE_lock(store);
tmp = X509_OBJECT_retrieve_by_subject(store->objs, type, name);
X509_STORE_unlock(store);
if (tmp == NULL || type == X509_LU_CRL) {
for (i = 0; i < sk_X509_LOOKUP_num(store->get_cert_methods); i++) {
lu = sk_X509_LOOKUP_value(store->get_cert_methods, i);
- j = X509_LOOKUP_by_subject(lu, type, name, &stmp);
+ j = X509_LOOKUP_by_subject_ex(lu, type, name, &stmp, vs->libctx,
+ vs->propq);
if (j) {
tmp = &stmp;
break;
@@ -350,7 +373,12 @@ static int x509_store_add(X509_STORE *store, void *x, int crl) {
return 0;
}
- X509_STORE_lock(store);
+ if (!X509_STORE_lock(store)) {
+ obj->type = X509_LU_NONE;
+ X509_OBJECT_free(obj);
+ return 0;
+ }
+
if (X509_OBJECT_retrieve_match(store->objs, obj)) {
ret = 1;
} else {
@@ -368,7 +396,7 @@ static int x509_store_add(X509_STORE *store, void *x, int crl) {
int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
{
if (!x509_store_add(ctx, x, 0)) {
- X509err(X509_F_X509_STORE_ADD_CERT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
@@ -377,7 +405,7 @@ int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
{
if (!x509_store_add(ctx, x, 1)) {
- X509err(X509_F_X509_STORE_ADD_CRL, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
@@ -403,7 +431,7 @@ X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a)
return a->data.x509;
}
-X509_CRL *X509_OBJECT_get0_X509_CRL(X509_OBJECT *a)
+X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a)
{
if (a == NULL || a->type != X509_LU_CRL)
return NULL;
@@ -420,7 +448,7 @@ X509_OBJECT *X509_OBJECT_new(void)
X509_OBJECT *ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL) {
- X509err(X509_F_X509_OBJECT_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->type = X509_LU_NONE;
@@ -472,7 +500,7 @@ void X509_OBJECT_free(X509_OBJECT *a)
}
static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type,
- X509_NAME *name, int *pnmatch)
+ const X509_NAME *name, int *pnmatch)
{
X509_OBJECT stmp;
X509 x509_s;
@@ -483,42 +511,30 @@ static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type,
switch (type) {
case X509_LU_X509:
stmp.data.x509 = &x509_s;
- x509_s.cert_info.subject = name;
+ x509_s.cert_info.subject = (X509_NAME *)name; /* won't modify it */
break;
case X509_LU_CRL:
stmp.data.crl = &crl_s;
- crl_s.crl.issuer = name;
+ crl_s.crl.issuer = (X509_NAME *)name; /* won't modify it */
break;
case X509_LU_NONE:
/* abort(); */
return -1;
}
- idx = sk_X509_OBJECT_find(h, &stmp);
- if (idx >= 0 && pnmatch) {
- int tidx;
- const X509_OBJECT *tobj, *pstmp;
- *pnmatch = 1;
- pstmp = &stmp;
- for (tidx = idx + 1; tidx < sk_X509_OBJECT_num(h); tidx++) {
- tobj = sk_X509_OBJECT_value(h, tidx);
- if (x509_object_cmp(&tobj, &pstmp))
- break;
- (*pnmatch)++;
- }
- }
+ idx = sk_X509_OBJECT_find_all(h, &stmp, pnmatch);
return idx;
}
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type,
- X509_NAME *name)
+ const X509_NAME *name)
{
return x509_object_idx_cnt(h, type, name, NULL);
}
X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,
X509_LOOKUP_TYPE type,
- X509_NAME *name)
+ const X509_NAME *name)
{
int idx;
idx = X509_OBJECT_idx_by_subject(h, type, name);
@@ -527,23 +543,59 @@ X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,
return sk_X509_OBJECT_value(h, idx);
}
-STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v)
+STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(const X509_STORE *v)
{
return v->objs;
}
-STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
+STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *store)
+{
+ STACK_OF(X509) *sk;
+ STACK_OF(X509_OBJECT) *objs;
+ int i;
+
+ if (store == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if ((sk = sk_X509_new_null()) == NULL)
+ return NULL;
+ if (!X509_STORE_lock(store))
+ goto out_free;
+
+ objs = X509_STORE_get0_objects(store);
+ for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
+ X509 *cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
+
+ if (cert != NULL
+ && !X509_add_cert(sk, cert, X509_ADD_FLAG_UP_REF))
+ goto err;
+ }
+ X509_STORE_unlock(store);
+ return sk;
+
+ err:
+ X509_STORE_unlock(store);
+ out_free:
+ sk_X509_pop_free(sk, X509_free);
+ return NULL;
+}
+
+STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx,
+ const X509_NAME *nm)
{
int i, idx, cnt;
STACK_OF(X509) *sk = NULL;
X509 *x;
X509_OBJECT *obj;
- X509_STORE *store = ctx->ctx;
+ X509_STORE *store = ctx->store;
if (store == NULL)
return NULL;
- X509_STORE_lock(store);
+ if (!X509_STORE_lock(store))
+ return NULL;
+
idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt);
if (idx < 0) {
/*
@@ -561,7 +613,8 @@ STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
return NULL;
}
X509_OBJECT_free(xobj);
- X509_STORE_lock(store);
+ if (!X509_STORE_lock(store))
+ return NULL;
idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt);
if (idx < 0) {
X509_STORE_unlock(store);
@@ -573,29 +626,24 @@ STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
for (i = 0; i < cnt; i++, idx++) {
obj = sk_X509_OBJECT_value(store->objs, idx);
x = obj->data.x509;
- if (!X509_up_ref(x)) {
+ if (!X509_add_cert(sk, x, X509_ADD_FLAG_UP_REF)) {
X509_STORE_unlock(store);
sk_X509_pop_free(sk, X509_free);
return NULL;
}
- if (!sk_X509_push(sk, x)) {
- X509_STORE_unlock(store);
- X509_free(x);
- sk_X509_pop_free(sk, X509_free);
- return NULL;
- }
}
X509_STORE_unlock(store);
return sk;
}
-STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
+STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(const X509_STORE_CTX *ctx,
+ const X509_NAME *nm)
{
int i, idx, cnt;
STACK_OF(X509_CRL) *sk = sk_X509_CRL_new_null();
X509_CRL *x;
X509_OBJECT *obj, *xobj = X509_OBJECT_new();
- X509_STORE *store = ctx->ctx;
+ X509_STORE *store = ctx->store;
/* Always do lookup to possibly add new CRLs to cache */
if (sk == NULL
@@ -607,7 +655,10 @@ STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
return NULL;
}
X509_OBJECT_free(xobj);
- X509_STORE_lock(store);
+ if (!X509_STORE_lock(store)) {
+ sk_X509_CRL_free(sk);
+ return NULL;
+ }
idx = x509_object_idx_cnt(store->objs, X509_LU_CRL, nm, &cnt);
if (idx < 0) {
X509_STORE_unlock(store);
@@ -654,7 +705,7 @@ X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h,
if (!X509_cmp(obj->data.x509, x->data.x509))
return obj;
} else if (x->type == X509_LU_CRL) {
- if (!X509_CRL_match(obj->data.crl, x->data.crl))
+ if (X509_CRL_match(obj->data.crl, x->data.crl) == 0)
return obj;
} else
return obj;
@@ -663,11 +714,8 @@ X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h,
}
/*-
- * Try to get issuer certificate from store. Due to limitations
- * of the API this can only retrieve a single certificate matching
- * a given subject name. However it will fill the cache with all
- * matching certificates, so we can examine the cache for all
- * matches.
+ * Try to get issuer cert from |ctx->store| matching the subject name of |x|.
+ * Prefer the first non-expired one, else take the most recently expired one.
*
* Return values are:
* 1 lookup successful.
@@ -676,10 +724,10 @@ X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h,
*/
int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
{
- X509_NAME *xn;
+ const X509_NAME *xn;
X509_OBJECT *obj = X509_OBJECT_new(), *pobj = NULL;
- X509_STORE *store = ctx->ctx;
- int i, ok, idx, ret;
+ X509_STORE *store = ctx->store;
+ int i, ok, idx, ret, nmatch = 0;
if (obj == NULL)
return -1;
@@ -690,53 +738,58 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
X509_OBJECT_free(obj);
return 0;
}
- /* If certificate matches all OK */
+ /* If certificate matches and is currently valid all OK */
if (ctx->check_issued(ctx, x, obj->data.x509)) {
- if (x509_check_cert_time(ctx, obj->data.x509, -1)) {
+ if (ossl_x509_check_cert_time(ctx, obj->data.x509, -1)) {
*issuer = obj->data.x509;
- if (!X509_up_ref(*issuer)) {
- *issuer = NULL;
- ok = -1;
- }
+ /* |*issuer| has taken over the cert reference from |obj| */
+ obj->type = X509_LU_NONE;
X509_OBJECT_free(obj);
- return ok;
+ return 1;
}
}
X509_OBJECT_free(obj);
+ /*
+ * Due to limitations of the API this can only retrieve a single cert.
+ * However it will fill the cache with all matching certificates,
+ * so we can examine the cache for all matches.
+ */
if (store == NULL)
return 0;
- /* Else find index of first cert accepted by 'check_issued' */
+ /* Find index of first currently valid cert accepted by 'check_issued' */
ret = 0;
- X509_STORE_lock(store);
- idx = X509_OBJECT_idx_by_subject(store->objs, X509_LU_X509, xn);
- if (idx != -1) { /* should be true as we've had at least one
- * match */
+ if (!X509_STORE_lock(store))
+ return 0;
+
+ idx = x509_object_idx_cnt(store->objs, X509_LU_X509, xn, &nmatch);
+ if (idx != -1) { /* should be true as we've had at least one match */
/* Look through all matching certs for suitable issuer */
- for (i = idx; i < sk_X509_OBJECT_num(store->objs); i++) {
+ for (i = idx; i < idx + nmatch; i++) {
pobj = sk_X509_OBJECT_value(store->objs, i);
/* See if we've run past the matches */
if (pobj->type != X509_LU_X509)
break;
- if (X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509)))
- break;
if (ctx->check_issued(ctx, x, pobj->data.x509)) {
- *issuer = pobj->data.x509;
ret = 1;
+ /* If times check fine, exit with match, else keep looking. */
+ if (ossl_x509_check_cert_time(ctx, pobj->data.x509, -1)) {
+ *issuer = pobj->data.x509;
+ break;
+ }
/*
- * If times check, exit with match,
- * otherwise keep looking. Leave last
- * match in issuer so we return nearest
- * match if no certificate time is OK.
+ * Leave the so far most recently expired match in *issuer
+ * so we return nearest match if no certificate time is OK.
*/
-
- if (x509_check_cert_time(ctx, *issuer, -1))
- break;
+ if (*issuer == NULL
+ || ASN1_TIME_compare(X509_get0_notAfter(pobj->data.x509),
+ X509_get0_notAfter(*issuer)) > 0)
+ *issuer = pobj->data.x509;
}
}
}
- if (*issuer && !X509_up_ref(*issuer)) {
+ if (*issuer != NULL && !X509_up_ref(*issuer)) {
*issuer = NULL;
ret = -1;
}
@@ -765,12 +818,12 @@ int X509_STORE_set_trust(X509_STORE *ctx, int trust)
return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
}
-int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param)
+int X509_STORE_set1_param(X509_STORE *ctx, const X509_VERIFY_PARAM *param)
{
return X509_VERIFY_PARAM_set1(ctx->param, param);
}
-X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *ctx)
+X509_VERIFY_PARAM *X509_STORE_get0_param(const X509_STORE *ctx)
{
return ctx->param;
}
@@ -780,7 +833,7 @@ void X509_STORE_set_verify(X509_STORE *ctx, X509_STORE_CTX_verify_fn verify)
ctx->verify = verify;
}
-X509_STORE_CTX_verify_fn X509_STORE_get_verify(X509_STORE *ctx)
+X509_STORE_CTX_verify_fn X509_STORE_get_verify(const X509_STORE *ctx)
{
return ctx->verify;
}
@@ -791,7 +844,7 @@ void X509_STORE_set_verify_cb(X509_STORE *ctx,
ctx->verify_cb = verify_cb;
}
-X509_STORE_CTX_verify_cb X509_STORE_get_verify_cb(X509_STORE *ctx)
+X509_STORE_CTX_verify_cb X509_STORE_get_verify_cb(const X509_STORE *ctx)
{
return ctx->verify_cb;
}
@@ -802,7 +855,7 @@ void X509_STORE_set_get_issuer(X509_STORE *ctx,
ctx->get_issuer = get_issuer;
}
-X509_STORE_CTX_get_issuer_fn X509_STORE_get_get_issuer(X509_STORE *ctx)
+X509_STORE_CTX_get_issuer_fn X509_STORE_get_get_issuer(const X509_STORE *ctx)
{
return ctx->get_issuer;
}
@@ -813,7 +866,7 @@ void X509_STORE_set_check_issued(X509_STORE *ctx,
ctx->check_issued = check_issued;
}
-X509_STORE_CTX_check_issued_fn X509_STORE_get_check_issued(X509_STORE *ctx)
+X509_STORE_CTX_check_issued_fn X509_STORE_get_check_issued(const X509_STORE *ctx)
{
return ctx->check_issued;
}
@@ -824,7 +877,7 @@ void X509_STORE_set_check_revocation(X509_STORE *ctx,
ctx->check_revocation = check_revocation;
}
-X509_STORE_CTX_check_revocation_fn X509_STORE_get_check_revocation(X509_STORE *ctx)
+X509_STORE_CTX_check_revocation_fn X509_STORE_get_check_revocation(const X509_STORE *ctx)
{
return ctx->check_revocation;
}
@@ -835,7 +888,7 @@ void X509_STORE_set_get_crl(X509_STORE *ctx,
ctx->get_crl = get_crl;
}
-X509_STORE_CTX_get_crl_fn X509_STORE_get_get_crl(X509_STORE *ctx)
+X509_STORE_CTX_get_crl_fn X509_STORE_get_get_crl(const X509_STORE *ctx)
{
return ctx->get_crl;
}
@@ -846,7 +899,7 @@ void X509_STORE_set_check_crl(X509_STORE *ctx,
ctx->check_crl = check_crl;
}
-X509_STORE_CTX_check_crl_fn X509_STORE_get_check_crl(X509_STORE *ctx)
+X509_STORE_CTX_check_crl_fn X509_STORE_get_check_crl(const X509_STORE *ctx)
{
return ctx->check_crl;
}
@@ -857,7 +910,7 @@ void X509_STORE_set_cert_crl(X509_STORE *ctx,
ctx->cert_crl = cert_crl;
}
-X509_STORE_CTX_cert_crl_fn X509_STORE_get_cert_crl(X509_STORE *ctx)
+X509_STORE_CTX_cert_crl_fn X509_STORE_get_cert_crl(const X509_STORE *ctx)
{
return ctx->cert_crl;
}
@@ -868,7 +921,7 @@ void X509_STORE_set_check_policy(X509_STORE *ctx,
ctx->check_policy = check_policy;
}
-X509_STORE_CTX_check_policy_fn X509_STORE_get_check_policy(X509_STORE *ctx)
+X509_STORE_CTX_check_policy_fn X509_STORE_get_check_policy(const X509_STORE *ctx)
{
return ctx->check_policy;
}
@@ -879,7 +932,7 @@ void X509_STORE_set_lookup_certs(X509_STORE *ctx,
ctx->lookup_certs = lookup_certs;
}
-X509_STORE_CTX_lookup_certs_fn X509_STORE_get_lookup_certs(X509_STORE *ctx)
+X509_STORE_CTX_lookup_certs_fn X509_STORE_get_lookup_certs(const X509_STORE *ctx)
{
return ctx->lookup_certs;
}
@@ -890,7 +943,7 @@ void X509_STORE_set_lookup_crls(X509_STORE *ctx,
ctx->lookup_crls = lookup_crls;
}
-X509_STORE_CTX_lookup_crls_fn X509_STORE_get_lookup_crls(X509_STORE *ctx)
+X509_STORE_CTX_lookup_crls_fn X509_STORE_get_lookup_crls(const X509_STORE *ctx)
{
return ctx->lookup_crls;
}
@@ -901,7 +954,7 @@ void X509_STORE_set_cleanup(X509_STORE *ctx,
ctx->cleanup = ctx_cleanup;
}
-X509_STORE_CTX_cleanup_fn X509_STORE_get_cleanup(X509_STORE *ctx)
+X509_STORE_CTX_cleanup_fn X509_STORE_get_cleanup(const X509_STORE *ctx)
{
return ctx->cleanup;
}
@@ -911,12 +964,12 @@ int X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data)
return CRYPTO_set_ex_data(&ctx->ex_data, idx, data);
}
-void *X509_STORE_get_ex_data(X509_STORE *ctx, int idx)
+void *X509_STORE_get_ex_data(const X509_STORE *ctx, int idx)
{
return CRYPTO_get_ex_data(&ctx->ex_data, idx);
}
-X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx)
+X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx)
{
- return ctx->ctx;
+ return ctx->store;
}
diff --git a/crypto/x509/x509_meth.c b/crypto/x509/x509_meth.c
index 9348cc8eb788..a8eedd9b59af 100644
--- a/crypto/x509/x509_meth.c
+++ b/crypto/x509/x509_meth.c
@@ -1,7 +1,7 @@
/*
- * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -14,7 +14,7 @@
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/x509.h>
-#include <openssl/ossl_typ.h>
+#include <openssl/types.h>
#include "x509_local.h"
X509_LOOKUP_METHOD *X509_LOOKUP_meth_new(const char *name)
@@ -24,7 +24,7 @@ X509_LOOKUP_METHOD *X509_LOOKUP_meth_new(const char *name)
if (method != NULL) {
method->name = OPENSSL_strdup(name);
if (method->name == NULL) {
- X509err(X509_F_X509_LOOKUP_METH_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
}
diff --git a/crypto/x509/x509_obj.c b/crypto/x509/x509_obj.c
index f54d483cc4dd..12c6d6f78b6e 100644
--- a/crypto/x509/x509_obj.c
+++ b/crypto/x509/x509_obj.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -13,6 +13,7 @@
#include <openssl/x509.h>
#include <openssl/buffer.h>
#include "crypto/x509.h"
+#include "crypto/ctype.h"
/*
* Limit to ensure we don't overflow: much greater than
@@ -26,6 +27,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
const X509_NAME_ENTRY *ne;
int i;
int n, lold, l, l1, l2, num, j, type;
+ int prev_set = -1;
const char *s;
char *p;
unsigned char *q;
@@ -71,7 +73,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
type = ne->value->type;
num = ne->value->length;
if (num > NAME_ONELINE_MAX) {
- X509err(X509_F_X509_NAME_ONELINE, X509_R_NAME_TOO_LONG);
+ ERR_raise(ERR_LIB_X509, X509_R_NAME_TOO_LONG);
goto end;
}
q = ne->value->data;
@@ -107,20 +109,17 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
if (!gs_doit[j & 3])
continue;
l2++;
-#ifndef CHARSET_EBCDIC
- if ((q[j] < ' ') || (q[j] > '~'))
- l2 += 3;
-#else
- if ((os_toascii[q[j]] < os_toascii[' ']) ||
- (os_toascii[q[j]] > os_toascii['~']))
+ if (q[j] == '/' || q[j] == '+')
+ l2++; /* char needs to be escaped */
+ else if ((ossl_toascii(q[j]) < ossl_toascii(' ')) ||
+ (ossl_toascii(q[j]) > ossl_toascii('~')))
l2 += 3;
-#endif
}
lold = l;
l += 1 + l1 + 1 + l2;
if (l > NAME_ONELINE_MAX) {
- X509err(X509_F_X509_NAME_ONELINE, X509_R_NAME_TOO_LONG);
+ ERR_raise(ERR_LIB_X509, X509_R_NAME_TOO_LONG);
goto end;
}
if (b != NULL) {
@@ -131,7 +130,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
break;
} else
p = &(buf[lold]);
- *(p++) = '/';
+ *(p++) = prev_set == ne->set ? '+' : '/';
memcpy(p, s, (unsigned int)l1);
p += l1;
*(p++) = '=';
@@ -150,8 +149,11 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
*(p++) = 'x';
*(p++) = hex[(n >> 4) & 0x0f];
*(p++) = hex[n & 0x0f];
- } else
+ } else {
+ if (n == '/' || n == '+')
+ *(p++) = '\\';
*(p++) = n;
+ }
#else
n = os_toascii[q[j]];
if ((n < os_toascii[' ']) || (n > os_toascii['~'])) {
@@ -159,11 +161,15 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
*(p++) = 'x';
*(p++) = hex[(n >> 4) & 0x0f];
*(p++) = hex[n & 0x0f];
- } else
+ } else {
+ if (n == os_toascii['/'] || n == os_toascii['+'])
+ *(p++) = '\\';
*(p++) = q[j];
+ }
#endif
}
*p = '\0';
+ prev_set = ne->set;
}
if (b != NULL) {
p = b->data;
@@ -174,7 +180,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
*p = '\0';
return p;
err:
- X509err(X509_F_X509_NAME_ONELINE, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
end:
BUF_MEM_free(b);
return NULL;
diff --git a/crypto/x509/x509_r2x.c b/crypto/x509/x509_r2x.c
index 6b1623feacb7..c7f6181c4465 100644
--- a/crypto/x509/x509_r2x.c
+++ b/crypto/x509/x509_r2x.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -21,11 +21,11 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
{
X509 *ret = NULL;
X509_CINF *xi = NULL;
- X509_NAME *xn;
+ const X509_NAME *xn;
EVP_PKEY *pubkey = NULL;
if ((ret = X509_new()) == NULL) {
- X509err(X509_F_X509_REQ_TO_X509, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c
index c2b8cb9f3e2d..0434fbbc6b70 100644
--- a/crypto/x509/x509_req.c
+++ b/crypto/x509/x509_req.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -26,9 +26,9 @@ X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
int i;
EVP_PKEY *pktmp;
- ret = X509_REQ_new();
+ ret = X509_REQ_new_ex(x->libctx, x->propq);
if (ret == NULL) {
- X509err(X509_F_X509_TO_X509_REQ, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -85,33 +85,18 @@ int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k)
int ok = 0;
xk = X509_REQ_get_pubkey(x);
- switch (EVP_PKEY_cmp(xk, k)) {
+ switch (EVP_PKEY_eq(xk, k)) {
case 1:
ok = 1;
break;
case 0:
- X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY,
- X509_R_KEY_VALUES_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH);
break;
case -1:
- X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, X509_R_KEY_TYPE_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH);
break;
case -2:
-#ifndef OPENSSL_NO_EC
- if (EVP_PKEY_id(k) == EVP_PKEY_EC) {
- X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, ERR_R_EC_LIB);
- break;
- }
-#endif
-#ifndef OPENSSL_NO_DH
- if (EVP_PKEY_id(k) == EVP_PKEY_DH) {
- /* No idea */
- X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY,
- X509_R_CANT_CHECK_DH_KEY);
- break;
- }
-#endif
- X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, X509_R_UNKNOWN_KEY_TYPE);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE);
}
EVP_PKEY_free(xk);
@@ -131,6 +116,7 @@ static int *ext_nids = ext_nid_list;
int X509_REQ_extension_nid(int req_nid)
{
int i, nid;
+
for (i = 0;; i++) {
nid = ext_nids[i];
if (nid == NID_undef)
@@ -157,7 +143,7 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
int idx, *pnid;
const unsigned char *p;
- if ((req == NULL) || !ext_nids)
+ if (req == NULL || !ext_nids)
return NULL;
for (pnid = ext_nids; *pnid != NID_undef; pnid++) {
idx = X509_REQ_get_attr_by_NID(req, *pnid, -1);
@@ -181,15 +167,15 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
* Add a STACK_OF extensions to a certificate request: allow alternative OIDs
* in case we want to create a non standard one.
*/
-
-int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
- int nid)
+int X509_REQ_add_extensions_nid(X509_REQ *req,
+ const STACK_OF(X509_EXTENSION) *exts, int nid)
{
int extlen;
int rv = 0;
unsigned char *ext = NULL;
+
/* Generate encoding of extensions */
- extlen = ASN1_item_i2d((ASN1_VALUE *)exts, &ext,
+ extlen = ASN1_item_i2d((const ASN1_VALUE *)exts, &ext,
ASN1_ITEM_rptr(X509_EXTENSIONS));
if (extlen <= 0)
return 0;
@@ -199,7 +185,7 @@ int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
}
/* This is the normal usage: use the "official" OID */
-int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts)
+int X509_REQ_add_extensions(X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts)
{
return X509_REQ_add_extensions_nid(req, exts, NID_ext_req);
}
@@ -229,8 +215,13 @@ X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc)
X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc)
{
- X509_ATTRIBUTE *attr = X509at_delete_attr(req->req_info.attributes, loc);
+ X509_ATTRIBUTE *attr;
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ attr = X509at_delete_attr(req->req_info.attributes, loc);
if (attr != NULL)
req->req_info.enc.modified = 1;
return attr;
@@ -238,6 +229,10 @@ X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc)
int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr)
{
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
if (!X509at_add1_attr(&req->req_info.attributes, attr))
return 0;
req->req_info.enc.modified = 1;
@@ -248,6 +243,10 @@ int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
const ASN1_OBJECT *obj, int type,
const unsigned char *bytes, int len)
{
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
if (!X509at_add1_attr_by_OBJ(&req->req_info.attributes, obj,
type, bytes, len))
return 0;
@@ -259,6 +258,10 @@ int X509_REQ_add1_attr_by_NID(X509_REQ *req,
int nid, int type,
const unsigned char *bytes, int len)
{
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
if (!X509at_add1_attr_by_NID(&req->req_info.attributes, nid,
type, bytes, len))
return 0;
@@ -270,6 +273,10 @@ int X509_REQ_add1_attr_by_txt(X509_REQ *req,
const char *attrname, int type,
const unsigned char *bytes, int len)
{
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
if (!X509at_add1_attr_by_txt(&req->req_info.attributes, attrname,
type, bytes, len))
return 0;
@@ -299,7 +306,7 @@ void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig,
void X509_REQ_set0_signature(X509_REQ *req, ASN1_BIT_STRING *psig)
{
if (req->signature)
- ASN1_BIT_STRING_free(req->signature);
+ ASN1_BIT_STRING_free(req->signature);
req->signature = psig;
}
@@ -315,6 +322,10 @@ int X509_REQ_get_signature_nid(const X509_REQ *req)
int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp)
{
+ if (req == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
req->req_info.enc.modified = 1;
return i2d_X509_REQ_INFO(&req->req_info, pp);
}
diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
index 164b4e2be136..d8ddde8aaa51 100644
--- a/crypto/x509/x509_set.c
+++ b/crypto/x509/x509_set.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -47,21 +47,21 @@ int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial)
return 1;
}
-int X509_set_issuer_name(X509 *x, X509_NAME *name)
+int X509_set_issuer_name(X509 *x, const X509_NAME *name)
{
if (x == NULL)
return 0;
return X509_NAME_set(&x->cert_info.issuer, name);
}
-int X509_set_subject_name(X509 *x, X509_NAME *name)
+int X509_set_subject_name(X509 *x, const X509_NAME *name)
{
if (x == NULL)
return 0;
return X509_NAME_set(&x->cert_info.subject, name);
}
-int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm)
+int ossl_x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm)
{
ASN1_TIME *in;
in = *ptm;
@@ -79,14 +79,14 @@ int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm)
{
if (x == NULL)
return 0;
- return x509_set1_time(&x->cert_info.validity.notBefore, tm);
+ return ossl_x509_set1_time(&x->cert_info.validity.notBefore, tm);
}
int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm)
{
if (x == NULL)
return 0;
- return x509_set1_time(&x->cert_info.validity.notAfter, tm);
+ return ossl_x509_set1_time(&x->cert_info.validity.notAfter, tm);
}
int X509_set_pubkey(X509 *x, EVP_PKEY *pkey)
@@ -192,46 +192,85 @@ int X509_get_signature_info(X509 *x, int *mdnid, int *pknid, int *secbits,
return X509_SIG_INFO_get(&x->siginf, mdnid, pknid, secbits, flags);
}
-static void x509_sig_info_init(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
- const ASN1_STRING *sig)
+/* Modify *siginf according to alg and sig. Return 1 on success, else 0. */
+static int x509_sig_info_init(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
+ const ASN1_STRING *sig)
{
int pknid, mdnid;
const EVP_MD *md;
+ const EVP_PKEY_ASN1_METHOD *ameth;
siginf->mdnid = NID_undef;
siginf->pknid = NID_undef;
siginf->secbits = -1;
siginf->flags = 0;
if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), &mdnid, &pknid)
- || pknid == NID_undef)
- return;
+ || pknid == NID_undef) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_SIGID_ALGS);
+ return 0;
+ }
+ siginf->mdnid = mdnid;
siginf->pknid = pknid;
- if (mdnid == NID_undef) {
+
+ switch (mdnid) {
+ case NID_undef:
/* If we have one, use a custom handler for this algorithm */
- const EVP_PKEY_ASN1_METHOD *ameth = EVP_PKEY_asn1_find(NULL, pknid);
+ ameth = EVP_PKEY_asn1_find(NULL, pknid);
if (ameth == NULL || ameth->siginf_set == NULL
- || ameth->siginf_set(siginf, alg, sig) == 0)
- return;
- siginf->flags |= X509_SIG_INFO_VALID;
- return;
+ || !ameth->siginf_set(siginf, alg, sig)) {
+ ERR_raise(ERR_LIB_X509, X509_R_ERROR_USING_SIGINF_SET);
+ return 0;
+ }
+ break;
+ /*
+ * SHA1 and MD5 are known to be broken. Reduce security bits so that
+ * they're no longer accepted at security level 1.
+ * The real values don't really matter as long as they're lower than 80,
+ * which is our security level 1.
+ */
+ case NID_sha1:
+ /*
+ * https://eprint.iacr.org/2020/014 puts a chosen-prefix attack
+ * for SHA1 at2^63.4
+ */
+ siginf->secbits = 63;
+ break;
+ case NID_md5:
+ /*
+ * https://documents.epfl.ch/users/l/le/lenstra/public/papers/lat.pdf
+ * puts a chosen-prefix attack for MD5 at 2^39.
+ */
+ siginf->secbits = 39;
+ break;
+ case NID_id_GostR3411_94:
+ /*
+ * There is a collision attack on GOST R 34.11-94 at 2^105, see
+ * https://link.springer.com/chapter/10.1007%2F978-3-540-85174-5_10
+ */
+ siginf->secbits = 105;
+ break;
+ default:
+ /* Security bits: half number of bits in digest */
+ if ((md = EVP_get_digestbynid(mdnid)) == NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_ERROR_GETTING_MD_BY_NID);
+ return 0;
+ }
+ siginf->secbits = EVP_MD_get_size(md) * 4;
+ break;
}
- siginf->flags |= X509_SIG_INFO_VALID;
- siginf->mdnid = mdnid;
- md = EVP_get_digestbynid(mdnid);
- if (md == NULL)
- return;
- /* Security bits: half number of bits in digest */
- siginf->secbits = EVP_MD_size(md) * 4;
switch (mdnid) {
- case NID_sha1:
- case NID_sha256:
- case NID_sha384:
- case NID_sha512:
+ case NID_sha1:
+ case NID_sha256:
+ case NID_sha384:
+ case NID_sha512:
siginf->flags |= X509_SIG_INFO_TLS;
}
+ siginf->flags |= X509_SIG_INFO_VALID;
+ return 1;
}
-void x509_init_sig_info(X509 *x)
+/* Returns 1 on success, 0 on failure */
+int ossl_x509_init_sig_info(X509 *x)
{
- x509_sig_info_init(&x->siginf, &x->sig_alg, &x->signature);
+ return x509_sig_info_init(&x->siginf, &x->sig_alg, &x->signature);
}
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trust.c
index a10d437735b8..fd77b0c6fe61 100644
--- a/crypto/x509/x509_trs.c
+++ b/crypto/x509/x509_trust.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -72,7 +72,7 @@ int X509_check_trust(X509 *x, int id, int flags)
return obj_trust(NID_anyExtendedKeyUsage, x,
flags | X509_TRUST_DO_SS_COMPAT);
idx = X509_TRUST_get_by_id(id);
- if (idx == -1)
+ if (idx < 0)
return default_trust(id, x, flags);
pt = X509_TRUST_get0(idx);
return pt->check_trust(pt, x, flags);
@@ -112,8 +112,8 @@ int X509_TRUST_get_by_id(int id)
int X509_TRUST_set(int *t, int trust)
{
- if (X509_TRUST_get_by_id(trust) == -1) {
- X509err(X509_F_X509_TRUST_SET, X509_R_INVALID_TRUST);
+ if (X509_TRUST_get_by_id(trust) < 0) {
+ ERR_raise(ERR_LIB_X509, X509_R_INVALID_TRUST);
return 0;
}
*t = trust;
@@ -134,9 +134,9 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
/* Get existing entry if any */
idx = X509_TRUST_get_by_id(id);
/* Need a new entry */
- if (idx == -1) {
+ if (idx < 0) {
if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) {
- X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return 0;
}
trtmp->flags = X509_TRUST_DYNAMIC;
@@ -148,7 +148,7 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
OPENSSL_free(trtmp->name);
/* dup supplied name */
if ((trtmp->name = OPENSSL_strdup(name)) == NULL) {
- X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
/* Keep the dynamic flag of existing entry */
@@ -162,20 +162,20 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
trtmp->arg2 = arg2;
/* If its a new entry manage the dynamic table */
- if (idx == -1) {
+ if (idx < 0) {
if (trtable == NULL
&& (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) {
- X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;;
}
if (!sk_X509_TRUST_push(trtable, trtmp)) {
- X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
}
return 1;
err:
- if (idx == -1) {
+ if (idx < 0) {
OPENSSL_free(trtmp->name);
OPENSSL_free(trtmp);
}
@@ -184,7 +184,7 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
static void trtable_free(X509_TRUST *p)
{
- if (!p)
+ if (p == NULL)
return;
if (p->flags & X509_TRUST_DYNAMIC) {
if (p->flags & X509_TRUST_DYNAMIC_NAME)
@@ -220,7 +220,7 @@ static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
* Declare the chain verified if the desired trust OID is not rejected in
* any auxiliary trust info for this certificate, and the OID is either
* expressly trusted, or else either "anyEKU" is trusted, or the
- * certificate is self-signed.
+ * certificate is self-signed and X509_TRUST_NO_SS_COMPAT is not set.
*/
flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU;
return obj_trust(trust->arg1, x, flags);
@@ -239,7 +239,7 @@ static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
{
- /* Call for side-effect of computing hash and caching extensions */
+ /* Call for side-effect of setting EXFLAG_SS for self-signed-certs */
if (X509_check_purpose(x, -1, 0) != 1)
return X509_TRUST_UNTRUSTED;
if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && (x->ex_flags & EXFLAG_SS))
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index 02bde640d8e8..61d41117e2c0 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -58,9 +58,9 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_OUT_OF_MEM:
return "out of memory";
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- return "self signed certificate";
+ return "self-signed certificate";
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- return "self signed certificate in certificate chain";
+ return "self-signed certificate in certificate chain";
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
return "unable to get local issuer certificate";
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
@@ -69,12 +69,12 @@ const char *X509_verify_cert_error_string(long n)
return "certificate chain too long";
case X509_V_ERR_CERT_REVOKED:
return "certificate revoked";
- case X509_V_ERR_INVALID_CA:
- return "invalid CA certificate";
+ case X509_V_ERR_NO_ISSUER_PUBLIC_KEY:
+ return "issuer certificate doesn't have a public key";
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
return "path length constraint exceeded";
case X509_V_ERR_INVALID_PURPOSE:
- return "unsupported certificate purpose";
+ return "unsuitable certificate purpose";
case X509_V_ERR_CERT_UNTRUSTED:
return "certificate not trusted";
case X509_V_ERR_CERT_REJECTED:
@@ -111,9 +111,9 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_NO_EXPLICIT_POLICY:
return "no explicit policy";
case X509_V_ERR_DIFFERENT_CRL_SCOPE:
- return "Different CRL scope";
+ return "different CRL scope";
case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE:
- return "Unsupported extension feature";
+ return "unsupported extension feature";
case X509_V_ERR_UNNESTED_RESOURCE:
return "RFC 3779 resource not subset of parent's resources";
case X509_V_ERR_PERMITTED_VIOLATION:
@@ -133,7 +133,7 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_CRL_PATH_VALIDATION_ERROR:
return "CRL path validation error";
case X509_V_ERR_PATH_LOOP:
- return "Path Loop";
+ return "path loop";
case X509_V_ERR_SUITE_B_INVALID_VERSION:
return "Suite B: certificate version invalid";
case X509_V_ERR_SUITE_B_INVALID_ALGORITHM:
@@ -147,13 +147,13 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256:
return "Suite B: cannot sign P-384 with P-256";
case X509_V_ERR_HOSTNAME_MISMATCH:
- return "Hostname mismatch";
+ return "hostname mismatch";
case X509_V_ERR_EMAIL_MISMATCH:
- return "Email address mismatch";
+ return "email address mismatch";
case X509_V_ERR_IP_ADDRESS_MISMATCH:
return "IP address mismatch";
case X509_V_ERR_DANE_NO_MATCH:
- return "No matching DANE TLSA records";
+ return "no matching DANE TLSA records";
case X509_V_ERR_EE_KEY_TOO_SMALL:
return "EE certificate key too weak";
case X509_V_ERR_CA_KEY_TOO_SMALL:
@@ -161,9 +161,9 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_CA_MD_TOO_WEAK:
return "CA signature digest algorithm too weak";
case X509_V_ERR_INVALID_CALL:
- return "Invalid certificate verification context";
+ return "invalid certificate verification context";
case X509_V_ERR_STORE_LOOKUP:
- return "Issuer certificate lookup error";
+ return "issuer certificate lookup error";
case X509_V_ERR_NO_VALID_SCTS:
return "Certificate Transparency required, but no valid SCTs found";
case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION:
@@ -174,9 +174,50 @@ const char *X509_verify_cert_error_string(long n)
return "OCSP verification failed";
case X509_V_ERR_OCSP_CERT_UNKNOWN:
return "OCSP unknown cert";
+ case X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM:
+ return "Cannot find certificate signature algorithm";
+ case X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH:
+ return "subject signature algorithm and issuer public key algorithm mismatch";
+ case X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY:
+ return "cert info signature and signature algorithm mismatch";
+ case X509_V_ERR_INVALID_CA:
+ return "invalid CA certificate";
+ case X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA:
+ return "Path length invalid for non-CA cert";
+ case X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN:
+ return "Path length given without key usage keyCertSign";
+ case X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA:
+ return "Key usage keyCertSign invalid for non-CA cert";
+ case X509_V_ERR_ISSUER_NAME_EMPTY:
+ return "Issuer name empty";
+ case X509_V_ERR_SUBJECT_NAME_EMPTY:
+ return "Subject name empty";
+ case X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER:
+ return "Missing Authority Key Identifier";
+ case X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER:
+ return "Missing Subject Key Identifier";
+ case X509_V_ERR_EMPTY_SUBJECT_ALT_NAME:
+ return "Empty Subject Alternative Name extension";
+ case X509_V_ERR_CA_BCONS_NOT_CRITICAL:
+ return "Basic Constraints of CA cert not marked critical";
+ case X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL:
+ return "Subject empty and Subject Alt Name extension not critical";
+ case X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL:
+ return "Authority Key Identifier marked critical";
+ case X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL:
+ return "Subject Key Identifier marked critical";
+ case X509_V_ERR_CA_CERT_MISSING_KEY_USAGE:
+ return "CA cert does not include key usage extension";
+ case X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3:
+ return "Using cert extension requires at least X509v3";
case X509_V_ERR_EC_KEY_EXPLICIT_PARAMS:
return "Certificate public key has explicit ECC parameters";
+ /*
+ * Entries must be kept consistent with include/openssl/x509_vfy.h.in
+ * and with doc/man3/X509_STORE_CTX_get_error.pod
+ */
+
default:
/* Printing an error number into a static buffer is not thread-safe */
return "unknown certificate verification error";
diff --git a/crypto/x509/x509_v3.c b/crypto/x509/x509_v3.c
index c7876023304c..62ae7d6b8d62 100644
--- a/crypto/x509/x509_v3.c
+++ b/crypto/x509/x509_v3.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -19,9 +19,12 @@
int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x)
{
+ int ret;
+
if (x == NULL)
return 0;
- return sk_X509_EXTENSION_num(x);
+ ret = sk_X509_EXTENSION_num(x);
+ return ret > 0 ? ret : 0;
}
int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid,
@@ -101,7 +104,7 @@ STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
STACK_OF(X509_EXTENSION) *sk = NULL;
if (x == NULL) {
- X509err(X509_F_X509V3_ADD_EXT, ERR_R_PASSED_NULL_PARAMETER);
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
goto err2;
}
@@ -125,7 +128,7 @@ STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
*x = sk;
return sk;
err:
- X509err(X509_F_X509V3_ADD_EXT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
err2:
X509_EXTENSION_free(new_ex);
if (x != NULL && *x == NULL)
@@ -142,7 +145,7 @@ X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid,
obj = OBJ_nid2obj(nid);
if (obj == NULL) {
- X509err(X509_F_X509_EXTENSION_CREATE_BY_NID, X509_R_UNKNOWN_NID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_NID);
return NULL;
}
ret = X509_EXTENSION_create_by_OBJ(ex, obj, crit, data);
@@ -159,8 +162,7 @@ X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex,
if ((ex == NULL) || (*ex == NULL)) {
if ((ret = X509_EXTENSION_new()) == NULL) {
- X509err(X509_F_X509_EXTENSION_CREATE_BY_OBJ,
- ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
} else
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 925fbb541258..d19efeaa9919 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -1,12 +1,14 @@
/*
- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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/deprecated.h"
+
#include <stdio.h>
#include <time.h>
#include <errno.h>
@@ -21,47 +23,23 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/objects.h>
+#include <openssl/core_names.h>
#include "internal/dane.h"
#include "crypto/x509.h"
#include "x509_local.h"
/* CRL score values */
-/* No unhandled critical extensions */
-
-#define CRL_SCORE_NOCRITICAL 0x100
-
-/* certificate is within CRL scope */
-
-#define CRL_SCORE_SCOPE 0x080
-
-/* CRL times valid */
-
-#define CRL_SCORE_TIME 0x040
-
-/* Issuer name matches certificate */
-
-#define CRL_SCORE_ISSUER_NAME 0x020
-
-/* If this score or above CRL is probably valid */
-
-#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE)
-
-/* CRL issuer is certificate issuer */
-
-#define CRL_SCORE_ISSUER_CERT 0x018
-
-/* CRL issuer is on certificate path */
-
-#define CRL_SCORE_SAME_PATH 0x008
-
-/* CRL issuer matches CRL AKID */
-
-#define CRL_SCORE_AKID 0x004
-
-/* Have a delta CRL with valid times */
-
-#define CRL_SCORE_TIME_DELTA 0x002
+#define CRL_SCORE_NOCRITICAL 0x100 /* No unhandled critical extensions */
+#define CRL_SCORE_SCOPE 0x080 /* certificate is within CRL scope */
+#define CRL_SCORE_TIME 0x040 /* CRL times valid */
+#define CRL_SCORE_ISSUER_NAME 0x020 /* Issuer name matches certificate */
+#define CRL_SCORE_VALID /* If this score or above CRL is probably valid */ \
+ (CRL_SCORE_NOCRITICAL | CRL_SCORE_TIME | CRL_SCORE_SCOPE)
+#define CRL_SCORE_ISSUER_CERT 0x018 /* CRL issuer is certificate issuer */
+#define CRL_SCORE_SAME_PATH 0x008 /* CRL issuer is on certificate path */
+#define CRL_SCORE_AKID 0x004 /* CRL issuer matches CRL AKID */
+#define CRL_SCORE_TIME_DELTA 0x002 /* Have a delta CRL with valid times */
static int build_chain(X509_STORE_CTX *ctx);
static int verify_chain(X509_STORE_CTX *ctx);
@@ -69,7 +47,7 @@ static int dane_verify(X509_STORE_CTX *ctx);
static int null_callback(int ok, X509_STORE_CTX *e);
static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
-static int check_chain_extensions(X509_STORE_CTX *ctx);
+static int check_extensions(X509_STORE_CTX *ctx);
static int check_name_constraints(X509_STORE_CTX *ctx);
static int check_id(X509_STORE_CTX *ctx);
static int check_trust(X509_STORE_CTX *ctx, int num_untrusted);
@@ -105,64 +83,90 @@ static int null_callback(int ok, X509_STORE_CTX *e)
return ok;
}
-/*
- * Return 1 if given cert is considered self-signed, 0 if not or on error.
- * This does not verify self-signedness but relies on x509v3_cache_extensions()
- * matching issuer and subject names (i.e., the cert being self-issued) and any
- * present authority key identifier matching the subject key identifier, etc.
+/*-
+ * Return 1 if given cert is considered self-signed, 0 if not, or -1 on error.
+ * This actually verifies self-signedness only if requested.
+ * It calls ossl_x509v3_cache_extensions()
+ * to match issuer and subject names (i.e., the cert being self-issued) and any
+ * present authority key identifier to match the subject key identifier, etc.
*/
-static int cert_self_signed(X509 *x)
+int X509_self_signed(X509 *cert, int verify_signature)
{
- if (X509_check_purpose(x, -1, 0) != 1)
+ EVP_PKEY *pkey;
+
+ if ((pkey = X509_get0_pubkey(cert)) == NULL) { /* handles cert == NULL */
+ ERR_raise(ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+ return -1;
+ }
+ if (!ossl_x509v3_cache_extensions(cert))
+ return -1;
+ if ((cert->ex_flags & EXFLAG_SS) == 0)
return 0;
- if (x->ex_flags & EXFLAG_SS)
+ if (!verify_signature)
return 1;
- else
- return 0;
+ return X509_verify(cert, pkey);
}
-/* Given a certificate try and find an exact match in the store */
-
-static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
+/*
+ * Given a certificate, try and find an exact match in the store.
+ * Returns 1 on success, 0 on not found, -1 on internal error.
+ */
+static int lookup_cert_match(X509 **result, X509_STORE_CTX *ctx, X509 *x)
{
STACK_OF(X509) *certs;
X509 *xtmp = NULL;
- int i;
+ int i, ret;
+
+ *result = NULL;
/* Lookup all certs with matching subject name */
+ ERR_set_mark();
certs = ctx->lookup_certs(ctx, X509_get_subject_name(x));
+ ERR_pop_to_mark();
if (certs == NULL)
- return NULL;
+ return -1;
/* Look for exact match */
for (i = 0; i < sk_X509_num(certs); i++) {
xtmp = sk_X509_value(certs, i);
- if (!X509_cmp(xtmp, x))
+ if (X509_cmp(xtmp, x) == 0)
break;
xtmp = NULL;
}
- if (xtmp != NULL && !X509_up_ref(xtmp))
- xtmp = NULL;
+ ret = xtmp != NULL;
+ if (ret) {
+ if (!X509_up_ref(xtmp))
+ ret = -1;
+ else
+ *result = xtmp;
+ }
sk_X509_pop_free(certs, X509_free);
- return xtmp;
+ return ret;
}
/*-
* Inform the verify callback of an error.
- * If B<x> is not NULL it is the error cert, otherwise use the chain cert at
- * B<depth>.
- * If B<err> is not X509_V_OK, that's the error value, otherwise leave
- * unchanged (presumably set by the caller).
+ * The error code is set to |err| if |err| is not X509_V_OK, else
+ * |ctx->error| is left unchanged (under the assumption it is set elsewhere).
+ * The error depth is |depth| if >= 0, else it defaults to |ctx->error_depth|.
+ * The error cert is |x| if not NULL, else defaults to the chain cert at depth.
*
* Returns 0 to abort verification with an error, non-zero to continue.
*/
static int verify_cb_cert(X509_STORE_CTX *ctx, X509 *x, int depth, int err)
{
- ctx->error_depth = depth;
+ if (depth < 0)
+ depth = ctx->error_depth;
+ else
+ ctx->error_depth = depth;
ctx->current_cert = (x != NULL) ? x : sk_X509_value(ctx->chain, depth);
if (err != X509_V_OK)
ctx->error = err;
return ctx->verify_cb(0, ctx);
}
+#define CB_FAIL_IF(cond, ctx, cert, depth, err) \
+ if ((cond) && verify_cb_cert(ctx, cert, depth, err) == 0) \
+ return 0
+
/*-
* Inform the verify callback of an error, CRL-specific variant. Here, the
* error depth and certificate are already set, we just specify the error
@@ -191,73 +195,79 @@ static int check_auth_level(X509_STORE_CTX *ctx)
* We've already checked the security of the leaf key, so here we only
* check the security of issuer keys.
*/
- if (i > 0 && !check_key_level(ctx, cert) &&
- verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_KEY_TOO_SMALL) == 0)
- return 0;
+ CB_FAIL_IF(i > 0 && !check_key_level(ctx, cert),
+ ctx, cert, i, X509_V_ERR_CA_KEY_TOO_SMALL);
/*
* We also check the signature algorithm security of all certificates
* except those of the trust anchor at index num-1.
*/
- if (i < num - 1 && !check_sig_level(ctx, cert) &&
- verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_MD_TOO_WEAK) == 0)
- return 0;
+ CB_FAIL_IF(i < num - 1 && !check_sig_level(ctx, cert),
+ ctx, cert, i, X509_V_ERR_CA_MD_TOO_WEAK);
}
return 1;
}
+/* Returns -1 on internal error */
static int verify_chain(X509_STORE_CTX *ctx)
{
int err;
int ok;
- /*
- * Before either returning with an error, or continuing with CRL checks,
- * instantiate chain public key parameters.
- */
- if ((ok = build_chain(ctx)) == 0 ||
- (ok = check_chain_extensions(ctx)) == 0 ||
- (ok = check_auth_level(ctx)) == 0 ||
- (ok = check_id(ctx)) == 0 || 1)
- X509_get_pubkey_parameters(NULL, ctx->chain);
- if (ok == 0 || (ok = ctx->check_revocation(ctx)) == 0)
+ if ((ok = build_chain(ctx)) <= 0
+ || (ok = check_extensions(ctx)) <= 0
+ || (ok = check_auth_level(ctx)) <= 0
+ || (ok = check_id(ctx)) <= 0
+ || (ok = X509_get_pubkey_parameters(NULL, ctx->chain) ? 1 : -1) <= 0
+ || (ok = ctx->check_revocation(ctx)) <= 0)
return ok;
err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
ctx->param->flags);
- if (err != X509_V_OK) {
- if ((ok = verify_cb_cert(ctx, NULL, ctx->error_depth, err)) == 0)
- return ok;
- }
+ CB_FAIL_IF(err != X509_V_OK, ctx, NULL, ctx->error_depth, err);
/* Verify chain signatures and expiration times */
- ok = (ctx->verify != NULL) ? ctx->verify(ctx) : internal_verify(ctx);
- if (!ok)
+ ok = ctx->verify != NULL ? ctx->verify(ctx) : internal_verify(ctx);
+ if (ok <= 0)
return ok;
- if ((ok = check_name_constraints(ctx)) == 0)
+ if ((ok = check_name_constraints(ctx)) <= 0)
return ok;
#ifndef OPENSSL_NO_RFC3779
/* RFC 3779 path validation, now that CRL check has been done */
- if ((ok = X509v3_asid_validate_path(ctx)) == 0)
+ if ((ok = X509v3_asid_validate_path(ctx)) <= 0)
return ok;
- if ((ok = X509v3_addr_validate_path(ctx)) == 0)
+ if ((ok = X509v3_addr_validate_path(ctx)) <= 0)
return ok;
#endif
/* If we get this far evaluate policies */
- if (ctx->param->flags & X509_V_FLAG_POLICY_CHECK)
+ if ((ctx->param->flags & X509_V_FLAG_POLICY_CHECK) != 0)
ok = ctx->check_policy(ctx);
return ok;
}
+int X509_STORE_CTX_verify(X509_STORE_CTX *ctx)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return -1;
+ }
+ if (ctx->cert == NULL && sk_X509_num(ctx->untrusted) >= 1)
+ ctx->cert = sk_X509_value(ctx->untrusted, 0);
+ return X509_verify_cert(ctx);
+}
+
int X509_verify_cert(X509_STORE_CTX *ctx)
{
- SSL_DANE *dane = ctx->dane;
int ret;
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return -1;
+ }
if (ctx->cert == NULL) {
- X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
+ ERR_raise(ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
@@ -267,40 +277,22 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* This X509_STORE_CTX has already been used to verify a cert. We
* cannot do another one.
*/
- X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ ERR_raise(ERR_LIB_X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
- if (!X509_up_ref(ctx->cert)) {
- X509err(X509_F_X509_VERIFY_CERT, ERR_R_INTERNAL_ERROR);
- ctx->error = X509_V_ERR_UNSPECIFIED;
- return -1;
- }
-
- /*
- * first we make sure the chain we are going to build is present and that
- * the first entry is in place
- */
- if ((ctx->chain = sk_X509_new_null()) == NULL
- || !sk_X509_push(ctx->chain, ctx->cert)) {
- X509_free(ctx->cert);
- X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+ if (!ossl_x509_add_cert_new(&ctx->chain, ctx->cert, X509_ADD_FLAG_UP_REF)) {
ctx->error = X509_V_ERR_OUT_OF_MEM;
return -1;
}
-
ctx->num_untrusted = 1;
/* If the peer's public key is too weak, we can stop early. */
- if (!check_key_level(ctx, ctx->cert) &&
- !verify_cb_cert(ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL))
- return 0;
+ CB_FAIL_IF(!check_key_level(ctx, ctx->cert),
+ ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL);
- if (DANETLS_ENABLED(dane))
- ret = dane_verify(ctx);
- else
- ret = verify_chain(ctx);
+ ret = DANETLS_ENABLED(ctx->dane) ? dane_verify(ctx) : verify_chain(ctx);
/*
* Safety-net. If we are returning an error, we must also set ctx->error,
@@ -323,10 +315,10 @@ static int sk_X509_contains(STACK_OF(X509) *sk, X509 *cert)
}
/*
- * Find in given STACK_OF(X509) sk an issuer cert of given cert x.
- * The issuer must not yet be in ctx->chain, where the exceptional case
- * that x is self-issued and ctx->chain has just one element is allowed.
- * Prefer the first one that is not expired, else take the last expired one.
+ * Find in given STACK_OF(X509) |sk| an issuer cert (if any) of given cert |x|.
+ * The issuer must not yet be in |ctx->chain|, yet allowing the exception that
+ * |x| is self-issued and |ctx->chain| has just one element.
+ * Prefer the first non-expired one, else take the most recently expired one.
*/
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
{
@@ -338,56 +330,60 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
if (ctx->check_issued(ctx, x, issuer)
&& (((x->ex_flags & EXFLAG_SI) != 0 && sk_X509_num(ctx->chain) == 1)
|| !sk_X509_contains(ctx->chain, issuer))) {
- rv = issuer;
- if (x509_check_cert_time(ctx, rv, -1))
- break;
+ if (ossl_x509_check_cert_time(ctx, issuer, -1))
+ return issuer;
+ if (rv == NULL || ASN1_TIME_compare(X509_get0_notAfter(issuer),
+ X509_get0_notAfter(rv)) > 0)
+ rv = issuer;
}
}
return rv;
}
/* Check that the given certificate 'x' is issued by the certificate 'issuer' */
-static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
+static int check_issued(ossl_unused X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
{
- return x509_likely_issued(issuer, x) == X509_V_OK;
+ int err = ossl_x509_likely_issued(issuer, x);
+
+ if (err == X509_V_OK)
+ return 1;
+ /*
+ * SUBJECT_ISSUER_MISMATCH just means 'x' is clearly not issued by 'issuer'.
+ * Every other error code likely indicates a real error.
+ */
+ return 0;
}
-/* Alternative lookup method: look from a STACK stored in other_ctx */
+/*-
+ * Alternative get_issuer method: look up from a STACK_OF(X509) in other_ctx.
+ * Returns -1 on internal error.
+ */
static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
{
*issuer = find_issuer(ctx, ctx->other_ctx, x);
-
- if (*issuer == NULL || !X509_up_ref(*issuer))
- goto err;
-
- return 1;
-
- err:
- *issuer = NULL;
+ if (*issuer != NULL)
+ return X509_up_ref(*issuer) ? 1 : -1;
return 0;
}
-static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
+/*-
+ * Alternative lookup method: look from a STACK stored in other_ctx.
+ * Returns NULL on internal error (such as out of memory).
+ */
+static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx,
+ const X509_NAME *nm)
{
- STACK_OF(X509) *sk = NULL;
+ STACK_OF(X509) *sk = sk_X509_new_null();
X509 *x;
int i;
+ if (sk == NULL)
+ return NULL;
for (i = 0; i < sk_X509_num(ctx->other_ctx); i++) {
x = sk_X509_value(ctx->other_ctx, i);
if (X509_NAME_cmp(nm, X509_get_subject_name(x)) == 0) {
- if (!X509_up_ref(x)) {
+ if (!X509_add_cert(sk, x, X509_ADD_FLAG_UP_REF)) {
sk_X509_pop_free(sk, X509_free);
- X509err(X509_F_LOOKUP_CERTS_SK, ERR_R_INTERNAL_ERROR);
- ctx->error = X509_V_ERR_UNSPECIFIED;
- return NULL;
- }
- if (sk == NULL)
- sk = sk_X509_new_null();
- if (sk == NULL || !sk_X509_push(sk, x)) {
- X509_free(x);
- sk_X509_pop_free(sk, X509_free);
- X509err(X509_F_LOOKUP_CERTS_SK, ERR_R_MALLOC_FAILURE);
ctx->error = X509_V_ERR_OUT_OF_MEM;
return NULL;
}
@@ -399,6 +395,7 @@ static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
/*
* Check EE or CA certificate purpose. For trusted certificates explicit local
* auxiliary trust can be used to override EKU-restrictions.
+ * Sadly, returns 0 also on internal error.
*/
static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth,
int must_be_ca)
@@ -448,18 +445,15 @@ static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth,
}
/*
- * Check a certificate chains extensions for consistency with the supplied
- * purpose
+ * Check extensions of a cert chain for consistency with the supplied purpose.
+ * Sadly, returns 0 also on internal error.
*/
-
-static int check_chain_extensions(X509_STORE_CTX *ctx)
+static int check_extensions(X509_STORE_CTX *ctx)
{
int i, must_be_ca, plen = 0;
X509 *x;
- int proxy_path_length = 0;
- int purpose;
- int allow_proxy_certs;
- int num = sk_X509_num(ctx->chain);
+ int ret, proxy_path_length = 0;
+ int purpose, allow_proxy_certs, num = sk_X509_num(ctx->chain);
/*-
* must_be_ca can have 1 of 3 values:
@@ -473,87 +467,127 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
must_be_ca = -1;
/* CRL path validation */
- if (ctx->parent) {
+ if (ctx->parent != NULL) {
allow_proxy_certs = 0;
purpose = X509_PURPOSE_CRL_SIGN;
} else {
allow_proxy_certs =
- ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS);
+ (ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS) != 0;
purpose = ctx->param->purpose;
}
for (i = 0; i < num; i++) {
- int ret;
x = sk_X509_value(ctx->chain, i);
- if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
- && (x->ex_flags & EXFLAG_CRITICAL)) {
- if (!verify_cb_cert(ctx, x, i,
- X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION))
- return 0;
- }
- if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) {
- if (!verify_cb_cert(ctx, x, i,
- X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED))
- return 0;
- }
+ CB_FAIL_IF((ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) == 0
+ && (x->ex_flags & EXFLAG_CRITICAL) != 0,
+ ctx, x, i, X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
+ CB_FAIL_IF(!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY) != 0,
+ ctx, x, i, X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
ret = X509_check_ca(x);
switch (must_be_ca) {
case -1:
- if ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
- && (ret != 1) && (ret != 0)) {
- ret = 0;
- ctx->error = X509_V_ERR_INVALID_CA;
- } else
- ret = 1;
+ CB_FAIL_IF((ctx->param->flags & X509_V_FLAG_X509_STRICT) != 0
+ && ret != 1 && ret != 0,
+ ctx, x, i, X509_V_ERR_INVALID_CA);
break;
case 0:
- if (ret != 0) {
- ret = 0;
- ctx->error = X509_V_ERR_INVALID_NON_CA;
- } else
- ret = 1;
+ CB_FAIL_IF(ret != 0, ctx, x, i, X509_V_ERR_INVALID_NON_CA);
break;
default:
/* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */
- if ((ret == 0)
- || ((i + 1 < num || ctx->param->flags & X509_V_FLAG_X509_STRICT)
- && (ret != 1))) {
- ret = 0;
- ctx->error = X509_V_ERR_INVALID_CA;
- } else
- ret = 1;
+ CB_FAIL_IF(ret == 0
+ || ((i + 1 < num
+ || (ctx->param->flags & X509_V_FLAG_X509_STRICT) != 0)
+ && ret != 1), ctx, x, i, X509_V_ERR_INVALID_CA);
break;
}
- if (ret > 0
- && (ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) {
+ if (num > 1) {
/* Check for presence of explicit elliptic curve parameters */
ret = check_curve(x);
- if (ret < 0) {
- ctx->error = X509_V_ERR_UNSPECIFIED;
- ret = 0;
- } else if (ret == 0) {
- ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS;
- }
+ CB_FAIL_IF(ret < 0, ctx, x, i, X509_V_ERR_UNSPECIFIED);
+ CB_FAIL_IF(ret == 0, ctx, x, i, X509_V_ERR_EC_KEY_EXPLICIT_PARAMS);
}
- if (ret > 0
- && (x->ex_flags & EXFLAG_CA) == 0
- && x->ex_pathlen != -1
- && (ctx->param->flags & X509_V_FLAG_X509_STRICT)) {
- ctx->error = X509_V_ERR_INVALID_EXTENSION;
- ret = 0;
+ /*
+ * Do the following set of checks only if strict checking is requested
+ * and not for self-issued (including self-signed) EE (non-CA) certs
+ * because RFC 5280 does not apply to them according RFC 6818 section 2.
+ */
+ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) != 0
+ && num > 1) { /*
+ * this should imply
+ * !(i == 0 && (x->ex_flags & EXFLAG_CA) == 0
+ * && (x->ex_flags & EXFLAG_SI) != 0)
+ */
+ /* Check Basic Constraints according to RFC 5280 section 4.2.1.9 */
+ if (x->ex_pathlen != -1) {
+ CB_FAIL_IF((x->ex_flags & EXFLAG_CA) == 0,
+ ctx, x, i, X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA);
+ CB_FAIL_IF((x->ex_kusage & KU_KEY_CERT_SIGN) == 0, ctx,
+ x, i, X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN);
+ }
+ CB_FAIL_IF((x->ex_flags & EXFLAG_CA) != 0
+ && (x->ex_flags & EXFLAG_BCONS) != 0
+ && (x->ex_flags & EXFLAG_BCONS_CRITICAL) == 0,
+ ctx, x, i, X509_V_ERR_CA_BCONS_NOT_CRITICAL);
+ /* Check Key Usage according to RFC 5280 section 4.2.1.3 */
+ if ((x->ex_flags & EXFLAG_CA) != 0) {
+ CB_FAIL_IF((x->ex_flags & EXFLAG_KUSAGE) == 0,
+ ctx, x, i, X509_V_ERR_CA_CERT_MISSING_KEY_USAGE);
+ } else {
+ CB_FAIL_IF((x->ex_kusage & KU_KEY_CERT_SIGN) != 0, ctx, x, i,
+ X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA);
+ }
+ /* Check issuer is non-empty acc. to RFC 5280 section 4.1.2.4 */
+ CB_FAIL_IF(X509_NAME_entry_count(X509_get_issuer_name(x)) == 0,
+ ctx, x, i, X509_V_ERR_ISSUER_NAME_EMPTY);
+ /* Check subject is non-empty acc. to RFC 5280 section 4.1.2.6 */
+ CB_FAIL_IF(((x->ex_flags & EXFLAG_CA) != 0
+ || (x->ex_kusage & KU_CRL_SIGN) != 0
+ || x->altname == NULL)
+ && X509_NAME_entry_count(X509_get_subject_name(x)) == 0,
+ ctx, x, i, X509_V_ERR_SUBJECT_NAME_EMPTY);
+ CB_FAIL_IF(X509_NAME_entry_count(X509_get_subject_name(x)) == 0
+ && x->altname != NULL
+ && (x->ex_flags & EXFLAG_SAN_CRITICAL) == 0,
+ ctx, x, i, X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL);
+ /* Check SAN is non-empty according to RFC 5280 section 4.2.1.6 */
+ CB_FAIL_IF(x->altname != NULL
+ && sk_GENERAL_NAME_num(x->altname) <= 0,
+ ctx, x, i, X509_V_ERR_EMPTY_SUBJECT_ALT_NAME);
+ /* Check sig alg consistency acc. to RFC 5280 section 4.1.1.2 */
+ CB_FAIL_IF(X509_ALGOR_cmp(&x->sig_alg, &x->cert_info.signature) != 0,
+ ctx, x, i, X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY);
+ CB_FAIL_IF(x->akid != NULL
+ && (x->ex_flags & EXFLAG_AKID_CRITICAL) != 0,
+ ctx, x, i, X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL);
+ CB_FAIL_IF(x->skid != NULL
+ && (x->ex_flags & EXFLAG_SKID_CRITICAL) != 0,
+ ctx, x, i, X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL);
+ if (X509_get_version(x) >= X509_VERSION_3) {
+ /* Check AKID presence acc. to RFC 5280 section 4.2.1.1 */
+ CB_FAIL_IF(i + 1 < num /*
+ * this means not last cert in chain,
+ * taken as "generated by conforming CAs"
+ */
+ && (x->akid == NULL || x->akid->keyid == NULL), ctx,
+ x, i, X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER);
+ /* Check SKID presence acc. to RFC 5280 section 4.2.1.2 */
+ CB_FAIL_IF((x->ex_flags & EXFLAG_CA) != 0 && x->skid == NULL,
+ ctx, x, i, X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER);
+ } else {
+ CB_FAIL_IF(sk_X509_EXTENSION_num(X509_get0_extensions(x)) > 0,
+ ctx, x, i, X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3);
+ }
}
- if (ret == 0 && !verify_cb_cert(ctx, x, i, X509_V_OK))
- return 0;
+
/* check_purpose() makes the callback as needed */
if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca))
return 0;
- /* Check pathlen */
- if ((i > 1) && (x->ex_pathlen != -1)
- && (plen > (x->ex_pathlen + proxy_path_length))) {
- if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED))
- return 0;
- }
- /* Increment path length if not a self issued intermediate CA */
+ /* Check path length */
+ CB_FAIL_IF(i > 1 && x->ex_pathlen != -1
+ && plen > x->ex_pathlen + proxy_path_length,
+ ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED);
+ /* Increment path length if not a self-issued intermediate CA */
if (i > 0 && (x->ex_flags & EXFLAG_SI) == 0)
plen++;
/*
@@ -574,17 +608,15 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
* increment proxy_path_length.
*/
if (x->ex_pcpathlen != -1) {
- if (proxy_path_length > x->ex_pcpathlen) {
- if (!verify_cb_cert(ctx, x, i,
- X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED))
- return 0;
- }
+ CB_FAIL_IF(proxy_path_length > x->ex_pcpathlen,
+ ctx, x, i, X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
proxy_path_length = x->ex_pcpathlen;
}
proxy_path_length++;
must_be_ca = 0;
- } else
+ } else {
must_be_ca = 1;
+ }
}
return 1;
}
@@ -610,6 +642,7 @@ static int has_san_id(X509 *x, int gtype)
return ret;
}
+/* Returns -1 on internal error */
static int check_name_constraints(X509_STORE_CTX *ctx)
{
int i;
@@ -619,8 +652,8 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
X509 *x = sk_X509_value(ctx->chain, i);
int j;
- /* Ignore self issued certs unless last in chain */
- if (i && (x->ex_flags & EXFLAG_SI))
+ /* Ignore self-issued certs unless last in chain */
+ if (i != 0 && (x->ex_flags & EXFLAG_SI) != 0)
continue;
/*
@@ -629,16 +662,16 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
* added.
* (RFC 3820: 3.4, 4.1.3 (a)(4))
*/
- if (x->ex_flags & EXFLAG_PROXY) {
+ if ((x->ex_flags & EXFLAG_PROXY) != 0) {
X509_NAME *tmpsubject = X509_get_subject_name(x);
X509_NAME *tmpissuer = X509_get_issuer_name(x);
X509_NAME_ENTRY *tmpentry = NULL;
- int last_object_nid = 0;
+ int last_nid = 0;
int err = X509_V_OK;
- int last_object_loc = X509_NAME_entry_count(tmpsubject) - 1;
+ int last_loc = X509_NAME_entry_count(tmpsubject) - 1;
/* Check that there are at least two RDNs */
- if (last_object_loc < 1) {
+ if (last_loc < 1) {
err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
goto proxy_name_done;
}
@@ -655,12 +688,11 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
/*
* Check that the last subject component isn't part of a
- * multivalued RDN
+ * multi-valued RDN
*/
- if (X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject,
- last_object_loc))
+ if (X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject, last_loc))
== X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject,
- last_object_loc - 1))) {
+ last_loc - 1))) {
err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
goto proxy_name_done;
}
@@ -671,17 +703,15 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
*/
tmpsubject = X509_NAME_dup(tmpsubject);
if (tmpsubject == NULL) {
- X509err(X509_F_CHECK_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
ctx->error = X509_V_ERR_OUT_OF_MEM;
- return 0;
+ return -1;
}
- tmpentry =
- X509_NAME_delete_entry(tmpsubject, last_object_loc);
- last_object_nid =
- OBJ_obj2nid(X509_NAME_ENTRY_get_object(tmpentry));
+ tmpentry = X509_NAME_delete_entry(tmpsubject, last_loc);
+ last_nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(tmpentry));
- if (last_object_nid != NID_commonName
+ if (last_nid != NID_commonName
|| X509_NAME_cmp(tmpsubject, tmpissuer) != 0) {
err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
}
@@ -689,10 +719,8 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
X509_NAME_ENTRY_free(tmpentry);
X509_NAME_free(tmpsubject);
- proxy_name_done:
- if (err != X509_V_OK
- && !verify_cb_cert(ctx, x, i, err))
- return 0;
+ proxy_name_done:
+ CB_FAIL_IF(err != X509_V_OK, ctx, x, i, err);
}
/*
@@ -706,6 +734,7 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
if (nc) {
int rv = NAME_CONSTRAINTS_check(x, nc);
+ int ret = 1;
/* If EE certificate check commonName too */
if (rv == X509_V_OK && i == 0
@@ -713,17 +742,18 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
& X509_CHECK_FLAG_NEVER_CHECK_SUBJECT) == 0
&& ((ctx->param->hostflags
& X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) != 0
- || !has_san_id(x, GEN_DNS)))
+ || (ret = has_san_id(x, GEN_DNS)) == 0))
rv = NAME_CONSTRAINTS_check_CN(x, nc);
+ if (ret < 0)
+ return ret;
switch (rv) {
case X509_V_OK:
break;
case X509_V_ERR_OUT_OF_MEM:
- return 0;
+ return -1;
default:
- if (!verify_cb_cert(ctx, x, i, rv))
- return 0;
+ CB_FAIL_IF(1, ctx, x, i, rv);
break;
}
}
@@ -759,24 +789,27 @@ static int check_id(X509_STORE_CTX *ctx)
{
X509_VERIFY_PARAM *vpm = ctx->param;
X509 *x = ctx->cert;
- if (vpm->hosts && check_hosts(x, vpm) <= 0) {
+
+ if (vpm->hosts != NULL && check_hosts(x, vpm) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
return 0;
}
- if (vpm->email && X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) {
+ if (vpm->email != NULL
+ && X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
return 0;
}
- if (vpm->ip && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) {
+ if (vpm->ip != NULL && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
return 0;
}
return 1;
}
+/* Returns -1 on internal error */
static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
{
- int i;
+ int i, res;
X509 *x = NULL;
X509 *mx;
SSL_DANE *dane = ctx->dane;
@@ -788,11 +821,9 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
* match, we're done, otherwise we'll merely record the match depth.
*/
if (DANETLS_HAS_TA(dane) && num_untrusted > 0 && num_untrusted < num) {
- switch (trust = check_dane_issuer(ctx, num_untrusted)) {
- case X509_TRUST_TRUSTED:
- case X509_TRUST_REJECTED:
+ trust = check_dane_issuer(ctx, num_untrusted);
+ if (trust != X509_TRUST_UNTRUSTED)
return trust;
- }
}
/*
@@ -804,7 +835,7 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
for (i = num_untrusted; i < num; i++) {
x = sk_X509_value(ctx->chain, i);
trust = X509_check_trust(x, ctx->param->trust, 0);
- /* If explicitly trusted return trusted */
+ /* If explicitly trusted (so not neutral nor rejected) return trusted */
if (trust == X509_TRUST_TRUSTED)
goto trusted;
if (trust == X509_TRUST_REJECTED)
@@ -816,20 +847,23 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
* the chain is PKIX trusted.
*/
if (num_untrusted < num) {
- if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN)
+ if ((ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) != 0)
goto trusted;
return X509_TRUST_UNTRUSTED;
}
- if (num_untrusted == num && ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
+ if (num_untrusted == num
+ && (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) != 0) {
/*
* Last-resort call with no new trusted certificates, check the leaf
* for a direct trust store match.
*/
i = 0;
x = sk_X509_value(ctx->chain, i);
- mx = lookup_cert_match(ctx, x);
- if (!mx)
+ res = lookup_cert_match(&mx, ctx, x);
+ if (res < 0)
+ return res;
+ if (mx == NULL)
return X509_TRUST_UNTRUSTED;
/*
@@ -843,7 +877,7 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
}
/* Replace leaf with trusted match */
- (void) sk_X509_set(ctx->chain, 0, mx);
+ (void)sk_X509_set(ctx->chain, 0, mx);
X509_free(x);
ctx->num_untrusted = 0;
goto trusted;
@@ -856,9 +890,8 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
return X509_TRUST_UNTRUSTED;
rejected:
- if (!verify_cb_cert(ctx, x, i, X509_V_ERR_CERT_REJECTED))
- return X509_TRUST_REJECTED;
- return X509_TRUST_UNTRUSTED;
+ return verify_cb_cert(ctx, x, i, X509_V_ERR_CERT_REJECTED) == 0
+ ? X509_TRUST_REJECTED : X509_TRUST_UNTRUSTED;
trusted:
if (!DANETLS_ENABLED(dane))
@@ -871,14 +904,16 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
return X509_TRUST_UNTRUSTED;
}
+/* Sadly, returns 0 also on internal error. */
static int check_revocation(X509_STORE_CTX *ctx)
{
int i = 0, last = 0, ok = 0;
- if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK))
+
+ if ((ctx->param->flags & X509_V_FLAG_CRL_CHECK) == 0)
return 1;
- if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL)
+ if ((ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) != 0) {
last = sk_X509_num(ctx->chain) - 1;
- else {
+ } else {
/* If checking CRL paths this isn't the EE certificate */
if (ctx->parent)
return 1;
@@ -893,6 +928,7 @@ static int check_revocation(X509_STORE_CTX *ctx)
return 1;
}
+/* Sadly, returns 0 also on internal error. */
static int check_cert(X509_STORE_CTX *ctx)
{
X509_CRL *crl = NULL, *dcrl = NULL;
@@ -905,20 +941,18 @@ static int check_cert(X509_STORE_CTX *ctx)
ctx->current_crl_score = 0;
ctx->current_reasons = 0;
- if (x->ex_flags & EXFLAG_PROXY)
+ if ((x->ex_flags & EXFLAG_PROXY) != 0)
return 1;
while (ctx->current_reasons != CRLDP_ALL_REASONS) {
unsigned int last_reasons = ctx->current_reasons;
/* Try to retrieve relevant CRL */
- if (ctx->get_crl)
+ if (ctx->get_crl != NULL)
ok = ctx->get_crl(ctx, &crl, x);
else
ok = get_crl_delta(ctx, &crl, &dcrl, x);
- /*
- * If error looking up CRL, nothing we can do except notify callback
- */
+ /* If error looking up CRL, nothing we can do except notify callback */
if (!ok) {
ok = verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL);
goto done;
@@ -928,15 +962,16 @@ static int check_cert(X509_STORE_CTX *ctx)
if (!ok)
goto done;
- if (dcrl) {
+ if (dcrl != NULL) {
ok = ctx->check_crl(ctx, dcrl);
if (!ok)
goto done;
ok = ctx->cert_crl(ctx, dcrl, x);
if (!ok)
goto done;
- } else
+ } else {
ok = 1;
+ }
/* Don't look in full CRL if delta reason is removefromCRL */
if (ok != 2) {
@@ -967,15 +1002,14 @@ static int check_cert(X509_STORE_CTX *ctx)
}
/* Check CRL times against values in X509_STORE_CTX */
-
static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
{
time_t *ptime;
int i;
- if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
+ if ((ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) != 0)
ptime = &ctx->param->check_time;
- else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME)
+ else if ((ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) != 0)
return 1;
else
ptime = NULL;
@@ -1006,11 +1040,9 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
if (!verify_cb_crl(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD))
return 0;
}
- /* Ignore expiry of base CRL is delta is valid */
- if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) {
- if (!notify)
- return 0;
- if (!verify_cb_crl(ctx, X509_V_ERR_CRL_HAS_EXPIRED))
+ /* Ignore expiration of base CRL is delta is valid */
+ if (i < 0 && (ctx->current_crl_score & CRL_SCORE_TIME_DELTA) == 0) {
+ if (!notify || !verify_cb_crl(ctx, X509_V_ERR_CRL_HAS_EXPIRED))
return 0;
}
}
@@ -1040,6 +1072,7 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
/* If current CRL is equivalent use it if it is newer */
if (crl_score == best_score && best_crl != NULL) {
int day, sec;
+
if (ASN1_TIME_diff(&day, &sec, X509_CRL_get0_lastUpdate(best_crl),
X509_CRL_get0_lastUpdate(crl)) == 0)
continue;
@@ -1056,7 +1089,7 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
best_reasons = reasons;
}
- if (best_crl) {
+ if (best_crl != NULL) {
X509_CRL_free(*pcrl);
*pcrl = best_crl;
*pissuer = best_crl_issuer;
@@ -1078,54 +1111,46 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
* Compare two CRL extensions for delta checking purposes. They should be
* both present or both absent. If both present all fields must be identical.
*/
-
static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid)
{
- ASN1_OCTET_STRING *exta, *extb;
- int i;
- i = X509_CRL_get_ext_by_NID(a, nid, -1);
+ ASN1_OCTET_STRING *exta = NULL, *extb = NULL;
+ int i = X509_CRL_get_ext_by_NID(a, nid, -1);
+
if (i >= 0) {
/* Can't have multiple occurrences */
if (X509_CRL_get_ext_by_NID(a, nid, i) != -1)
return 0;
exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i));
- } else
- exta = NULL;
+ }
i = X509_CRL_get_ext_by_NID(b, nid, -1);
-
if (i >= 0) {
-
if (X509_CRL_get_ext_by_NID(b, nid, i) != -1)
return 0;
extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i));
- } else
- extb = NULL;
+ }
- if (!exta && !extb)
+ if (exta == NULL && extb == NULL)
return 1;
- if (!exta || !extb)
+ if (exta == NULL || extb == NULL)
return 0;
- if (ASN1_OCTET_STRING_cmp(exta, extb))
- return 0;
-
- return 1;
+ return ASN1_OCTET_STRING_cmp(exta, extb) == 0;
}
/* See if a base and delta are compatible */
-
static int check_delta_base(X509_CRL *delta, X509_CRL *base)
{
/* Delta CRL must be a delta */
- if (!delta->base_crl_number)
+ if (delta->base_crl_number == NULL)
return 0;
/* Base must have a CRL number */
- if (!base->crl_number)
+ if (base->crl_number == NULL)
return 0;
/* Issuer names must match */
- if (X509_NAME_cmp(X509_CRL_get_issuer(base), X509_CRL_get_issuer(delta)))
+ if (X509_NAME_cmp(X509_CRL_get_issuer(base),
+ X509_CRL_get_issuer(delta)) != 0)
return 0;
/* AKID and IDP must match */
if (!crl_extension_match(delta, base, NID_authority_key_identifier))
@@ -1136,24 +1161,22 @@ static int check_delta_base(X509_CRL *delta, X509_CRL *base)
if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0)
return 0;
/* Delta CRL number must exceed full CRL number */
- if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0)
- return 1;
- return 0;
+ return ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0;
}
/*
* For a given base CRL find a delta... maybe extend to delta scoring or
* retrieve a chain of deltas...
*/
-
static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore,
X509_CRL *base, STACK_OF(X509_CRL) *crls)
{
X509_CRL *delta;
int i;
- if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS))
+
+ if ((ctx->param->flags & X509_V_FLAG_USE_DELTAS) == 0)
return;
- if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST))
+ if (((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST) == 0)
return;
for (i = 0; i < sk_X509_CRL_num(crls); i++) {
delta = sk_X509_CRL_value(crls, i);
@@ -1175,42 +1198,41 @@ static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore,
* also used to determine if the CRL is suitable: if no new reasons the CRL
* is rejected, otherwise reasons is updated.
*/
-
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
unsigned int *preasons, X509_CRL *crl, X509 *x)
{
-
int crl_score = 0;
unsigned int tmp_reasons = *preasons, crl_reasons;
/* First see if we can reject CRL straight away */
/* Invalid IDP cannot be processed */
- if (crl->idp_flags & IDP_INVALID)
+ if ((crl->idp_flags & IDP_INVALID) != 0)
return 0;
/* Reason codes or indirect CRLs need extended CRL support */
- if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) {
+ if ((ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT) == 0) {
if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS))
return 0;
- } else if (crl->idp_flags & IDP_REASONS) {
+ } else if ((crl->idp_flags & IDP_REASONS) != 0) {
/* If no new reasons reject */
- if (!(crl->idp_reasons & ~tmp_reasons))
+ if ((crl->idp_reasons & ~tmp_reasons) == 0)
return 0;
}
/* Don't process deltas at this stage */
- else if (crl->base_crl_number)
+ else if (crl->base_crl_number != NULL)
return 0;
/* If issuer name doesn't match certificate need indirect CRL */
- if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl))) {
- if (!(crl->idp_flags & IDP_INDIRECT))
+ if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl)) != 0) {
+ if ((crl->idp_flags & IDP_INDIRECT) == 0)
return 0;
- } else
+ } else {
crl_score |= CRL_SCORE_ISSUER_NAME;
+ }
- if (!(crl->flags & EXFLAG_CRITICAL))
+ if ((crl->flags & EXFLAG_CRITICAL) == 0)
crl_score |= CRL_SCORE_NOCRITICAL;
- /* Check expiry */
+ /* Check expiration */
if (check_crl_time(ctx, crl, 0))
crl_score |= CRL_SCORE_TIME;
@@ -1218,15 +1240,13 @@ static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
crl_akid_check(ctx, crl, pissuer, &crl_score);
/* If we can't locate certificate issuer at this point forget it */
-
- if (!(crl_score & CRL_SCORE_AKID))
+ if ((crl_score & CRL_SCORE_AKID) == 0)
return 0;
/* Check cert for matching CRL distribution points */
-
if (crl_crldp_check(x, crl, crl_score, &crl_reasons)) {
/* If no new reasons reject */
- if (!(crl_reasons & ~tmp_reasons))
+ if ((crl_reasons & ~tmp_reasons) == 0)
return 0;
tmp_reasons |= crl_reasons;
crl_score |= CRL_SCORE_SCOPE;
@@ -1242,7 +1262,7 @@ static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
X509 **pissuer, int *pcrl_score)
{
X509 *crl_issuer = NULL;
- X509_NAME *cnm = X509_CRL_get_issuer(crl);
+ const X509_NAME *cnm = X509_CRL_get_issuer(crl);
int cidx = ctx->error_depth;
int i;
@@ -1271,8 +1291,7 @@ static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
}
/* Anything else needs extended CRL support */
-
- if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT))
+ if ((ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT) == 0)
return;
/*
@@ -1281,7 +1300,7 @@ static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
*/
for (i = 0; i < sk_X509_num(ctx->untrusted); i++) {
crl_issuer = sk_X509_value(ctx->untrusted, i);
- if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm))
+ if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm) != 0)
continue;
if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) {
*pissuer = crl_issuer;
@@ -1297,16 +1316,15 @@ static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
* parent. This could be optimised somewhat since a lot of path checking will
* be duplicated by the parent, but this will rarely be used in practice.
*/
-
static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
{
- X509_STORE_CTX crl_ctx;
+ X509_STORE_CTX crl_ctx = {0};
int ret;
/* Don't allow recursive CRL path validation */
- if (ctx->parent)
+ if (ctx->parent != NULL)
return 0;
- if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted))
+ if (!X509_STORE_CTX_init(&crl_ctx, ctx->store, x, ctx->untrusted))
return -1;
crl_ctx.crls = ctx->crls;
@@ -1331,22 +1349,19 @@ static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
/*
* RFC3280 says nothing about the relationship between CRL path and
* certificate path, which could lead to situations where a certificate could
- * be revoked or validated by a CA not authorised to do so. RFC5280 is more
+ * be revoked or validated by a CA not authorized to do so. RFC5280 is more
* strict and states that the two paths must end in the same trust anchor,
* though some discussions remain... until this is resolved we use the
* RFC5280 version
*/
-
static int check_crl_chain(X509_STORE_CTX *ctx,
STACK_OF(X509) *cert_path,
STACK_OF(X509) *crl_path)
{
- X509 *cert_ta, *crl_ta;
- cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1);
- crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1);
- if (!X509_cmp(cert_ta, crl_ta))
- return 1;
- return 0;
+ X509 *cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1);
+ X509 *crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1);
+
+ return X509_cmp(cert_ta, crl_ta) == 0;
}
/*-
@@ -1356,32 +1371,29 @@ static int check_crl_chain(X509_STORE_CTX *ctx,
* 3. Both are full names and compare two GENERAL_NAMES.
* 4. One is NULL: automatic match.
*/
-
static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b)
{
X509_NAME *nm = NULL;
GENERAL_NAMES *gens = NULL;
GENERAL_NAME *gena, *genb;
int i, j;
- if (!a || !b)
+
+ if (a == NULL || b == NULL)
return 1;
if (a->type == 1) {
- if (!a->dpname)
+ if (a->dpname == NULL)
return 0;
/* Case 1: two X509_NAME */
if (b->type == 1) {
- if (!b->dpname)
- return 0;
- if (!X509_NAME_cmp(a->dpname, b->dpname))
- return 1;
- else
+ if (b->dpname == NULL)
return 0;
+ return X509_NAME_cmp(a->dpname, b->dpname) == 0;
}
/* Case 2: set name and GENERAL_NAMES appropriately */
nm = a->dpname;
gens = b->name.fullname;
} else if (b->type == 1) {
- if (!b->dpname)
+ if (b->dpname == NULL)
return 0;
/* Case 2: set name and GENERAL_NAMES appropriately */
gens = a->name.fullname;
@@ -1389,12 +1401,12 @@ static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b)
}
/* Handle case 2 with one GENERAL_NAMES and one X509_NAME */
- if (nm) {
+ if (nm != NULL) {
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gena = sk_GENERAL_NAME_value(gens, i);
if (gena->type != GEN_DIRNAME)
continue;
- if (!X509_NAME_cmp(nm, gena->d.directoryName))
+ if (X509_NAME_cmp(nm, gena->d.directoryName) == 0)
return 1;
}
return 0;
@@ -1406,7 +1418,7 @@ static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b)
gena = sk_GENERAL_NAME_value(a->name.fullname, i);
for (j = 0; j < sk_GENERAL_NAME_num(b->name.fullname); j++) {
genb = sk_GENERAL_NAME_value(b->name.fullname, j);
- if (!GENERAL_NAME_cmp(gena, genb))
+ if (GENERAL_NAME_cmp(gena, genb) == 0)
return 1;
}
}
@@ -1418,56 +1430,57 @@ static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b)
static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score)
{
int i;
- X509_NAME *nm = X509_CRL_get_issuer(crl);
+ const X509_NAME *nm = X509_CRL_get_issuer(crl);
+
/* If no CRLissuer return is successful iff don't need a match */
- if (!dp->CRLissuer)
- return ! !(crl_score & CRL_SCORE_ISSUER_NAME);
+ if (dp->CRLissuer == NULL)
+ return (crl_score & CRL_SCORE_ISSUER_NAME) != 0;
for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+
if (gen->type != GEN_DIRNAME)
continue;
- if (!X509_NAME_cmp(gen->d.directoryName, nm))
+ if (X509_NAME_cmp(gen->d.directoryName, nm) == 0)
return 1;
}
return 0;
}
/* Check CRLDP and IDP */
-
static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score,
unsigned int *preasons)
{
int i;
- if (crl->idp_flags & IDP_ONLYATTR)
+
+ if ((crl->idp_flags & IDP_ONLYATTR) != 0)
return 0;
- if (x->ex_flags & EXFLAG_CA) {
- if (crl->idp_flags & IDP_ONLYUSER)
+ if ((x->ex_flags & EXFLAG_CA) != 0) {
+ if ((crl->idp_flags & IDP_ONLYUSER) != 0)
return 0;
} else {
- if (crl->idp_flags & IDP_ONLYCA)
+ if ((crl->idp_flags & IDP_ONLYCA) != 0)
return 0;
}
*preasons = crl->idp_reasons;
for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i);
+
if (crldp_check_crlissuer(dp, crl, crl_score)) {
- if (!crl->idp || idp_check_dp(dp->distpoint, crl->idp->distpoint)) {
+ if (crl->idp == NULL
+ || idp_check_dp(dp->distpoint, crl->idp->distpoint)) {
*preasons &= dp->dp_reasons;
return 1;
}
}
}
- if ((!crl->idp || !crl->idp->distpoint)
- && (crl_score & CRL_SCORE_ISSUER_NAME))
- return 1;
- return 0;
+ return (crl->idp == NULL || crl->idp->distpoint == NULL)
+ && (crl_score & CRL_SCORE_ISSUER_NAME) != 0;
}
/*
* Retrieve CRL corresponding to current certificate. If deltas enabled try
* to find a delta CRL too
*/
-
static int get_crl_delta(X509_STORE_CTX *ctx,
X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x)
{
@@ -1477,7 +1490,7 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
unsigned int reasons;
X509_CRL *crl = NULL, *dcrl = NULL;
STACK_OF(X509_CRL) *skcrl;
- X509_NAME *nm = X509_get_issuer_name(x);
+ const X509_NAME *nm = X509_get_issuer_name(x);
reasons = ctx->current_reasons;
ok = get_crl_sk(ctx, &crl, &dcrl,
@@ -1486,11 +1499,10 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
goto done;
/* Lookup CRLs from store */
-
skcrl = ctx->lookup_crls(ctx, nm);
/* If no CRLs found and a near match from get_crl_sk use that */
- if (!skcrl && crl)
+ if (skcrl == NULL && crl != NULL)
goto done;
get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl);
@@ -1499,7 +1511,7 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
done:
/* If we got any kind of CRL use it and return success */
- if (crl) {
+ if (crl != NULL) {
ctx->current_issuer = issuer;
ctx->current_crl_score = crl_score;
ctx->current_reasons = reasons;
@@ -1518,18 +1530,18 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
int cnum = ctx->error_depth;
int chnum = sk_X509_num(ctx->chain) - 1;
- /* if we have an alternative CRL issuer cert use that */
- if (ctx->current_issuer)
+ /* If we have an alternative CRL issuer cert use that */
+ if (ctx->current_issuer != NULL) {
issuer = ctx->current_issuer;
/*
* Else find CRL issuer: if not last certificate then issuer is next
* certificate in chain.
*/
- else if (cnum < chnum)
+ } else if (cnum < chnum) {
issuer = sk_X509_value(ctx->chain, cnum + 1);
- else {
+ } else {
issuer = sk_X509_value(ctx->chain, chnum);
- /* If not self signed, can't check signature */
+ /* If not self-issued, can't check signature */
if (!ctx->check_issued(ctx, issuer, issuer) &&
!verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER))
return 0;
@@ -1541,39 +1553,38 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
/*
* Skip most tests for deltas because they have already been done
*/
- if (!crl->base_crl_number) {
+ if (crl->base_crl_number == NULL) {
/* Check for cRLSign bit if keyUsage present */
- if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
- !(issuer->ex_kusage & KU_CRL_SIGN) &&
+ if ((issuer->ex_flags & EXFLAG_KUSAGE) != 0 &&
+ (issuer->ex_kusage & KU_CRL_SIGN) == 0 &&
!verify_cb_crl(ctx, X509_V_ERR_KEYUSAGE_NO_CRL_SIGN))
return 0;
- if (!(ctx->current_crl_score & CRL_SCORE_SCOPE) &&
+ if ((ctx->current_crl_score & CRL_SCORE_SCOPE) == 0 &&
!verify_cb_crl(ctx, X509_V_ERR_DIFFERENT_CRL_SCOPE))
return 0;
- if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH) &&
+ if ((ctx->current_crl_score & CRL_SCORE_SAME_PATH) == 0 &&
check_crl_path(ctx, ctx->current_issuer) <= 0 &&
!verify_cb_crl(ctx, X509_V_ERR_CRL_PATH_VALIDATION_ERROR))
return 0;
- if ((crl->idp_flags & IDP_INVALID) &&
+ if ((crl->idp_flags & IDP_INVALID) != 0 &&
!verify_cb_crl(ctx, X509_V_ERR_INVALID_EXTENSION))
return 0;
}
- if (!(ctx->current_crl_score & CRL_SCORE_TIME) &&
+ if ((ctx->current_crl_score & CRL_SCORE_TIME) == 0 &&
!check_crl_time(ctx, crl, 1))
return 0;
/* Attempt to get issuer certificate public key */
ikey = X509_get0_pubkey(issuer);
-
- if (!ikey &&
+ if (ikey == NULL &&
!verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
return 0;
- if (ikey) {
+ if (ikey != NULL) {
int rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags);
if (rv != X509_V_OK && !verify_cb_crl(ctx, rv))
@@ -1597,8 +1608,8 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
* was revoked. This has since been changed since critical extensions can
* change the meaning of CRL entries.
*/
- if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
- && (crl->flags & EXFLAG_CRITICAL) &&
+ if ((ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) == 0
+ && (crl->flags & EXFLAG_CRITICAL) != 0 &&
!verify_cb_crl(ctx, X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION))
return 0;
/*
@@ -1632,35 +1643,34 @@ static int check_policy(X509_STORE_CTX *ctx)
* was verified via a bare public key, and pop it off right after the
* X509_policy_check() call.
*/
- if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL)) {
- X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- return 0;
- }
+ if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL))
+ goto memerr;
ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain,
ctx->param->policies, ctx->param->flags);
if (ctx->bare_ta_signed)
- sk_X509_pop(ctx->chain);
+ (void)sk_X509_pop(ctx->chain);
- if (ret == X509_PCY_TREE_INTERNAL) {
- X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- return 0;
- }
+ if (ret == X509_PCY_TREE_INTERNAL)
+ goto memerr;
/* Invalid or inconsistent extensions */
if (ret == X509_PCY_TREE_INVALID) {
- int i;
+ int i, cbcalled = 0;
/* Locate certificates with bad extensions and notify callback. */
- for (i = 1; i < sk_X509_num(ctx->chain); i++) {
+ for (i = 0; i < sk_X509_num(ctx->chain); i++) {
X509 *x = sk_X509_value(ctx->chain, i);
- if (!(x->ex_flags & EXFLAG_INVALID_POLICY))
- continue;
- if (!verify_cb_cert(ctx, x, i,
- X509_V_ERR_INVALID_POLICY_EXTENSION))
- return 0;
+ if ((x->ex_flags & EXFLAG_INVALID_POLICY) != 0)
+ cbcalled = 1;
+ CB_FAIL_IF((x->ex_flags & EXFLAG_INVALID_POLICY) != 0,
+ ctx, x, i, X509_V_ERR_INVALID_POLICY_EXTENSION);
+ }
+ if (!cbcalled) {
+ /* Should not be able to get here */
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+ return 0;
}
+ /* The callback ignored the error so we return success */
return 1;
}
if (ret == X509_PCY_TREE_FAILURE) {
@@ -1669,11 +1679,11 @@ static int check_policy(X509_STORE_CTX *ctx)
return ctx->verify_cb(0, ctx);
}
if (ret != X509_PCY_TREE_VALID) {
- X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR);
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
return 0;
}
- if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
+ if ((ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) != 0) {
ctx->current_cert = NULL;
/*
* Verification errors need to be "sticky", a callback may have allowed
@@ -1686,6 +1696,11 @@ static int check_policy(X509_STORE_CTX *ctx)
}
return 1;
+
+ memerr:
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ return -1;
}
/*-
@@ -1695,14 +1710,14 @@ static int check_policy(X509_STORE_CTX *ctx)
*
* Return 1 on success, 0 otherwise.
*/
-int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
+int ossl_x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
{
time_t *ptime;
int i;
- if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
+ if ((ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) != 0)
ptime = &ctx->param->check_time;
- else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME)
+ else if ((ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) != 0)
return 1;
else
ptime = NULL;
@@ -1710,79 +1725,73 @@ int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
i = X509_cmp_time(X509_get0_notBefore(x), ptime);
if (i >= 0 && depth < 0)
return 0;
- if (i == 0 && !verify_cb_cert(ctx, x, depth,
- X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD))
- return 0;
- if (i > 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_NOT_YET_VALID))
- return 0;
+ CB_FAIL_IF(i == 0, ctx, x, depth, X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
+ CB_FAIL_IF(i > 0, ctx, x, depth, X509_V_ERR_CERT_NOT_YET_VALID);
i = X509_cmp_time(X509_get0_notAfter(x), ptime);
if (i <= 0 && depth < 0)
return 0;
- if (i == 0 && !verify_cb_cert(ctx, x, depth,
- X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD))
- return 0;
- if (i < 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_HAS_EXPIRED))
- return 0;
+ CB_FAIL_IF(i == 0, ctx, x, depth, X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
+ CB_FAIL_IF(i < 0, ctx, x, depth, X509_V_ERR_CERT_HAS_EXPIRED);
return 1;
}
-/* verify the issuer signatures and cert times of ctx->chain */
+/*
+ * Verify the issuer signatures and cert times of ctx->chain.
+ * Sadly, returns 0 also on internal error.
+ */
static int internal_verify(X509_STORE_CTX *ctx)
{
int n = sk_X509_num(ctx->chain) - 1;
X509 *xi = sk_X509_value(ctx->chain, n);
- X509 *xs;
+ X509 *xs = xi;
- /*
- * With DANE-verified bare public key TA signatures, it remains only to
- * check the timestamps of the top certificate. We report the issuer as
- * NULL, since all we have is a bare key.
- */
+ ctx->error_depth = n;
if (ctx->bare_ta_signed) {
- xs = xi;
+ /*
+ * With DANE-verified bare public key TA signatures,
+ * on the top certificate we check only the timestamps.
+ * We report the issuer as NULL because all we have is a bare key.
+ */
xi = NULL;
- goto check_cert_time;
- }
-
- if (ctx->check_issued(ctx, xi, xi))
- xs = xi; /* the typical case: last cert in the chain is self-issued */
- else {
- if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
- xs = xi;
- goto check_cert_time;
- }
- if (n <= 0) {
- if (!verify_cb_cert(ctx, xi, 0,
- X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
- return 0;
-
- xs = xi;
- goto check_cert_time;
+ } else if (ossl_x509_likely_issued(xi, xi) != X509_V_OK
+ /* exceptional case: last cert in the chain is not self-issued */
+ && ((ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) == 0)) {
+ if (n > 0) {
+ n--;
+ ctx->error_depth = n;
+ xs = sk_X509_value(ctx->chain, n);
+ } else {
+ CB_FAIL_IF(1, ctx, xi, 0,
+ X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
}
-
- n--;
- ctx->error_depth = n;
- xs = sk_X509_value(ctx->chain, n);
+ /*
+ * The below code will certainly not do a
+ * self-signature check on xi because it is not self-issued.
+ */
}
/*
- * Do not clear ctx->error=0, it must be "sticky", only the user's callback
- * is allowed to reset errors (at its own peril).
+ * Do not clear error (by ctx->error = X509_V_OK), it must be "sticky",
+ * only the user's callback is allowed to reset errors (at its own peril).
*/
while (n >= 0) {
- /*
+ /*-
* For each iteration of this loop:
* n is the subject depth
* xs is the subject cert, for which the signature is to be checked
- * xi is the supposed issuer cert containing the public key to use
+ * xi is NULL for DANE-verified bare public key TA signatures
+ * else the supposed issuer cert containing the public key to use
* Initially xs == xi if the last cert in the chain is self-issued.
- *
- * Skip signature check for self-signed certificates unless explicitly
+ */
+ /*
+ * Do signature check for self-signed certificates only if explicitly
* asked for because it does not add any security and just wastes time.
*/
- if (xs != xi || ((ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)
- && (xi->ex_flags & EXFLAG_SS) != 0)) {
+ if (xi != NULL
+ && (xs != xi
+ || ((ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE) != 0
+ && (xi->ex_flags & EXFLAG_SS) != 0))) {
EVP_PKEY *pkey;
/*
* If the issuer's public key is not available or its key usage
@@ -1795,8 +1804,8 @@ static int internal_verify(X509_STORE_CTX *ctx)
* step (n) we must check any given key usage extension in a CA cert
* when preparing the verification of a certificate issued by it.
* According to https://tools.ietf.org/html/rfc5280#section-4.2.1.3
- * we must not verify a certifiate signature if the key usage of the
- * CA certificate that issued the certificate prohibits signing.
+ * we must not verify a certificate signature if the key usage of
+ * the CA certificate that issued the certificate prohibits signing.
* In case the 'issuing' certificate is the last in the chain and is
* not a CA certificate but a 'self-issued' end-entity cert (i.e.,
* xs == xi && !(xi->ex_flags & EXFLAG_CA)) RFC 5280 does not apply
@@ -1804,24 +1813,21 @@ static int internal_verify(X509_STORE_CTX *ctx)
* we are free to ignore any key usage restrictions on such certs.
*/
int ret = xs == xi && (xi->ex_flags & EXFLAG_CA) == 0
- ? X509_V_OK : x509_signing_allowed(xi, xs);
+ ? X509_V_OK : ossl_x509_signing_allowed(xi, xs);
- if (ret != X509_V_OK && !verify_cb_cert(ctx, xi, issuer_depth, ret))
- return 0;
+ CB_FAIL_IF(ret != X509_V_OK, ctx, xi, issuer_depth, ret);
if ((pkey = X509_get0_pubkey(xi)) == NULL) {
- ret = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
- if (!verify_cb_cert(ctx, xi, issuer_depth, ret))
- return 0;
- } else if (X509_verify(xs, pkey) <= 0) {
- ret = X509_V_ERR_CERT_SIGNATURE_FAILURE;
- if (!verify_cb_cert(ctx, xs, n, ret))
- return 0;
+ CB_FAIL_IF(1, ctx, xi, issuer_depth,
+ X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+ } else {
+ CB_FAIL_IF(X509_verify(xs, pkey) <= 0,
+ ctx, xs, n, X509_V_ERR_CERT_SIGNATURE_FAILURE);
}
}
- check_cert_time: /* in addition to RFC 5280, do also for trusted (root) cert */
+ /* In addition to RFC 5280 requirements do also for trust anchor cert */
/* Calls verify callback as needed */
- if (!x509_check_cert_time(ctx, xs, n))
+ if (!ossl_x509_check_cert_time(ctx, xs, n))
return 0;
/*
@@ -1858,7 +1864,8 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
#else
const char upper_z = 'Z';
#endif
- /*
+
+ /*-
* Note that ASN.1 allows much more slack in the time format than RFC5280.
* In RFC5280, the representation is fixed:
* UTCTime: YYMMDDHHMMSSZ
@@ -1888,7 +1895,7 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
* Digit and date ranges will be verified in the conversion methods.
*/
for (i = 0; i < ctm->length - 1; i++) {
- if (!ascii_isdigit(ctm->data[i]))
+ if (!ossl_ascii_isdigit(ctm->data[i]))
return 0;
}
if (ctm->data[ctm->length - 1] != upper_z)
@@ -1902,7 +1909,7 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
asn1_cmp_time = X509_time_adj(NULL, 0, cmp_time);
if (asn1_cmp_time == NULL)
goto err;
- if (!ASN1_TIME_diff(&day, &sec, ctm, asn1_cmp_time))
+ if (ASN1_TIME_diff(&day, &sec, ctm, asn1_cmp_time) == 0)
goto err;
/*
@@ -1916,6 +1923,31 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
return ret;
}
+/*
+ * Return 0 if time should not be checked or reference time is in range,
+ * or else 1 if it is past the end, or -1 if it is before the start
+ */
+int X509_cmp_timeframe(const X509_VERIFY_PARAM *vpm,
+ const ASN1_TIME *start, const ASN1_TIME *end)
+{
+ time_t ref_time;
+ time_t *time = NULL;
+ unsigned long flags = vpm == NULL ? 0 : X509_VERIFY_PARAM_get_flags(vpm);
+
+ if ((flags & X509_V_FLAG_USE_CHECK_TIME) != 0) {
+ ref_time = X509_VERIFY_PARAM_get_time(vpm);
+ time = &ref_time;
+ } else if ((flags & X509_V_FLAG_NO_CHECK_TIME) != 0) {
+ return 0; /* this means ok */
+ } /* else reference time is the current time */
+
+ if (end != NULL && X509_cmp_time(end, time) < 0)
+ return 1;
+ if (start != NULL && X509_cmp_time(start, time) > 0)
+ return -1;
+ return 0;
+}
+
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj)
{
return X509_time_adj(s, adj, NULL);
@@ -1936,7 +1968,7 @@ ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s,
else
time(&t);
- if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) {
+ if (s != NULL && (s->flags & ASN1_STRING_FLAG_MSTRING) == 0) {
if (s->type == V_ASN1_UTCTIME)
return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec);
if (s->type == V_ASN1_GENERALIZEDTIME)
@@ -1945,87 +1977,92 @@ ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s,
return ASN1_TIME_adj(s, t, offset_day, offset_sec);
}
+/* Copy any missing public key parameters up the chain towards pkey */
int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain)
{
EVP_PKEY *ktmp = NULL, *ktmp2;
int i, j;
- if ((pkey != NULL) && !EVP_PKEY_missing_parameters(pkey))
+ if (pkey != NULL && !EVP_PKEY_missing_parameters(pkey))
return 1;
for (i = 0; i < sk_X509_num(chain); i++) {
ktmp = X509_get0_pubkey(sk_X509_value(chain, i));
if (ktmp == NULL) {
- X509err(X509_F_X509_GET_PUBKEY_PARAMETERS,
- X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+ ERR_raise(ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
return 0;
}
if (!EVP_PKEY_missing_parameters(ktmp))
break;
+ ktmp = NULL;
}
if (ktmp == NULL) {
- X509err(X509_F_X509_GET_PUBKEY_PARAMETERS,
- X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN);
+ ERR_raise(ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN);
return 0;
}
/* first, populate the other certs */
for (j = i - 1; j >= 0; j--) {
ktmp2 = X509_get0_pubkey(sk_X509_value(chain, j));
- EVP_PKEY_copy_parameters(ktmp2, ktmp);
+ if (!EVP_PKEY_copy_parameters(ktmp2, ktmp))
+ return 0;
}
if (pkey != NULL)
- EVP_PKEY_copy_parameters(pkey, ktmp);
+ return EVP_PKEY_copy_parameters(pkey, ktmp);
return 1;
}
-/* Make a delta CRL as the diff between two full CRLs */
-
+/*
+ * Make a delta CRL as the difference between two full CRLs.
+ * Sadly, returns NULL also on internal error.
+ */
X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
EVP_PKEY *skey, const EVP_MD *md, unsigned int flags)
{
X509_CRL *crl = NULL;
int i;
+
STACK_OF(X509_REVOKED) *revs = NULL;
/* CRLs can't be delta already */
- if (base->base_crl_number || newer->base_crl_number) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_ALREADY_DELTA);
+ if (base->base_crl_number != NULL || newer->base_crl_number != NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_CRL_ALREADY_DELTA);
return NULL;
}
/* Base and new CRL must have a CRL number */
- if (!base->crl_number || !newer->crl_number) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_NO_CRL_NUMBER);
+ if (base->crl_number == NULL || newer->crl_number == NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_NO_CRL_NUMBER);
return NULL;
}
/* Issuer names must match */
- if (X509_NAME_cmp(X509_CRL_get_issuer(base), X509_CRL_get_issuer(newer))) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_ISSUER_MISMATCH);
+ if (X509_NAME_cmp(X509_CRL_get_issuer(base),
+ X509_CRL_get_issuer(newer)) != 0) {
+ ERR_raise(ERR_LIB_X509, X509_R_ISSUER_MISMATCH);
return NULL;
}
/* AKID and IDP must match */
if (!crl_extension_match(base, newer, NID_authority_key_identifier)) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_AKID_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_AKID_MISMATCH);
return NULL;
}
if (!crl_extension_match(base, newer, NID_issuing_distribution_point)) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_IDP_MISMATCH);
+ ERR_raise(ERR_LIB_X509, X509_R_IDP_MISMATCH);
return NULL;
}
/* Newer CRL number must exceed full CRL number */
if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_NEWER_CRL_NOT_NEWER);
+ ERR_raise(ERR_LIB_X509, X509_R_NEWER_CRL_NOT_NEWER);
return NULL;
}
/* CRLs must verify */
- if (skey && (X509_CRL_verify(base, skey) <= 0 ||
- X509_CRL_verify(newer, skey) <= 0)) {
- X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_VERIFY_FAILURE);
+ if (skey != NULL && (X509_CRL_verify(base, skey) <= 0 ||
+ X509_CRL_verify(newer, skey) <= 0)) {
+ ERR_raise(ERR_LIB_X509, X509_R_CRL_VERIFY_FAILURE);
return NULL;
}
/* Create new CRL */
- crl = X509_CRL_new();
- if (crl == NULL || !X509_CRL_set_version(crl, 1))
+ crl = X509_CRL_new_ex(base->libctx, base->propq);
+ if (crl == NULL || !X509_CRL_set_version(crl, X509_CRL_VERSION_2))
goto memerr;
/* Set issuer name */
if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer)))
@@ -2037,7 +2074,6 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
goto memerr;
/* Set base CRL number: must be critical */
-
if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0))
goto memerr;
@@ -2045,28 +2081,28 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
* Copy extensions across from newest CRL to delta: this will set CRL
* number to correct value too.
*/
-
for (i = 0; i < X509_CRL_get_ext_count(newer); i++) {
- X509_EXTENSION *ext;
- ext = X509_CRL_get_ext(newer, i);
+ X509_EXTENSION *ext = X509_CRL_get_ext(newer, i);
+
if (!X509_CRL_add_ext(crl, ext, -1))
goto memerr;
}
/* Go through revoked entries, copying as needed */
-
revs = X509_CRL_get_REVOKED(newer);
for (i = 0; i < sk_X509_REVOKED_num(revs); i++) {
X509_REVOKED *rvn, *rvtmp;
+
rvn = sk_X509_REVOKED_value(revs, i);
/*
- * Add only if not also in base. TODO: need something cleverer here
- * for some more complex CRLs covering multiple CAs.
+ * Add only if not also in base.
+ * Need something cleverer here for some more complex CRLs covering
+ * multiple CAs.
*/
if (!X509_CRL_get0_by_serial(base, &rvtmp, &rvn->serialNumber)) {
rvtmp = X509_REVOKED_dup(rvn);
- if (!rvtmp)
+ if (rvtmp == NULL)
goto memerr;
if (!X509_CRL_add0_revoked(crl, rvtmp)) {
X509_REVOKED_free(rvtmp);
@@ -2074,15 +2110,14 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
}
}
}
- /* TODO: optionally prune deleted entries */
- if (skey && md && !X509_CRL_sign(crl, skey, md))
+ if (skey != NULL && md != NULL && !X509_CRL_sign(crl, skey, md))
goto memerr;
return crl;
memerr:
- X509err(X509_F_X509_CRL_DIFF, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
X509_CRL_free(crl);
return NULL;
}
@@ -2092,12 +2127,12 @@ int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data)
return CRYPTO_set_ex_data(&ctx->ex_data, idx, data);
}
-void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx)
+void *X509_STORE_CTX_get_ex_data(const X509_STORE_CTX *ctx, int idx)
{
return CRYPTO_get_ex_data(&ctx->ex_data, idx);
}
-int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx)
+int X509_STORE_CTX_get_error(const X509_STORE_CTX *ctx)
{
return ctx->error;
}
@@ -2107,7 +2142,7 @@ void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int err)
ctx->error = err;
}
-int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx)
+int X509_STORE_CTX_get_error_depth(const X509_STORE_CTX *ctx)
{
return ctx->error_depth;
}
@@ -2117,7 +2152,7 @@ void X509_STORE_CTX_set_error_depth(X509_STORE_CTX *ctx, int depth)
ctx->error_depth = depth;
}
-X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx)
+X509 *X509_STORE_CTX_get_current_cert(const X509_STORE_CTX *ctx)
{
return ctx->current_cert;
}
@@ -2127,29 +2162,29 @@ void X509_STORE_CTX_set_current_cert(X509_STORE_CTX *ctx, X509 *x)
ctx->current_cert = x;
}
-STACK_OF(X509) *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx)
+STACK_OF(X509) *X509_STORE_CTX_get0_chain(const X509_STORE_CTX *ctx)
{
return ctx->chain;
}
-STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx)
+STACK_OF(X509) *X509_STORE_CTX_get1_chain(const X509_STORE_CTX *ctx)
{
- if (!ctx->chain)
+ if (ctx->chain == NULL)
return NULL;
return X509_chain_up_ref(ctx->chain);
}
-X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx)
+X509 *X509_STORE_CTX_get0_current_issuer(const X509_STORE_CTX *ctx)
{
return ctx->current_issuer;
}
-X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx)
+X509_CRL *X509_STORE_CTX_get0_current_crl(const X509_STORE_CTX *ctx)
{
return ctx->current_crl;
}
-X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx)
+X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(const X509_STORE_CTX *ctx)
{
return ctx->parent;
}
@@ -2193,13 +2228,13 @@ int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust)
* application can set: if they aren't set then we use the default of SSL
* client/server.
*/
-
int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
int purpose, int trust)
{
int idx;
+
/* If purpose not set use default */
- if (!purpose)
+ if (purpose == 0)
purpose = def_purpose;
/*
* If purpose is set but we don't have a default then set the default to
@@ -2208,70 +2243,91 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
else if (def_purpose == 0)
def_purpose = purpose;
/* If we have a purpose then check it is valid */
- if (purpose) {
+ if (purpose != 0) {
X509_PURPOSE *ptmp;
+
idx = X509_PURPOSE_get_by_id(purpose);
if (idx == -1) {
- X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT,
- X509_R_UNKNOWN_PURPOSE_ID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID);
return 0;
}
ptmp = X509_PURPOSE_get0(idx);
if (ptmp->trust == X509_TRUST_DEFAULT) {
idx = X509_PURPOSE_get_by_id(def_purpose);
if (idx == -1) {
- X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT,
- X509_R_UNKNOWN_PURPOSE_ID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID);
return 0;
}
ptmp = X509_PURPOSE_get0(idx);
}
/* If trust not set then get from purpose default */
- if (!trust)
+ if (trust == 0)
trust = ptmp->trust;
}
- if (trust) {
+ if (trust != 0) {
idx = X509_TRUST_get_by_id(trust);
if (idx == -1) {
- X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT,
- X509_R_UNKNOWN_TRUST_ID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID);
return 0;
}
}
- if (purpose && !ctx->param->purpose)
+ if (ctx->param->purpose == 0 && purpose != 0)
ctx->param->purpose = purpose;
- if (trust && !ctx->param->trust)
+ if (ctx->param->trust == 0 && trust != 0)
ctx->param->trust = trust;
return 1;
}
-X509_STORE_CTX *X509_STORE_CTX_new(void)
+X509_STORE_CTX *X509_STORE_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
{
X509_STORE_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL) {
- X509err(X509_F_X509_STORE_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
+
+ ctx->libctx = libctx;
+ if (propq != NULL) {
+ ctx->propq = OPENSSL_strdup(propq);
+ if (ctx->propq == NULL) {
+ OPENSSL_free(ctx);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ }
+
return ctx;
}
+X509_STORE_CTX *X509_STORE_CTX_new(void)
+{
+ return X509_STORE_CTX_new_ex(NULL, NULL);
+}
+
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
{
if (ctx == NULL)
return;
X509_STORE_CTX_cleanup(ctx);
+
+ /* libctx and propq survive X509_STORE_CTX_cleanup() */
+ OPENSSL_free(ctx->propq);
OPENSSL_free(ctx);
}
int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
STACK_OF(X509) *chain)
{
- int ret = 1;
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ X509_STORE_CTX_cleanup(ctx);
- ctx->ctx = store;
+ ctx->store = store;
ctx->cert = x509;
ctx->untrusted = chain;
ctx->crls = NULL;
@@ -2279,7 +2335,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
ctx->other_ctx = NULL;
ctx->valid = 0;
ctx->chain = NULL;
- ctx->error = 0;
+ ctx->error = X509_V_OK;
ctx->explicit_policy = 0;
ctx->error_depth = 0;
ctx->current_cert = NULL;
@@ -2295,88 +2351,80 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
memset(&ctx->ex_data, 0, sizeof(ctx->ex_data));
/* store->cleanup is always 0 in OpenSSL, if set must be idempotent */
- if (store)
+ if (store != NULL)
ctx->cleanup = store->cleanup;
else
- ctx->cleanup = 0;
+ ctx->cleanup = NULL;
- if (store && store->check_issued)
+ if (store != NULL && store->check_issued != NULL)
ctx->check_issued = store->check_issued;
else
ctx->check_issued = check_issued;
- if (store && store->get_issuer)
+ if (store != NULL && store->get_issuer != NULL)
ctx->get_issuer = store->get_issuer;
else
ctx->get_issuer = X509_STORE_CTX_get1_issuer;
- if (store && store->verify_cb)
+ if (store != NULL && store->verify_cb != NULL)
ctx->verify_cb = store->verify_cb;
else
ctx->verify_cb = null_callback;
- if (store && store->verify)
+ if (store != NULL && store->verify != NULL)
ctx->verify = store->verify;
else
ctx->verify = internal_verify;
- if (store && store->check_revocation)
+ if (store != NULL && store->check_revocation != NULL)
ctx->check_revocation = store->check_revocation;
else
ctx->check_revocation = check_revocation;
- if (store && store->get_crl)
+ if (store != NULL && store->get_crl != NULL)
ctx->get_crl = store->get_crl;
else
ctx->get_crl = NULL;
- if (store && store->check_crl)
+ if (store != NULL && store->check_crl != NULL)
ctx->check_crl = store->check_crl;
else
ctx->check_crl = check_crl;
- if (store && store->cert_crl)
+ if (store != NULL && store->cert_crl != NULL)
ctx->cert_crl = store->cert_crl;
else
ctx->cert_crl = cert_crl;
- if (store && store->check_policy)
+ if (store != NULL && store->check_policy != NULL)
ctx->check_policy = store->check_policy;
else
ctx->check_policy = check_policy;
- if (store && store->lookup_certs)
+ if (store != NULL && store->lookup_certs != NULL)
ctx->lookup_certs = store->lookup_certs;
else
ctx->lookup_certs = X509_STORE_CTX_get1_certs;
- if (store && store->lookup_crls)
+ if (store != NULL && store->lookup_crls != NULL)
ctx->lookup_crls = store->lookup_crls;
else
ctx->lookup_crls = X509_STORE_CTX_get1_crls;
ctx->param = X509_VERIFY_PARAM_new();
if (ctx->param == NULL) {
- X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
- /*
- * Inherit callbacks and flags from X509_STORE if not set use defaults.
- */
- if (store)
- ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param);
- else
+ /* Inherit callbacks and flags from X509_STORE if not set use defaults. */
+ if (store == NULL)
ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT | X509_VP_FLAG_ONCE;
+ else if (X509_VERIFY_PARAM_inherit(ctx->param, store->param) == 0)
+ goto err;
- if (ret)
- ret = X509_VERIFY_PARAM_inherit(ctx->param,
- X509_VERIFY_PARAM_lookup("default"));
-
- if (ret == 0) {
- X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
+ if (!X509_STORE_CTX_set_default(ctx, "default"))
goto err;
- }
/*
* XXX: For now, continue to inherit trust from VPM, but infer from the
@@ -2393,7 +2441,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
if (CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
&ctx->ex_data))
return 1;
- X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
err:
/*
@@ -2405,8 +2453,8 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
}
/*
- * Set alternative lookup method: just a STACK of trusted certificates. This
- * avoids X509_STORE nastiness where it isn't needed.
+ * Set alternative get_issuer method: just from a STACK of trusted certificates.
+ * This avoids the complexity of X509_STORE where it is not needed.
*/
void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
{
@@ -2423,7 +2471,7 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
* calls cleanup() for the same object twice! Thus we must zero the
* pointers below after they're freed!
*/
- /* Seems to always be 0 in OpenSSL, do this at most once. */
+ /* Seems to always be NULL in OpenSSL, do this at most once. */
if (ctx->cleanup != NULL) {
ctx->cleanup(ctx);
ctx->cleanup = NULL;
@@ -2457,12 +2505,12 @@ void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
X509_VERIFY_PARAM_set_time(ctx->param, t);
}
-X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx)
+X509 *X509_STORE_CTX_get0_cert(const X509_STORE_CTX *ctx)
{
return ctx->cert;
}
-STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx)
+STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(const X509_STORE_CTX *ctx)
{
return ctx->untrusted;
}
@@ -2484,7 +2532,7 @@ void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
ctx->verify_cb = verify_cb;
}
-X509_STORE_CTX_verify_cb X509_STORE_CTX_get_verify_cb(X509_STORE_CTX *ctx)
+X509_STORE_CTX_verify_cb X509_STORE_CTX_get_verify_cb(const X509_STORE_CTX *ctx)
{
return ctx->verify_cb;
}
@@ -2495,72 +2543,80 @@ void X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx,
ctx->verify = verify;
}
-X509_STORE_CTX_verify_fn X509_STORE_CTX_get_verify(X509_STORE_CTX *ctx)
+X509_STORE_CTX_verify_fn X509_STORE_CTX_get_verify(const X509_STORE_CTX *ctx)
{
return ctx->verify;
}
-X509_STORE_CTX_get_issuer_fn X509_STORE_CTX_get_get_issuer(X509_STORE_CTX *ctx)
+X509_STORE_CTX_get_issuer_fn
+X509_STORE_CTX_get_get_issuer(const X509_STORE_CTX *ctx)
{
return ctx->get_issuer;
}
-X509_STORE_CTX_check_issued_fn X509_STORE_CTX_get_check_issued(X509_STORE_CTX *ctx)
+X509_STORE_CTX_check_issued_fn
+X509_STORE_CTX_get_check_issued(const X509_STORE_CTX *ctx)
{
return ctx->check_issued;
}
-X509_STORE_CTX_check_revocation_fn X509_STORE_CTX_get_check_revocation(X509_STORE_CTX *ctx)
+X509_STORE_CTX_check_revocation_fn
+X509_STORE_CTX_get_check_revocation(const X509_STORE_CTX *ctx)
{
return ctx->check_revocation;
}
-X509_STORE_CTX_get_crl_fn X509_STORE_CTX_get_get_crl(X509_STORE_CTX *ctx)
+X509_STORE_CTX_get_crl_fn X509_STORE_CTX_get_get_crl(const X509_STORE_CTX *ctx)
{
return ctx->get_crl;
}
-X509_STORE_CTX_check_crl_fn X509_STORE_CTX_get_check_crl(X509_STORE_CTX *ctx)
+X509_STORE_CTX_check_crl_fn
+X509_STORE_CTX_get_check_crl(const X509_STORE_CTX *ctx)
{
return ctx->check_crl;
}
-X509_STORE_CTX_cert_crl_fn X509_STORE_CTX_get_cert_crl(X509_STORE_CTX *ctx)
+X509_STORE_CTX_cert_crl_fn
+X509_STORE_CTX_get_cert_crl(const X509_STORE_CTX *ctx)
{
return ctx->cert_crl;
}
-X509_STORE_CTX_check_policy_fn X509_STORE_CTX_get_check_policy(X509_STORE_CTX *ctx)
+X509_STORE_CTX_check_policy_fn
+X509_STORE_CTX_get_check_policy(const X509_STORE_CTX *ctx)
{
return ctx->check_policy;
}
-X509_STORE_CTX_lookup_certs_fn X509_STORE_CTX_get_lookup_certs(X509_STORE_CTX *ctx)
+X509_STORE_CTX_lookup_certs_fn
+X509_STORE_CTX_get_lookup_certs(const X509_STORE_CTX *ctx)
{
return ctx->lookup_certs;
}
-X509_STORE_CTX_lookup_crls_fn X509_STORE_CTX_get_lookup_crls(X509_STORE_CTX *ctx)
+X509_STORE_CTX_lookup_crls_fn
+X509_STORE_CTX_get_lookup_crls(const X509_STORE_CTX *ctx)
{
return ctx->lookup_crls;
}
-X509_STORE_CTX_cleanup_fn X509_STORE_CTX_get_cleanup(X509_STORE_CTX *ctx)
+X509_STORE_CTX_cleanup_fn X509_STORE_CTX_get_cleanup(const X509_STORE_CTX *ctx)
{
return ctx->cleanup;
}
-X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx)
+X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(const X509_STORE_CTX *ctx)
{
return ctx->tree;
}
-int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx)
+int X509_STORE_CTX_get_explicit_policy(const X509_STORE_CTX *ctx)
{
return ctx->explicit_policy;
}
-int X509_STORE_CTX_get_num_untrusted(X509_STORE_CTX *ctx)
+int X509_STORE_CTX_get_num_untrusted(const X509_STORE_CTX *ctx)
{
return ctx->num_untrusted;
}
@@ -2568,13 +2624,16 @@ int X509_STORE_CTX_get_num_untrusted(X509_STORE_CTX *ctx)
int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name)
{
const X509_VERIFY_PARAM *param;
+
param = X509_VERIFY_PARAM_lookup(name);
- if (!param)
+ if (param == NULL) {
+ ERR_raise_data(ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID, "name=%s", name);
return 0;
+ }
return X509_VERIFY_PARAM_inherit(ctx->param, param);
}
-X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx)
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(const X509_STORE_CTX *ctx)
{
return ctx->param;
}
@@ -2590,10 +2649,8 @@ void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, SSL_DANE *dane)
ctx->dane = dane;
}
-static unsigned char *dane_i2d(
- X509 *cert,
- uint8_t selector,
- unsigned int *i2dlen)
+static unsigned char *dane_i2d(X509 *cert, uint8_t selector,
+ unsigned int *i2dlen)
{
unsigned char *buf = NULL;
int len;
@@ -2609,12 +2666,12 @@ static unsigned char *dane_i2d(
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf);
break;
default:
- X509err(X509_F_DANE_I2D, X509_R_BAD_SELECTOR);
+ ERR_raise(ERR_LIB_X509, X509_R_BAD_SELECTOR);
return NULL;
}
if (len < 0 || buf == NULL) {
- X509err(X509_F_DANE_I2D, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
@@ -2622,8 +2679,9 @@ static unsigned char *dane_i2d(
return buf;
}
-#define DANETLS_NONE 256 /* impossible uint8_t */
+#define DANETLS_NONE 256 /* impossible uint8_t */
+/* Returns -1 on internal error */
static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
{
SSL_DANE *dane = ctx->dane;
@@ -2644,9 +2702,7 @@ static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
mask = (depth == 0) ? DANETLS_EE_MASK : DANETLS_TA_MASK;
- /*
- * The trust store is not applicable with DANE-TA(2)
- */
+ /* The trust store is not applicable with DANE-TA(2) */
if (depth >= ctx->num_untrusted)
mask &= DANETLS_PKIX_MASK;
@@ -2686,7 +2742,7 @@ static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
* exhausting all DANE-?? records, we've matched a PKIX-?? record, which is
* sufficient for DANE, and what remains to do is ordinary PKIX validation.
*/
- recnum = (dane->umask & mask) ? sk_danetls_record_num(dane->trecs) : 0;
+ recnum = (dane->umask & mask) != 0 ? sk_danetls_record_num(dane->trecs) : 0;
for (i = 0; matched == 0 && i < recnum; ++i) {
t = sk_danetls_record_value(dane->trecs, i);
if ((DANETLS_USAGE_BIT(t->usage) & mask) == 0)
@@ -2730,6 +2786,7 @@ static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
*/
if (t->mtype != mtype) {
const EVP_MD *md = dane->dctx->mdevp[mtype = t->mtype];
+
cmpbuf = i2dbuf;
cmplen = i2dlen;
@@ -2767,6 +2824,7 @@ static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
return matched;
}
+/* Returns -1 on internal error */
static int check_dane_issuer(X509_STORE_CTX *ctx, int depth)
{
SSL_DANE *dane = ctx->dane;
@@ -2774,22 +2832,22 @@ static int check_dane_issuer(X509_STORE_CTX *ctx, int depth)
X509 *cert;
if (!DANETLS_HAS_TA(dane) || depth == 0)
- return X509_TRUST_UNTRUSTED;
+ return X509_TRUST_UNTRUSTED;
/*
- * Record any DANE trust-anchor matches, for the first depth to test, if
+ * Record any DANE trust anchor matches, for the first depth to test, if
* there's one at that depth. (This'll be false for length 1 chains looking
* for an exact match for the leaf certificate).
*/
cert = sk_X509_value(ctx->chain, depth);
if (cert != NULL && (matched = dane_match(ctx, cert, depth)) < 0)
- return X509_TRUST_REJECTED;
+ return matched;
if (matched > 0) {
ctx->num_untrusted = depth - 1;
- return X509_TRUST_TRUSTED;
+ return X509_TRUST_TRUSTED;
}
- return X509_TRUST_UNTRUSTED;
+ return X509_TRUST_UNTRUSTED;
}
static int check_dane_pkeys(X509_STORE_CTX *ctx)
@@ -2831,9 +2889,7 @@ static int check_dane_pkeys(X509_STORE_CTX *ctx)
static void dane_reset(SSL_DANE *dane)
{
- /*
- * Reset state to verify another chain, or clear after failure.
- */
+ /* Reset state to verify another chain, or clear after failure. */
X509_free(dane->mcert);
dane->mcert = NULL;
dane->mtlsa = NULL;
@@ -2845,11 +2901,11 @@ static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert)
{
int err = X509_chain_check_suiteb(NULL, cert, NULL, ctx->param->flags);
- if (err == X509_V_OK)
- return 1;
- return verify_cb_cert(ctx, cert, 0, err);
+ CB_FAIL_IF(err != X509_V_OK, ctx, cert, 0, err);
+ return 1;
}
+/* Returns -1 on internal error */
static int dane_verify(X509_STORE_CTX *ctx)
{
X509 *cert = ctx->cert;
@@ -2863,7 +2919,7 @@ static int dane_verify(X509_STORE_CTX *ctx)
* When testing the leaf certificate, if we match a DANE-EE(3) record,
* dane_match() returns 1 and we're done. If however we match a PKIX-EE(1)
* record, the match depth and matching TLSA record are recorded, but the
- * return value is 0, because we still need to find a PKIX trust-anchor.
+ * return value is 0, because we still need to find a PKIX trust anchor.
* Therefore, when DANE authentication is enabled (required), we're done
* if:
* + matched < 0, internal error.
@@ -2874,8 +2930,8 @@ static int dane_verify(X509_STORE_CTX *ctx)
matched = dane_match(ctx, ctx->cert, 0);
done = matched != 0 || (!DANETLS_HAS_TA(dane) && dane->mdpth < 0);
- if (done)
- X509_get_pubkey_parameters(NULL, ctx->chain);
+ if (done && !X509_get_pubkey_parameters(NULL, ctx->chain))
+ return -1;
if (matched > 0) {
/* Callback invoked as needed */
@@ -2912,8 +2968,11 @@ static int dane_verify(X509_STORE_CTX *ctx)
return verify_chain(ctx);
}
-/* Get issuer, without duplicate suppression */
-static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *cert)
+/*
+ * Get trusted issuer, without duplicate suppression
+ * Returns -1 on internal error.
+ */
+static int get1_trusted_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *cert)
{
STACK_OF(X509) *saved_chain = ctx->chain;
int ok;
@@ -2925,118 +2984,89 @@ static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *cert)
return ok;
}
-static int augment_stack(STACK_OF(X509) *src, STACK_OF(X509) **dstPtr)
-{
- if (src) {
- STACK_OF(X509) *dst;
- int i;
-
- if (*dstPtr == NULL)
- return ((*dstPtr = sk_X509_dup(src)) != NULL);
-
- for (dst = *dstPtr, i = 0; i < sk_X509_num(src); ++i) {
- if (!sk_X509_push(dst, sk_X509_value(src, i))) {
- sk_X509_free(dst);
- *dstPtr = NULL;
- return 0;
- }
- }
- }
- return 1;
-}
-
+/* Returns -1 on internal error */
static int build_chain(X509_STORE_CTX *ctx)
{
SSL_DANE *dane = ctx->dane;
int num = sk_X509_num(ctx->chain);
- X509 *cert = sk_X509_value(ctx->chain, num - 1);
- int ss = cert_self_signed(cert);
- STACK_OF(X509) *sktmp = NULL;
+ STACK_OF(X509) *sk_untrusted = NULL;
unsigned int search;
int may_trusted = 0;
int may_alternate = 0;
int trust = X509_TRUST_UNTRUSTED;
int alt_untrusted = 0;
- int depth;
+ int max_depth;
int ok = 0;
int i;
/* Our chain starts with a single untrusted element. */
- if (!ossl_assert(num == 1 && ctx->num_untrusted == num)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
- ctx->error = X509_V_ERR_UNSPECIFIED;
- return 0;
- }
+ if (!ossl_assert(num == 1 && ctx->num_untrusted == num))
+ goto int_err;
-#define S_DOUNTRUSTED (1 << 0) /* Search untrusted chain */
-#define S_DOTRUSTED (1 << 1) /* Search trusted store */
-#define S_DOALTERNATE (1 << 2) /* Retry with pruned alternate chain */
+#define S_DOUNTRUSTED (1 << 0) /* Search untrusted chain */
+#define S_DOTRUSTED (1 << 1) /* Search trusted store */
+#define S_DOALTERNATE (1 << 2) /* Retry with pruned alternate chain */
/*
- * Set up search policy, untrusted if possible, trusted-first if enabled.
+ * Set up search policy, untrusted if possible, trusted-first if enabled,
+ * which is the default.
* If we're doing DANE and not doing PKIX-TA/PKIX-EE, we never look in the
* trust_store, otherwise we might look there first. If not trusted-first,
* and alternate chains are not disabled, try building an alternate chain
* if no luck with untrusted first.
*/
- search = (ctx->untrusted != NULL) ? S_DOUNTRUSTED : 0;
+ search = ctx->untrusted != NULL ? S_DOUNTRUSTED : 0;
if (DANETLS_HAS_PKIX(dane) || !DANETLS_HAS_DANE(dane)) {
- if (search == 0 || ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
+ if (search == 0 || (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) != 0)
search |= S_DOTRUSTED;
else if (!(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS))
may_alternate = 1;
may_trusted = 1;
}
+ /* Initialize empty untrusted stack. */
+ if ((sk_untrusted = sk_X509_new_null()) == NULL)
+ goto memerr;
+
/*
- * If we got any "Cert(0) Full(0)" issuer certificates from DNS, *prepend*
- * them to our working copy of the untrusted certificate stack. Since the
- * caller of X509_STORE_CTX_init() may have provided only a leaf cert with
- * no corresponding stack of untrusted certificates, we may need to create
- * an empty stack first. [ At present only the ssl library provides DANE
- * support, and ssl_verify_cert_chain() always provides a non-null stack
- * containing at least the leaf certificate, but we must be prepared for
- * this to change. ]
+ * If we got any "Cert(0) Full(0)" trust anchors from DNS, *prepend* them
+ * to our working copy of the untrusted certificate stack.
*/
- if (DANETLS_ENABLED(dane) && !augment_stack(dane->certs, &sktmp)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- return 0;
- }
+ if (DANETLS_ENABLED(dane) && dane->certs != NULL
+ && !X509_add_certs(sk_untrusted, dane->certs, X509_ADD_FLAG_DEFAULT))
+ goto memerr;
/*
* Shallow-copy the stack of untrusted certificates (with TLS, this is
- * typically the content of the peer's certificate message) so can make
+ * typically the content of the peer's certificate message) so we can make
* multiple passes over it, while free to remove elements as we go.
*/
- if (!augment_stack(ctx->untrusted, &sktmp)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- return 0;
- }
+ if (!X509_add_certs(sk_untrusted, ctx->untrusted, X509_ADD_FLAG_DEFAULT))
+ goto memerr;
/*
* Still absurdly large, but arithmetically safe, a lower hard upper bound
* might be reasonable.
*/
- if (ctx->param->depth > INT_MAX/2)
- ctx->param->depth = INT_MAX/2;
+ if (ctx->param->depth > INT_MAX / 2)
+ ctx->param->depth = INT_MAX / 2;
/*
- * Try to Extend the chain until we reach an ultimately trusted issuer.
+ * Try to extend the chain until we reach an ultimately trusted issuer.
* Build chains up to one longer the limit, later fail if we hit the limit,
* with an X509_V_ERR_CERT_CHAIN_TOO_LONG error code.
*/
- depth = ctx->param->depth + 1;
+ max_depth = ctx->param->depth + 1;
while (search != 0) {
- X509 *x;
- X509 *xtmp = NULL;
+ X509 *curr, *issuer = NULL;
+ num = sk_X509_num(ctx->chain);
+ ctx->error_depth = num - 1;
/*
* Look in the trust store if enabled for first lookup, or we've run
* out of untrusted issuers and search here is not disabled. When we
* reach the depth limit, we stop extending the chain, if by that point
- * we've not found a trust-anchor, any trusted chain would be too long.
+ * we've not found a trust anchor, any trusted chain would be too long.
*
* The error reported to the application verify callback is at the
* maximal valid depth with the current certificate equal to the last
@@ -3047,7 +3077,7 @@ static int build_chain(X509_STORE_CTX *ctx)
* would be a-priori too long.
*/
if ((search & S_DOTRUSTED) != 0) {
- i = num = sk_X509_num(ctx->chain);
+ i = num;
if ((search & S_DOALTERNATE) != 0) {
/*
* As high up the chain as we can, look for an alternative
@@ -3066,24 +3096,30 @@ static int build_chain(X509_STORE_CTX *ctx)
*/
i = alt_untrusted;
}
- x = sk_X509_value(ctx->chain, i-1);
+ curr = sk_X509_value(ctx->chain, i - 1);
- ok = (depth < num) ? 0 : get_issuer(&xtmp, ctx, x);
+ /* Note: get1_trusted_issuer() must be used even if self-signed. */
+ ok = num > max_depth ? 0 : get1_trusted_issuer(&issuer, ctx, curr);
if (ok < 0) {
- trust = X509_TRUST_REJECTED;
+ trust = -1;
ctx->error = X509_V_ERR_STORE_LOOKUP;
- search = 0;
- continue;
+ break;
}
if (ok > 0) {
+ int self_signed = X509_self_signed(curr, 0);
+
+ if (self_signed < 0) {
+ X509_free(issuer);
+ goto int_err;
+ }
/*
* Alternative trusted issuer for a mid-chain untrusted cert?
* Pop the untrusted cert's successors and retry. We might now
* be able to complete a valid chain via the trust store. Note
- * that despite the current trust-store match we might still
- * fail complete the chain to a suitable trust-anchor, in which
+ * that despite the current trust store match we might still
+ * fail complete the chain to a suitable trust anchor, in which
* case we may prune some more untrusted certificates and try
* again. Thus the S_DOALTERNATE bit may yet be turned on
* again with an even shorter untrusted chain!
@@ -3093,13 +3129,9 @@ static int build_chain(X509_STORE_CTX *ctx)
* certificate among the ones from the trust store.
*/
if ((search & S_DOALTERNATE) != 0) {
- if (!ossl_assert(num > i && i > 0 && ss == 0)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
- X509_free(xtmp);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_UNSPECIFIED;
- search = 0;
- continue;
+ if (!ossl_assert(num > i && i > 0 && !self_signed)) {
+ X509_free(issuer);
+ goto int_err;
}
search &= ~S_DOALTERNATE;
for (; num > i; --num)
@@ -3121,36 +3153,33 @@ static int build_chain(X509_STORE_CTX *ctx)
* Self-signed untrusted certificates get replaced by their
* trusted matching issuer. Otherwise, grow the chain.
*/
- if (ss == 0) {
- if (!sk_X509_push(ctx->chain, x = xtmp)) {
- X509_free(xtmp);
- X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- search = 0;
- continue;
+ if (!self_signed) {
+ if (!sk_X509_push(ctx->chain, issuer)) {
+ X509_free(issuer);
+ goto memerr;
}
- ss = cert_self_signed(x);
- } else if (num == ctx->num_untrusted) {
+ if ((self_signed = X509_self_signed(issuer, 0)) < 0)
+ goto int_err;
+ } else {
/*
* We have a self-signed certificate that has the same
* subject name (and perhaps keyid and/or serial number) as
- * a trust-anchor. We must have an exact match to avoid
+ * a trust anchor. We must have an exact match to avoid
* possible impersonation via key substitution etc.
*/
- if (X509_cmp(x, xtmp) != 0) {
+ if (X509_cmp(curr, issuer) != 0) {
/* Self-signed untrusted mimic. */
- X509_free(xtmp);
+ X509_free(issuer);
ok = 0;
- } else {
- X509_free(x);
+ } else { /* curr "==" issuer */
+ X509_free(curr);
ctx->num_untrusted = --num;
- (void) sk_X509_set(ctx->chain, num, x = xtmp);
+ (void)sk_X509_set(ctx->chain, num, issuer);
}
}
/*
- * We've added a new trusted certificate to the chain, recheck
+ * We've added a new trusted certificate to the chain, re-check
* trust. If not done, and not self-signed look deeper.
* Whether or not we're doing "trusted first", we no longer
* look for untrusted certificates from the peer's chain.
@@ -3163,21 +3192,13 @@ static int build_chain(X509_STORE_CTX *ctx)
* certificate with ctx->num_untrusted <= num.
*/
if (ok) {
- if (!ossl_assert(ctx->num_untrusted <= num)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_UNSPECIFIED;
- search = 0;
- continue;
- }
+ if (!ossl_assert(ctx->num_untrusted <= num))
+ goto int_err;
search &= ~S_DOUNTRUSTED;
- switch (trust = check_trust(ctx, num)) {
- case X509_TRUST_TRUSTED:
- case X509_TRUST_REJECTED:
- search = 0;
- continue;
- }
- if (ss == 0)
+ trust = check_trust(ctx, num);
+ if (trust != X509_TRUST_UNTRUSTED)
+ break;
+ if (!self_signed)
continue;
}
}
@@ -3199,30 +3220,25 @@ static int build_chain(X509_STORE_CTX *ctx)
/* Search for a trusted issuer of a shorter chain */
search |= S_DOALTERNATE;
alt_untrusted = ctx->num_untrusted - 1;
- ss = 0;
}
}
/*
- * Extend chain with peer-provided certificates
+ * Extend chain with peer-provided untrusted certificates
*/
if ((search & S_DOUNTRUSTED) != 0) {
num = sk_X509_num(ctx->chain);
- if (!ossl_assert(num == ctx->num_untrusted)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_UNSPECIFIED;
- search = 0;
- continue;
- }
- x = sk_X509_value(ctx->chain, num-1);
-
- /*
- * Once we run out of untrusted issuers, we stop looking for more
- * and start looking only in the trust store if enabled.
- */
- xtmp = (ss || depth < num) ? NULL : find_issuer(ctx, sktmp, x);
- if (xtmp == NULL) {
+ if (!ossl_assert(num == ctx->num_untrusted))
+ goto int_err;
+ curr = sk_X509_value(ctx->chain, num - 1);
+ issuer = (X509_self_signed(curr, 0) > 0 || num > max_depth) ?
+ NULL : find_issuer(ctx, sk_untrusted, curr);
+ if (issuer == NULL) {
+ /*
+ * Once we have reached a self-signed cert or num > max_depth
+ * or can't find an issuer in the untrusted list we stop looking
+ * there and start looking only in the trust store if enabled.
+ */
search &= ~S_DOUNTRUSTED;
if (may_trusted)
search |= S_DOTRUSTED;
@@ -3230,48 +3246,30 @@ static int build_chain(X509_STORE_CTX *ctx)
}
/* Drop this issuer from future consideration */
- (void) sk_X509_delete_ptr(sktmp, xtmp);
-
- if (!X509_up_ref(xtmp)) {
- X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_UNSPECIFIED;
- search = 0;
- continue;
- }
+ (void)sk_X509_delete_ptr(sk_untrusted, issuer);
- if (!sk_X509_push(ctx->chain, xtmp)) {
- X509_free(xtmp);
- X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
- trust = X509_TRUST_REJECTED;
- ctx->error = X509_V_ERR_OUT_OF_MEM;
- search = 0;
- continue;
- }
+ if (!X509_add_cert(ctx->chain, issuer, X509_ADD_FLAG_UP_REF))
+ goto int_err;
- x = xtmp;
++ctx->num_untrusted;
- ss = cert_self_signed(xtmp);
- /*
- * Check for DANE-TA trust of the topmost untrusted certificate.
- */
- switch (trust = check_dane_issuer(ctx, ctx->num_untrusted - 1)) {
- case X509_TRUST_TRUSTED:
- case X509_TRUST_REJECTED:
- search = 0;
- continue;
- }
+ /* Check for DANE-TA trust of the topmost untrusted certificate. */
+ trust = check_dane_issuer(ctx, ctx->num_untrusted - 1);
+ if (trust == X509_TRUST_TRUSTED || trust == X509_TRUST_REJECTED)
+ break;
}
}
- sk_X509_free(sktmp);
+ sk_X509_free(sk_untrusted);
+
+ if (trust < 0) /* internal error */
+ return trust;
/*
* Last chance to make a trusted chain, either bare DANE-TA public-key
* signers, or else direct leaf PKIX trust.
*/
num = sk_X509_num(ctx->chain);
- if (num <= depth) {
+ if (num <= max_depth) {
if (trust == X509_TRUST_UNTRUSTED && DANETLS_HAS_DANE_TA(dane))
trust = check_dane_pkeys(ctx);
if (trust == X509_TRUST_UNTRUSTED && num == ctx->num_untrusted)
@@ -3286,34 +3284,97 @@ static int build_chain(X509_STORE_CTX *ctx)
return 0;
case X509_TRUST_UNTRUSTED:
default:
- num = sk_X509_num(ctx->chain);
- if (num > depth)
- return verify_cb_cert(ctx, NULL, num-1,
- X509_V_ERR_CERT_CHAIN_TOO_LONG);
- if (DANETLS_ENABLED(dane) &&
- (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0))
- return verify_cb_cert(ctx, NULL, num-1, X509_V_ERR_DANE_NO_MATCH);
- if (ss && sk_X509_num(ctx->chain) == 1)
- return verify_cb_cert(ctx, NULL, num-1,
- X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
- if (ss)
- return verify_cb_cert(ctx, NULL, num-1,
- X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
- if (ctx->num_untrusted < num)
- return verify_cb_cert(ctx, NULL, num-1,
- X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
- return verify_cb_cert(ctx, NULL, num-1,
- X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+ switch(ctx->error) {
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ return 0; /* Callback already issued by ossl_x509_check_cert_time() */
+ default: /* A preliminary error has become final */
+ return verify_cb_cert(ctx, NULL, num - 1, ctx->error);
+ case X509_V_OK:
+ break;
+ }
+ CB_FAIL_IF(num > max_depth,
+ ctx, NULL, num - 1, X509_V_ERR_CERT_CHAIN_TOO_LONG);
+ CB_FAIL_IF(DANETLS_ENABLED(dane)
+ && (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0),
+ ctx, NULL, num - 1, X509_V_ERR_DANE_NO_MATCH);
+ if (X509_self_signed(sk_X509_value(ctx->chain, num - 1), 0) > 0)
+ return verify_cb_cert(ctx, NULL, num - 1,
+ num == 1
+ ? X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
+ : X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
+ return verify_cb_cert(ctx, NULL, num - 1,
+ ctx->num_untrusted < num
+ ? X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
+ : X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+ }
+
+ int_err:
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ sk_X509_free(sk_untrusted);
+ return -1;
+
+ memerr:
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ sk_X509_free(sk_untrusted);
+ return -1;
+}
+
+STACK_OF(X509) *X509_build_chain(X509 *target, STACK_OF(X509) *certs,
+ X509_STORE *store, int with_self_signed,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ int finish_chain = store != NULL;
+ X509_STORE_CTX *ctx;
+ int flags = X509_ADD_FLAG_UP_REF;
+ STACK_OF(X509) *result = NULL;
+
+ if (target == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if ((ctx = X509_STORE_CTX_new_ex(libctx, propq)) == NULL)
+ return NULL;
+ if (!X509_STORE_CTX_init(ctx, store, target, finish_chain ? certs : NULL))
+ goto err;
+ if (!finish_chain)
+ X509_STORE_CTX_set0_trusted_stack(ctx, certs);
+ if (!ossl_x509_add_cert_new(&ctx->chain, target, X509_ADD_FLAG_UP_REF)) {
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ goto err;
}
+ ctx->num_untrusted = 1;
+
+ if (!build_chain(ctx) && finish_chain)
+ goto err;
+
+ /* result list to store the up_ref'ed certificates */
+ if (sk_X509_num(ctx->chain) > 1 && !with_self_signed)
+ flags |= X509_ADD_FLAG_NO_SS;
+ if (!ossl_x509_add_certs_new(&result, ctx->chain, flags)) {
+ sk_X509_free(result);
+ result = NULL;
+ }
+
+ err:
+ X509_STORE_CTX_free(ctx);
+ return result;
}
+/*
+ * note that there's a corresponding minbits_table in ssl/ssl_cert.c
+ * in ssl_get_security_level_bits that's used for selection of DH parameters
+ */
static const int minbits_table[] = { 80, 112, 128, 192, 256 };
static const int NUM_AUTH_LEVELS = OSSL_NELEM(minbits_table);
-/*
- * Check whether the public key of ``cert`` meets the security level of
- * ``ctx``.
- *
+/*-
+ * Check whether the public key of `cert` meets the security level of `ctx`.
* Returns 1 on success, 0 otherwise.
*/
static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
@@ -3337,10 +3398,10 @@ static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
if (level > NUM_AUTH_LEVELS)
level = NUM_AUTH_LEVELS;
- return EVP_PKEY_security_bits(pkey) >= minbits_table[level - 1];
+ return EVP_PKEY_get_security_bits(pkey) >= minbits_table[level - 1];
}
-/*
+/*-
* Check whether the public key of ``cert`` does not use explicit params
* for an elliptic curve.
*
@@ -3348,25 +3409,25 @@ static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
*/
static int check_curve(X509 *cert)
{
-#ifndef OPENSSL_NO_EC
EVP_PKEY *pkey = X509_get0_pubkey(cert);
/* Unsupported or malformed key */
if (pkey == NULL)
return -1;
- if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
- int ret;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_EC) {
+ int ret, val;
- ret = EC_KEY_decoded_from_explicit_params(EVP_PKEY_get0_EC_KEY(pkey));
- return ret < 0 ? ret : !ret;
+ ret = EVP_PKEY_get_int_param(pkey,
+ OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS,
+ &val);
+ return ret == 1 ? !val : -1;
}
-#endif
return 1;
}
-/*
+/*-
* Check whether the signature digest algorithm of ``cert`` meets the security
* level of ``ctx``. Should not be checked for trust anchors (whether
* self-signed or otherwise).
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index 535f169a29e7..998ce8ac1ba1 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -1,7 +1,7 @@
/*
- * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -44,7 +44,8 @@ static int int_x509_param_set_hosts(X509_VERIFY_PARAM *vpm, int mode,
*/
if (namelen == 0 || name == NULL)
namelen = name ? strlen(name) : 0;
- else if (name && memchr(name, '\0', namelen > 1 ? namelen - 1 : namelen))
+ else if (name != NULL
+ && memchr(name, '\0', namelen > 1 ? namelen - 1 : namelen) != NULL)
return 0;
if (namelen > 0 && name[namelen - 1] == '\0')
--namelen;
@@ -78,14 +79,13 @@ static int int_x509_param_set_hosts(X509_VERIFY_PARAM *vpm, int mode,
return 1;
}
-
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
{
X509_VERIFY_PARAM *param;
param = OPENSSL_zalloc(sizeof(*param));
if (param == NULL) {
- X509err(X509_F_X509_VERIFY_PARAM_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
param->trust = X509_TRUST_DEFAULT;
@@ -142,39 +142,32 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
/* Macro to test if a field should be copied from src to dest */
#define test_x509_verify_param_copy(field, def) \
- (to_overwrite || \
- ((src->field != def) && (to_default || (dest->field == def))))
+ (to_overwrite || (src->field != def && (to_default || dest->field == def)))
/* Macro to test and copy a field if necessary */
#define x509_verify_param_copy(field, def) \
- if (test_x509_verify_param_copy(field, def)) \
- dest->field = src->field
+ if (test_x509_verify_param_copy(field, def)) \
+ dest->field = src->field;
int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
const X509_VERIFY_PARAM *src)
{
unsigned long inh_flags;
int to_default, to_overwrite;
- if (!src)
+
+ if (src == NULL)
return 1;
inh_flags = dest->inh_flags | src->inh_flags;
- if (inh_flags & X509_VP_FLAG_ONCE)
+ if ((inh_flags & X509_VP_FLAG_ONCE) != 0)
dest->inh_flags = 0;
- if (inh_flags & X509_VP_FLAG_LOCKED)
+ if ((inh_flags & X509_VP_FLAG_LOCKED) != 0)
return 1;
- if (inh_flags & X509_VP_FLAG_DEFAULT)
- to_default = 1;
- else
- to_default = 0;
-
- if (inh_flags & X509_VP_FLAG_OVERWRITE)
- to_overwrite = 1;
- else
- to_overwrite = 0;
+ to_default = (inh_flags & X509_VP_FLAG_DEFAULT) != 0;
+ to_overwrite = (inh_flags & X509_VP_FLAG_OVERWRITE) != 0;
x509_verify_param_copy(purpose, 0);
x509_verify_param_copy(trust, X509_TRUST_DEFAULT);
@@ -183,13 +176,13 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
/* If overwrite or check time not set, copy across */
- if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) {
+ if (to_overwrite || (dest->flags & X509_V_FLAG_USE_CHECK_TIME) == 0) {
dest->check_time = src->check_time;
dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME;
/* Don't need to copy flag: that is done below */
}
- if (inh_flags & X509_VP_FLAG_RESET_FLAGS)
+ if ((inh_flags & X509_VP_FLAG_RESET_FLAGS) != 0)
dest->flags = 0;
dest->flags |= src->flags;
@@ -204,7 +197,7 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
if (test_x509_verify_param_copy(hosts, NULL)) {
sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
dest->hosts = NULL;
- if (src->hosts) {
+ if (src->hosts != NULL) {
dest->hosts =
sk_OPENSSL_STRING_deep_copy(src->hosts, str_copy, str_free);
if (dest->hosts == NULL)
@@ -228,8 +221,14 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
const X509_VERIFY_PARAM *from)
{
- unsigned long save_flags = to->inh_flags;
+ unsigned long save_flags;
int ret;
+
+ if (to == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ save_flags = to->inh_flags;
to->inh_flags |= X509_VP_FLAG_DEFAULT;
ret = X509_VERIFY_PARAM_inherit(to, from);
to->inh_flags = save_flags;
@@ -239,14 +238,17 @@ int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
static int int_x509_param_set1(char **pdest, size_t *pdestlen,
const char *src, size_t srclen)
{
- void *tmp;
- if (src) {
+ char *tmp;
+
+ if (src != NULL) {
if (srclen == 0)
srclen = strlen(src);
- tmp = OPENSSL_memdup(src, srclen);
+ tmp = OPENSSL_malloc(srclen + 1);
if (tmp == NULL)
return 0;
+ memcpy(tmp, src, srclen);
+ tmp[srclen] = '\0'; /* enforce NUL termination */
} else {
tmp = NULL;
srclen = 0;
@@ -262,15 +264,13 @@ int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
{
OPENSSL_free(param->name);
param->name = OPENSSL_strdup(name);
- if (param->name)
- return 1;
- return 0;
+ return param->name != NULL;
}
int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags)
{
param->flags |= flags;
- if (flags & X509_V_FLAG_POLICY_MASK)
+ if ((flags & X509_V_FLAG_POLICY_MASK) != 0)
param->flags |= X509_V_FLAG_POLICY_CHECK;
return 1;
}
@@ -282,7 +282,7 @@ int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
return 1;
}
-unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param)
+unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param)
{
return param->flags;
}
@@ -332,12 +332,13 @@ void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t)
int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
ASN1_OBJECT *policy)
{
- if (!param->policies) {
+ if (param->policies == NULL) {
param->policies = sk_ASN1_OBJECT_new_null();
- if (!param->policies)
+ if (param->policies == NULL)
return 0;
}
- if (!sk_ASN1_OBJECT_push(param->policies, policy))
+
+ if (sk_ASN1_OBJECT_push(param->policies, policy) <= 0)
return 0;
return 1;
}
@@ -348,23 +349,25 @@ int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
int i;
ASN1_OBJECT *oid, *doid;
- if (!param)
+ if (param == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
return 0;
+ }
sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
- if (!policies) {
+ if (policies == NULL) {
param->policies = NULL;
return 1;
}
param->policies = sk_ASN1_OBJECT_new_null();
- if (!param->policies)
+ if (param->policies == NULL)
return 0;
for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) {
oid = sk_ASN1_OBJECT_value(policies, i);
doid = OBJ_dup(oid);
- if (!doid)
+ if (doid == NULL)
return 0;
if (!sk_ASN1_OBJECT_push(param->policies, doid)) {
ASN1_OBJECT_free(doid);
@@ -375,6 +378,11 @@ int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
return 1;
}
+char *X509_VERIFY_PARAM_get0_host(X509_VERIFY_PARAM *param, int idx)
+{
+ return sk_OPENSSL_STRING_value(param->hosts, idx);
+}
+
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
{
@@ -398,7 +406,7 @@ unsigned int X509_VERIFY_PARAM_get_hostflags(const X509_VERIFY_PARAM *param)
return param->hostflags;
}
-char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param)
+char *X509_VERIFY_PARAM_get0_peername(const X509_VERIFY_PARAM *param)
{
return param->peername;
}
@@ -417,10 +425,15 @@ void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *to,
OPENSSL_free(to->peername);
to->peername = peername;
}
- if (from)
+ if (from != NULL)
from->peername = NULL;
}
+char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param)
+{
+ return param->email;
+}
+
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen)
{
@@ -428,11 +441,33 @@ int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
email, emaillen);
}
+static unsigned char
+*int_X509_VERIFY_PARAM_get0_ip(X509_VERIFY_PARAM *param, size_t *plen)
+{
+ if (param == NULL || param->ip == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ if (plen != NULL)
+ *plen = param->iplen;
+ return param->ip;
+}
+
+char *X509_VERIFY_PARAM_get1_ip_asc(X509_VERIFY_PARAM *param)
+{
+ size_t iplen;
+ unsigned char *ip = int_X509_VERIFY_PARAM_get0_ip(param, &iplen);
+
+ return ip == NULL ? NULL : ossl_ipaddr_to_asc(ip, iplen);
+}
+
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen)
{
- if (iplen != 0 && iplen != 4 && iplen != 16)
+ if (iplen != 0 && iplen != 4 && iplen != 16) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
+ }
return int_x509_param_set1((char **)&param->ip, &param->iplen,
(char *)ip, iplen);
}
@@ -440,9 +475,8 @@ int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
{
unsigned char ipout[16];
- size_t iplen;
+ size_t iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
- iplen = (size_t)a2i_ipadd(ipout, ipasc);
if (iplen == 0)
return 0;
return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
@@ -474,8 +508,8 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
static const X509_VERIFY_PARAM default_table[] = {
{
"default", /* X509 default parameters */
- 0, /* Check time */
- 0, /* internal flags */
+ 0, /* check time to use */
+ 0, /* inheritance flags */
X509_V_FLAG_TRUSTED_FIRST, /* flags */
0, /* purpose */
0, /* trust */
@@ -485,8 +519,8 @@ static const X509_VERIFY_PARAM default_table[] = {
vpm_empty_id},
{
"pkcs7", /* S/MIME sign parameters */
- 0, /* Check time */
- 0, /* internal flags */
+ 0, /* check time to use */
+ 0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
@@ -496,8 +530,8 @@ static const X509_VERIFY_PARAM default_table[] = {
vpm_empty_id},
{
"smime_sign", /* S/MIME sign parameters */
- 0, /* Check time */
- 0, /* internal flags */
+ 0, /* check time to use */
+ 0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
@@ -507,8 +541,8 @@ static const X509_VERIFY_PARAM default_table[] = {
vpm_empty_id},
{
"ssl_client", /* SSL/TLS client parameters */
- 0, /* Check time */
- 0, /* internal flags */
+ 0, /* check time to use */
+ 0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SSL_CLIENT, /* purpose */
X509_TRUST_SSL_CLIENT, /* trust */
@@ -518,8 +552,8 @@ static const X509_VERIFY_PARAM default_table[] = {
vpm_empty_id},
{
"ssl_server", /* SSL/TLS server parameters */
- 0, /* Check time */
- 0, /* internal flags */
+ 0, /* check time to use */
+ 0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SSL_SERVER, /* purpose */
X509_TRUST_SSL_SERVER, /* trust */
@@ -549,6 +583,7 @@ int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
{
int idx;
X509_VERIFY_PARAM *ptmp;
+
if (param_table == NULL) {
param_table = sk_X509_VERIFY_PARAM_new(param_cmp);
if (param_table == NULL)
@@ -560,7 +595,8 @@ int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
X509_VERIFY_PARAM_free(ptmp);
}
}
- if (!sk_X509_VERIFY_PARAM_push(param_table, param))
+
+ if (sk_X509_VERIFY_PARAM_push(param_table, param) <= 0)
return 0;
return 1;
}
@@ -568,7 +604,8 @@ int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
int X509_VERIFY_PARAM_get_count(void)
{
int num = OSSL_NELEM(default_table);
- if (param_table)
+
+ if (param_table != NULL)
num += sk_X509_VERIFY_PARAM_num(param_table);
return num;
}
@@ -576,6 +613,7 @@ int X509_VERIFY_PARAM_get_count(void)
const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id)
{
int num = OSSL_NELEM(default_table);
+
if (id < num)
return default_table + id;
return sk_X509_VERIFY_PARAM_value(param_table, id - num);
diff --git a/crypto/x509/x509cset.c b/crypto/x509/x509cset.c
index 6c08509138d5..2746b9892506 100644
--- a/crypto/x509/x509cset.c
+++ b/crypto/x509/x509cset.c
@@ -1,7 +1,7 @@
/*
- * Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -27,7 +27,7 @@ int X509_CRL_set_version(X509_CRL *x, long version)
return ASN1_INTEGER_set(x->crl.version, version);
}
-int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)
+int X509_CRL_set_issuer_name(X509_CRL *x, const X509_NAME *name)
{
if (x == NULL)
return 0;
@@ -38,14 +38,14 @@ int X509_CRL_set1_lastUpdate(X509_CRL *x, const ASN1_TIME *tm)
{
if (x == NULL)
return 0;
- return x509_set1_time(&x->crl.lastUpdate, tm);
+ return ossl_x509_set1_time(&x->crl.lastUpdate, tm);
}
int X509_CRL_set1_nextUpdate(X509_CRL *x, const ASN1_TIME *tm)
{
if (x == NULL)
return 0;
- return x509_set1_time(&x->crl.nextUpdate, tm);
+ return ossl_x509_set1_time(&x->crl.nextUpdate, tm);
}
int X509_CRL_sort(X509_CRL *c)
@@ -91,7 +91,7 @@ const ASN1_TIME *X509_CRL_get0_nextUpdate(const X509_CRL *crl)
return crl->crl.nextUpdate;
}
-#if OPENSSL_API_COMPAT < 0x10100000L
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl)
{
return crl->crl.lastUpdate;
diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c
index c86d8e7914f1..9ae0dc5de48f 100644
--- a/crypto/x509/x509name.c
+++ b/crypto/x509/x509name.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -16,7 +16,8 @@
#include <openssl/x509.h>
#include "crypto/x509.h"
-int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len)
+int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid,
+ char *buf, int len)
{
ASN1_OBJECT *obj;
@@ -26,7 +27,7 @@ int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len)
return X509_NAME_get_text_by_OBJ(name, obj, buf, len);
}
-int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
+int X509_NAME_get_text_by_OBJ(const X509_NAME *name, const ASN1_OBJECT *obj,
char *buf, int len)
{
int i;
@@ -48,12 +49,15 @@ int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
int X509_NAME_entry_count(const X509_NAME *name)
{
+ int ret;
+
if (name == NULL)
return 0;
- return sk_X509_NAME_ENTRY_num(name->entries);
+ ret = sk_X509_NAME_ENTRY_num(name->entries);
+ return ret > 0 ? ret : 0;
}
-int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos)
+int X509_NAME_get_index_by_NID(const X509_NAME *name, int nid, int lastpos)
{
ASN1_OBJECT *obj;
@@ -64,7 +68,8 @@ int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos)
}
/* NOTE: you should be passing -1, not 0 as lastpos */
-int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int lastpos)
+int X509_NAME_get_index_by_OBJ(const X509_NAME *name, const ASN1_OBJECT *obj,
+ int lastpos)
{
int n;
X509_NAME_ENTRY *ne;
@@ -216,15 +221,11 @@ int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *ne, int loc,
set = sk_X509_NAME_ENTRY_value(sk, loc)->set;
}
- /*
- * X509_NAME_ENTRY_dup is ASN1 generated code, that can't be easily
- * const'ified; harmless cast since dup() don't modify its input.
- */
- if ((new_name = X509_NAME_ENTRY_dup((X509_NAME_ENTRY *)ne)) == NULL)
+ if ((new_name = X509_NAME_ENTRY_dup(ne)) == NULL)
goto err;
new_name->set = set;
if (!sk_X509_NAME_ENTRY_insert(sk, new_name, loc)) {
- X509err(X509_F_X509_NAME_ADD_ENTRY, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if (inc) {
@@ -248,9 +249,8 @@ X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne,
obj = OBJ_txt2obj(field, 0);
if (obj == NULL) {
- X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_TXT,
- X509_R_INVALID_FIELD_NAME);
- ERR_add_error_data(2, "name=", field);
+ ERR_raise_data(ERR_LIB_X509, X509_R_INVALID_FIELD_NAME,
+ "name=%s", field);
return NULL;
}
nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len);
@@ -268,7 +268,7 @@ X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid,
obj = OBJ_nid2obj(nid);
if (obj == NULL) {
- X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_NID, X509_R_UNKNOWN_NID);
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_NID);
return NULL;
}
nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len);
@@ -306,8 +306,7 @@ X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne,
int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj)
{
if ((ne == NULL) || (obj == NULL)) {
- X509err(X509_F_X509_NAME_ENTRY_SET_OBJECT,
- ERR_R_PASSED_NULL_PARAMETER);
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ASN1_OBJECT_free(ne->object);
diff --git a/crypto/x509/x509rset.c b/crypto/x509/x509rset.c
index 9da3f2ee27df..344993d4c78c 100644
--- a/crypto/x509/x509rset.c
+++ b/crypto/x509/x509rset.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -23,7 +23,7 @@ int X509_REQ_set_version(X509_REQ *x, long version)
return ASN1_INTEGER_set(x->req_info.version, version);
}
-int X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name)
+int X509_REQ_set_subject_name(X509_REQ *x, const X509_NAME *name)
{
if (x == NULL)
return 0;
diff --git a/crypto/x509/x509spki.c b/crypto/x509/x509spki.c
index fd8162af6df2..1d66697db00d 100644
--- a/crypto/x509/x509spki.c
+++ b/crypto/x509/x509spki.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -36,12 +36,12 @@ NETSCAPE_SPKI *NETSCAPE_SPKI_b64_decode(const char *str, int len)
if (len <= 0)
len = strlen(str);
if ((spki_der = OPENSSL_malloc(len + 1)) == NULL) {
- X509err(X509_F_NETSCAPE_SPKI_B64_DECODE, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
spki_len = EVP_DecodeBlock(spki_der, (const unsigned char *)str, len);
if (spki_len < 0) {
- X509err(X509_F_NETSCAPE_SPKI_B64_DECODE, X509_R_BASE64_DECODE_ERROR);
+ ERR_raise(ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR);
OPENSSL_free(spki_der);
return NULL;
}
@@ -58,11 +58,14 @@ char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki)
unsigned char *der_spki, *p;
char *b64_str;
int der_len;
+
der_len = i2d_NETSCAPE_SPKI(spki, NULL);
+ if (der_len <= 0)
+ return NULL;
der_spki = OPENSSL_malloc(der_len);
b64_str = OPENSSL_malloc(der_len * 2);
if (der_spki == NULL || b64_str == NULL) {
- X509err(X509_F_NETSCAPE_SPKI_B64_ENCODE, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
OPENSSL_free(der_spki);
OPENSSL_free(b64_str);
return NULL;
diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
index 0e33b424be51..79fd5e7db609 100644
--- a/crypto/x509/x509type.c
+++ b/crypto/x509/x509type.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -29,7 +29,7 @@ int X509_certificate_type(const X509 *x, const EVP_PKEY *pkey)
if (pk == NULL)
return 0;
- switch (EVP_PKEY_id(pk)) {
+ switch (EVP_PKEY_get_id(pk)) {
case EVP_PKEY_RSA:
ret = EVP_PK_RSA | EVP_PKT_SIGN;
/* if (!sign only extension) */
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index fcf6b5ba3780..158e11a8649c 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -1,46 +1,69 @@
/*
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
*/
+/*
+ * Low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/buffer.h>
#include <openssl/asn1.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
-#include "crypto/x509.h"
-#include <openssl/ocsp.h>
+#include <openssl/http.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/x509v3.h>
+#include "internal/asn1.h"
+#include "crypto/pkcs7.h"
+#include "crypto/x509.h"
+#include "crypto/rsa.h"
int X509_verify(X509 *a, EVP_PKEY *r)
{
- if (X509_ALGOR_cmp(&a->sig_alg, &a->cert_info.signature))
+ if (X509_ALGOR_cmp(&a->sig_alg, &a->cert_info.signature) != 0)
return 0;
- return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), &a->sig_alg,
- &a->signature, &a->cert_info, r));
+
+ return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_CINF), &a->sig_alg,
+ &a->signature, &a->cert_info,
+ a->distinguishing_id, r, a->libctx, a->propq);
+}
+
+int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *r, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_REQ_INFO), &a->sig_alg,
+ a->signature, &a->req_info, a->distinguishing_id,
+ r, libctx, propq);
}
int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
{
- return (ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO),
- &a->sig_alg, a->signature, &a->req_info, r));
+ return X509_REQ_verify_ex(a, r, NULL, NULL);
}
int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r)
{
- return (ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC),
- &a->sig_algor, a->signature, a->spkac, r));
+ return ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC),
+ &a->sig_algor, a->signature, a->spkac, r);
}
int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
/*
* Setting the modified flag before signing it. This makes the cached
* encoding to be ignored, so even if the certificate fields have changed,
@@ -49,36 +72,63 @@ int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
* which exist below are the same.
*/
x->cert_info.enc.modified = 1;
- return (ASN1_item_sign(ASN1_ITEM_rptr(X509_CINF), &x->cert_info.signature,
- &x->sig_alg, &x->signature, &x->cert_info, pkey,
- md));
+ return ASN1_item_sign_ex(ASN1_ITEM_rptr(X509_CINF), &x->cert_info.signature,
+ &x->sig_alg, &x->signature, &x->cert_info, NULL,
+ pkey, md, x->libctx, x->propq);
}
int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
x->cert_info.enc.modified = 1;
return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CINF),
&x->cert_info.signature,
&x->sig_alg, &x->signature, &x->cert_info, ctx);
}
-#ifndef OPENSSL_NO_OCSP
-int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert)
+static ASN1_VALUE *simple_get_asn1(const char *url, BIO *bio, BIO *rbio,
+ int timeout, const ASN1_ITEM *it)
{
- return OCSP_REQ_CTX_nbio_d2i(rctx,
- (ASN1_VALUE **)pcert, ASN1_ITEM_rptr(X509));
+ size_t max_resp_len = (it == ASN1_ITEM_rptr(X509_CRL)) ?
+ OSSL_HTTP_DEFAULT_MAX_CRL_LEN : OSSL_HTTP_DEFAULT_MAX_RESP_LEN;
+ BIO *mem = OSSL_HTTP_get(url, NULL /* proxy */, NULL /* no_proxy */,
+ bio, rbio, NULL /* cb */, NULL /* arg */,
+ 1024 /* buf_size */, NULL /* headers */,
+ NULL /* expected_ct */, 1 /* expect_asn1 */,
+ max_resp_len, timeout);
+ ASN1_VALUE *res = ASN1_item_d2i_bio(it, mem, NULL);
+
+ BIO_free(mem);
+ return res;
+}
+
+X509 *X509_load_http(const char *url, BIO *bio, BIO *rbio, int timeout)
+{
+ return (X509 *)simple_get_asn1(url, bio, rbio, timeout,
+ ASN1_ITEM_rptr(X509));
}
-#endif
int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
x->req_info.enc.modified = 1;
- return (ASN1_item_sign(ASN1_ITEM_rptr(X509_REQ_INFO), &x->sig_alg, NULL,
- x->signature, &x->req_info, pkey, md));
+ return ASN1_item_sign_ex(ASN1_ITEM_rptr(X509_REQ_INFO), &x->sig_alg, NULL,
+ x->signature, &x->req_info, NULL,
+ pkey, md, x->libctx, x->propq);
}
int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
x->req_info.enc.modified = 1;
return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_REQ_INFO),
&x->sig_alg, NULL, x->signature, &x->req_info,
@@ -87,32 +137,39 @@ int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx)
int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
x->crl.enc.modified = 1;
- return (ASN1_item_sign(ASN1_ITEM_rptr(X509_CRL_INFO), &x->crl.sig_alg,
- &x->sig_alg, &x->signature, &x->crl, pkey, md));
+ return ASN1_item_sign_ex(ASN1_ITEM_rptr(X509_CRL_INFO), &x->crl.sig_alg,
+ &x->sig_alg, &x->signature, &x->crl, NULL,
+ pkey, md, x->libctx, x->propq);
}
int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx)
{
+ if (x == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
x->crl.enc.modified = 1;
return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CRL_INFO),
&x->crl.sig_alg, &x->sig_alg, &x->signature,
&x->crl, ctx);
}
-#ifndef OPENSSL_NO_OCSP
-int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl)
+X509_CRL *X509_CRL_load_http(const char *url, BIO *bio, BIO *rbio, int timeout)
{
- return OCSP_REQ_CTX_nbio_d2i(rctx,
- (ASN1_VALUE **)pcrl,
- ASN1_ITEM_rptr(X509_CRL));
+ return (X509_CRL *)simple_get_asn1(url, bio, rbio, timeout,
+ ASN1_ITEM_rptr(X509_CRL));
}
-#endif
int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md)
{
- return (ASN1_item_sign(ASN1_ITEM_rptr(NETSCAPE_SPKAC), &x->sig_algor, NULL,
- x->signature, x->spkac, pkey, md));
+ return
+ ASN1_item_sign_ex(ASN1_ITEM_rptr(NETSCAPE_SPKAC), &x->sig_algor, NULL,
+ x->signature, x->spkac, NULL, pkey, md, NULL, NULL);
}
#ifndef OPENSSL_NO_STDIO
@@ -121,7 +178,7 @@ X509 *d2i_X509_fp(FILE *fp, X509 **x509)
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509);
}
-int i2d_X509_fp(FILE *fp, X509 *x509)
+int i2d_X509_fp(FILE *fp, const X509 *x509)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509);
}
@@ -132,7 +189,7 @@ X509 *d2i_X509_bio(BIO *bp, X509 **x509)
return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509), bp, x509);
}
-int i2d_X509_bio(BIO *bp, X509 *x509)
+int i2d_X509_bio(BIO *bp, const X509 *x509)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509);
}
@@ -143,7 +200,7 @@ X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl)
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
}
-int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl)
+int i2d_X509_CRL_fp(FILE *fp, const X509_CRL *crl)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
}
@@ -154,7 +211,7 @@ X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl)
return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl);
}
-int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl)
+int i2d_X509_CRL_bio(BIO *bp, const X509_CRL *crl)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl);
}
@@ -162,10 +219,22 @@ int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl)
#ifndef OPENSSL_NO_STDIO
PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7)
{
- return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7);
+ PKCS7 *ret;
+ OSSL_LIB_CTX *libctx = NULL;
+ const char *propq = NULL;
+
+ if (p7 != NULL && *p7 != NULL) {
+ libctx = (*p7)->ctx.libctx;
+ propq = (*p7)->ctx.propq;
+ }
+
+ ret = ASN1_item_d2i_fp_ex(ASN1_ITEM_rptr(PKCS7), fp, p7, libctx, propq);
+ if (ret != NULL)
+ ossl_pkcs7_resolve_libctx(ret);
+ return ret;
}
-int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7)
+int i2d_PKCS7_fp(FILE *fp, const PKCS7 *p7)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS7), fp, p7);
}
@@ -173,10 +242,22 @@ int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7)
PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7)
{
- return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7);
+ PKCS7 *ret;
+ OSSL_LIB_CTX *libctx = NULL;
+ const char *propq = NULL;
+
+ if (p7 != NULL && *p7 != NULL) {
+ libctx = (*p7)->ctx.libctx;
+ propq = (*p7)->ctx.propq;
+ }
+
+ ret = ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(PKCS7), bp, p7, libctx, propq);
+ if (ret != NULL)
+ ossl_pkcs7_resolve_libctx(ret);
+ return ret;
}
-int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7)
+int i2d_PKCS7_bio(BIO *bp, const PKCS7 *p7)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS7), bp, p7);
}
@@ -187,7 +268,7 @@ X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req)
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
}
-int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req)
+int i2d_X509_REQ_fp(FILE *fp, const X509_REQ *req)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
}
@@ -195,23 +276,29 @@ int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req)
X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req)
{
- return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
+ OSSL_LIB_CTX *libctx = NULL;
+ const char *propq = NULL;
+
+ if (req != NULL && *req != NULL) {
+ libctx = (*req)->libctx;
+ propq = (*req)->propq;
+ }
+
+ return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(X509_REQ), bp, req, libctx, propq);
}
-int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req)
+int i2d_X509_REQ_bio(BIO *bp, const X509_REQ *req)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
}
-#ifndef OPENSSL_NO_RSA
-
-# ifndef OPENSSL_NO_STDIO
+#ifndef OPENSSL_NO_STDIO
RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa)
{
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
}
-int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa)
+int i2d_RSAPrivateKey_fp(FILE *fp, const RSA *rsa)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
}
@@ -228,23 +315,23 @@ RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa)
(void **)rsa);
}
-int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa)
+int i2d_RSAPublicKey_fp(FILE *fp, const RSA *rsa)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa);
}
-int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa)
+int i2d_RSA_PUBKEY_fp(FILE *fp, const RSA *rsa)
{
return ASN1_i2d_fp((I2D_OF(void))i2d_RSA_PUBKEY, fp, rsa);
}
-# endif
+#endif
RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)
{
return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
}
-int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)
+int i2d_RSAPrivateKey_bio(BIO *bp, const RSA *rsa)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
}
@@ -259,16 +346,15 @@ RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa)
return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSA_PUBKEY, bp, rsa);
}
-int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)
+int i2d_RSAPublicKey_bio(BIO *bp, const RSA *rsa)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
}
-int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa)
+int i2d_RSA_PUBKEY_bio(BIO *bp, const RSA *rsa)
{
return ASN1_i2d_bio_of(RSA, i2d_RSA_PUBKEY, bp, rsa);
}
-#endif
#ifndef OPENSSL_NO_DSA
# ifndef OPENSSL_NO_STDIO
@@ -277,9 +363,9 @@ DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa)
return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSAPrivateKey, fp, dsa);
}
-int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa)
+int i2d_DSAPrivateKey_fp(FILE *fp, const DSA *dsa)
{
- return ASN1_i2d_fp_of_const(DSA, i2d_DSAPrivateKey, fp, dsa);
+ return ASN1_i2d_fp_of(DSA, i2d_DSAPrivateKey, fp, dsa);
}
DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa)
@@ -287,7 +373,7 @@ DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa)
return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSA_PUBKEY, fp, dsa);
}
-int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa)
+int i2d_DSA_PUBKEY_fp(FILE *fp, const DSA *dsa)
{
return ASN1_i2d_fp_of(DSA, i2d_DSA_PUBKEY, fp, dsa);
}
@@ -298,9 +384,9 @@ DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSAPrivateKey, bp, dsa);
}
-int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa)
+int i2d_DSAPrivateKey_bio(BIO *bp, const DSA *dsa)
{
- return ASN1_i2d_bio_of_const(DSA, i2d_DSAPrivateKey, bp, dsa);
+ return ASN1_i2d_bio_of(DSA, i2d_DSAPrivateKey, bp, dsa);
}
DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa)
@@ -308,7 +394,7 @@ DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa)
return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSA_PUBKEY, bp, dsa);
}
-int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa)
+int i2d_DSA_PUBKEY_bio(BIO *bp, const DSA *dsa)
{
return ASN1_i2d_bio_of(DSA, i2d_DSA_PUBKEY, bp, dsa);
}
@@ -322,7 +408,7 @@ EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey)
return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, fp, eckey);
}
-int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey)
+int i2d_EC_PUBKEY_fp(FILE *fp, const EC_KEY *eckey)
{
return ASN1_i2d_fp_of(EC_KEY, i2d_EC_PUBKEY, fp, eckey);
}
@@ -332,7 +418,7 @@ EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey)
return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, fp, eckey);
}
-int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey)
+int i2d_ECPrivateKey_fp(FILE *fp, const EC_KEY *eckey)
{
return ASN1_i2d_fp_of(EC_KEY, i2d_ECPrivateKey, fp, eckey);
}
@@ -342,7 +428,7 @@ EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey)
return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, bp, eckey);
}
-int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa)
+int i2d_EC_PUBKEY_bio(BIO *bp, const EC_KEY *ecdsa)
{
return ASN1_i2d_bio_of(EC_KEY, i2d_EC_PUBKEY, bp, ecdsa);
}
@@ -352,7 +438,7 @@ EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey)
return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, bp, eckey);
}
-int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey)
+int i2d_ECPrivateKey_bio(BIO *bp, const EC_KEY *eckey)
{
return ASN1_i2d_bio_of(EC_KEY, i2d_ECPrivateKey, bp, eckey);
}
@@ -361,63 +447,160 @@ int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey)
int X509_pubkey_digest(const X509 *data, const EVP_MD *type,
unsigned char *md, unsigned int *len)
{
- ASN1_BIT_STRING *key;
- key = X509_get0_pubkey_bitstr(data);
- if (!key)
+ ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(data);
+
+ if (key == NULL)
return 0;
return EVP_Digest(key->data, key->length, md, len, type, NULL);
}
-int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
+int X509_digest(const X509 *cert, const EVP_MD *md, unsigned char *data,
unsigned int *len)
{
- if (type == EVP_sha1() && (data->ex_flags & EXFLAG_SET) != 0
- && (data->ex_flags & EXFLAG_NO_FINGERPRINT) == 0) {
+ if (EVP_MD_is_a(md, SN_sha1) && (cert->ex_flags & EXFLAG_SET) != 0
+ && (cert->ex_flags & EXFLAG_NO_FINGERPRINT) == 0) {
/* Asking for SHA1 and we already computed it. */
if (len != NULL)
- *len = sizeof(data->sha1_hash);
- memcpy(md, data->sha1_hash, sizeof(data->sha1_hash));
+ *len = sizeof(cert->sha1_hash);
+ memcpy(data, cert->sha1_hash, sizeof(cert->sha1_hash));
return 1;
}
- return (ASN1_item_digest
- (ASN1_ITEM_rptr(X509), type, (char *)data, md, len));
+ return ossl_asn1_item_digest_ex(ASN1_ITEM_rptr(X509), md, (char *)cert,
+ data, len, cert->libctx, cert->propq);
+}
+
+/* calculate cert digest using the same hash algorithm as in its signature */
+ASN1_OCTET_STRING *X509_digest_sig(const X509 *cert,
+ EVP_MD **md_used, int *md_is_fallback)
+{
+ unsigned int len;
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ int mdnid, pknid;
+ EVP_MD *md = NULL;
+ const char *md_name;
+ ASN1_OCTET_STRING *new;
+
+ if (md_used != NULL)
+ *md_used = NULL;
+ if (md_is_fallback != NULL)
+ *md_is_fallback = 0;
+
+ if (cert == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if (!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &mdnid, &pknid)) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_SIGID_ALGS);
+ return NULL;
+ }
+
+ if (mdnid == NID_undef) {
+ if (pknid == EVP_PKEY_RSA_PSS) {
+ RSA_PSS_PARAMS *pss = ossl_rsa_pss_decode(&cert->sig_alg);
+ const EVP_MD *mgf1md, *mmd = NULL;
+ int saltlen, trailerfield;
+
+ if (pss == NULL
+ || !ossl_rsa_pss_get_param_unverified(pss, &mmd, &mgf1md,
+ &saltlen,
+ &trailerfield)
+ || mmd == NULL) {
+ RSA_PSS_PARAMS_free(pss);
+ ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
+ return NULL;
+ }
+ RSA_PSS_PARAMS_free(pss);
+ /* Fetch explicitly and do not fallback */
+ if ((md = EVP_MD_fetch(cert->libctx, EVP_MD_get0_name(mmd),
+ cert->propq)) == NULL)
+ /* Error code from fetch is sufficient */
+ return NULL;
+ } else if (pknid != NID_undef) {
+ /* A known algorithm, but without a digest */
+ switch (pknid) {
+ case NID_ED25519: /* Follow CMS default given in RFC8419 */
+ md_name = "SHA512";
+ break;
+ case NID_ED448: /* Follow CMS default given in RFC8419 */
+ md_name = "SHAKE256";
+ break;
+ default: /* Fall back to SHA-256 */
+ md_name = "SHA256";
+ break;
+ }
+ if ((md = EVP_MD_fetch(cert->libctx, md_name,
+ cert->propq)) == NULL)
+ return NULL;
+ if (md_is_fallback != NULL)
+ *md_is_fallback = 1;
+ } else {
+ /* A completely unknown algorithm */
+ ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
+ return NULL;
+ }
+ } else if ((md = EVP_MD_fetch(cert->libctx, OBJ_nid2sn(mdnid),
+ cert->propq)) == NULL
+ && (md = (EVP_MD *)EVP_get_digestbynid(mdnid)) == NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
+ return NULL;
+ }
+ if (!X509_digest(cert, md, hash, &len)
+ || (new = ASN1_OCTET_STRING_new()) == NULL)
+ goto err;
+ if (ASN1_OCTET_STRING_set(new, hash, len)) {
+ if (md_used != NULL)
+ *md_used = md;
+ else
+ EVP_MD_free(md);
+ return new;
+ }
+ ASN1_OCTET_STRING_free(new);
+ err:
+ EVP_MD_free(md);
+ return NULL;
}
int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type,
unsigned char *md, unsigned int *len)
{
- if (type == EVP_sha1() && (data->flags & EXFLAG_SET) != 0
- && (data->flags & EXFLAG_INVALID) == 0) {
+ if (type == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (EVP_MD_is_a(type, SN_sha1)
+ && (data->flags & EXFLAG_SET) != 0
+ && (data->flags & EXFLAG_NO_FINGERPRINT) == 0) {
/* Asking for SHA1; always computed in CRL d2i. */
if (len != NULL)
*len = sizeof(data->sha1_hash);
memcpy(md, data->sha1_hash, sizeof(data->sha1_hash));
return 1;
}
- return (ASN1_item_digest
- (ASN1_ITEM_rptr(X509_CRL), type, (char *)data, md, len));
+ return ossl_asn1_item_digest_ex(ASN1_ITEM_rptr(X509_CRL), type, (char *)data,
+ md, len, data->libctx, data->propq);
}
int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type,
unsigned char *md, unsigned int *len)
{
- return (ASN1_item_digest
- (ASN1_ITEM_rptr(X509_REQ), type, (char *)data, md, len));
+ return ossl_asn1_item_digest_ex(ASN1_ITEM_rptr(X509_REQ), type, (char *)data,
+ md, len, data->libctx, data->propq);
}
int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type,
unsigned char *md, unsigned int *len)
{
- return (ASN1_item_digest
- (ASN1_ITEM_rptr(X509_NAME), type, (char *)data, md, len));
+ return ASN1_item_digest(ASN1_ITEM_rptr(X509_NAME), type, (char *)data,
+ md, len);
}
int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,
const EVP_MD *type, unsigned char *md,
unsigned int *len)
{
- return (ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL), type,
- (char *)data, md, len));
+ return ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL), type,
+ (char *)data, md, len);
}
#ifndef OPENSSL_NO_STDIO
@@ -426,7 +609,7 @@ X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8)
return ASN1_d2i_fp_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, fp, p8);
}
-int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8)
+int i2d_PKCS8_fp(FILE *fp, const X509_SIG *p8)
{
return ASN1_i2d_fp_of(X509_SIG, i2d_X509_SIG, fp, p8);
}
@@ -437,12 +620,36 @@ X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8)
return ASN1_d2i_bio_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, bp, p8);
}
-int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8)
+int i2d_PKCS8_bio(BIO *bp, const X509_SIG *p8)
{
return ASN1_i2d_bio_of(X509_SIG, i2d_X509_SIG, bp, p8);
}
#ifndef OPENSSL_NO_STDIO
+X509_PUBKEY *d2i_X509_PUBKEY_fp(FILE *fp, X509_PUBKEY **xpk)
+{
+ return ASN1_d2i_fp_of(X509_PUBKEY, X509_PUBKEY_new, d2i_X509_PUBKEY,
+ fp, xpk);
+}
+
+int i2d_X509_PUBKEY_fp(FILE *fp, const X509_PUBKEY *xpk)
+{
+ return ASN1_i2d_fp_of(X509_PUBKEY, i2d_X509_PUBKEY, fp, xpk);
+}
+#endif
+
+X509_PUBKEY *d2i_X509_PUBKEY_bio(BIO *bp, X509_PUBKEY **xpk)
+{
+ return ASN1_d2i_bio_of(X509_PUBKEY, X509_PUBKEY_new, d2i_X509_PUBKEY,
+ bp, xpk);
+}
+
+int i2d_X509_PUBKEY_bio(BIO *bp, const X509_PUBKEY *xpk)
+{
+ return ASN1_i2d_bio_of(X509_PUBKEY, i2d_X509_PUBKEY, bp, xpk);
+}
+
+#ifndef OPENSSL_NO_STDIO
PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
PKCS8_PRIV_KEY_INFO **p8inf)
{
@@ -450,25 +657,26 @@ PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
d2i_PKCS8_PRIV_KEY_INFO, fp, p8inf);
}
-int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf)
+int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, const PKCS8_PRIV_KEY_INFO *p8inf)
{
return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, fp,
p8inf);
}
-int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key)
+int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, const EVP_PKEY *key)
{
PKCS8_PRIV_KEY_INFO *p8inf;
int ret;
+
p8inf = EVP_PKEY2PKCS8(key);
- if (!p8inf)
+ if (p8inf == NULL)
return 0;
ret = i2d_PKCS8_PRIV_KEY_INFO_fp(fp, p8inf);
PKCS8_PRIV_KEY_INFO_free(p8inf);
return ret;
}
-int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey)
+int i2d_PrivateKey_fp(FILE *fp, const EVP_PKEY *pkey)
{
return ASN1_i2d_fp_of(EVP_PKEY, i2d_PrivateKey, fp, pkey);
}
@@ -478,7 +686,23 @@ EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a)
return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, fp, a);
}
-int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey)
+EVP_PKEY *d2i_PrivateKey_ex_fp(FILE *fp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ BIO *b;
+ void *ret;
+
+ if ((b = BIO_new(BIO_s_file())) == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
+ return NULL;
+ }
+ BIO_set_fp(b, fp, BIO_NOCLOSE);
+ ret = d2i_PrivateKey_ex_bio(b, a, libctx, propq);
+ BIO_free(b);
+ return ret;
+}
+
+int i2d_PUBKEY_fp(FILE *fp, const EVP_PKEY *pkey)
{
return ASN1_i2d_fp_of(EVP_PKEY, i2d_PUBKEY, fp, pkey);
}
@@ -497,25 +721,26 @@ PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
d2i_PKCS8_PRIV_KEY_INFO, bp, p8inf);
}
-int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf)
+int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, const PKCS8_PRIV_KEY_INFO *p8inf)
{
return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, bp,
p8inf);
}
-int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key)
+int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, const EVP_PKEY *key)
{
PKCS8_PRIV_KEY_INFO *p8inf;
int ret;
+
p8inf = EVP_PKEY2PKCS8(key);
- if (!p8inf)
+ if (p8inf == NULL)
return 0;
ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf);
PKCS8_PRIV_KEY_INFO_free(p8inf);
return ret;
}
-int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey)
+int i2d_PrivateKey_bio(BIO *bp, const EVP_PKEY *pkey)
{
return ASN1_i2d_bio_of(EVP_PKEY, i2d_PrivateKey, bp, pkey);
}
@@ -525,7 +750,26 @@ EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a)
return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, bp, a);
}
-int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey)
+EVP_PKEY *d2i_PrivateKey_ex_bio(BIO *bp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ BUF_MEM *b = NULL;
+ const unsigned char *p;
+ void *ret = NULL;
+ int len;
+
+ len = asn1_d2i_read_bio(bp, &b);
+ if (len < 0)
+ goto err;
+
+ p = (unsigned char *)b->data;
+ ret = d2i_AutoPrivateKey_ex(a, &p, len, libctx, propq);
+ err:
+ BUF_MEM_free(b);
+ return ret;
+}
+
+int i2d_PUBKEY_bio(BIO *bp, const EVP_PKEY *pkey)
{
return ASN1_i2d_bio_of(EVP_PKEY, i2d_PUBKEY, bp, pkey);
}
diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c
index 7342c4f6bcb5..5c7e622d1a0b 100644
--- a/crypto/x509/x_attrib.c
+++ b/crypto/x509/x_attrib.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index df0041c0108c..fd98ad6926cf 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -1,7 +1,7 @@
/*
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -27,8 +27,8 @@ ASN1_SEQUENCE(X509_REVOKED) = {
static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r);
static int def_crl_lookup(X509_CRL *crl,
- X509_REVOKED **ret, ASN1_INTEGER *serial,
- X509_NAME *issuer);
+ X509_REVOKED **ret, const ASN1_INTEGER *serial,
+ const X509_NAME *issuer);
static X509_CRL_METHOD int_crl_meth = {
0,
@@ -151,7 +151,7 @@ static int crl_set_issuers(X509_CRL *crl)
/*
* The X509_CRL structure needs a bit of customisation. Cache some extensions
- * and hash of the whole CRL.
+ * and hash of the whole CRL or set EXFLAG_NO_FINGERPRINT if this fails.
*/
static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
@@ -189,7 +189,7 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
case ASN1_OP_D2I_POST:
if (!X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL))
- crl->flags |= EXFLAG_INVALID;
+ crl->flags |= EXFLAG_NO_FINGERPRINT;
crl->idp = X509_CRL_get_ext_d2i(crl,
NID_issuing_distribution_point, &i,
NULL);
@@ -268,6 +268,15 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
ASN1_INTEGER_free(crl->crl_number);
ASN1_INTEGER_free(crl->base_crl_number);
sk_GENERAL_NAMES_pop_free(crl->issuers, GENERAL_NAMES_free);
+ OPENSSL_free(crl->propq);
+ break;
+ case ASN1_OP_DUP_POST:
+ {
+ X509_CRL *old = exarg;
+
+ if (!ossl_x509_crl_set0_libctx(crl, old->libctx, old->propq))
+ return 0;
+ }
break;
}
return 1;
@@ -335,6 +344,18 @@ static int X509_REVOKED_cmp(const X509_REVOKED *const *a,
(ASN1_STRING *)&(*b)->serialNumber));
}
+X509_CRL *X509_CRL_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509_CRL *crl = NULL;
+
+ crl = (X509_CRL *)ASN1_item_new((X509_CRL_it()));
+ if (!ossl_x509_crl_set0_libctx(crl, libctx, propq)) {
+ X509_CRL_free(crl);
+ crl = NULL;
+ }
+ return crl;
+}
+
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
{
X509_CRL_INFO *inf;
@@ -343,7 +364,7 @@ int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
if (inf->revoked == NULL)
inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp);
if (inf->revoked == NULL || !sk_X509_REVOKED_push(inf->revoked, rev)) {
- ASN1err(ASN1_F_X509_CRL_ADD0_REVOKED, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
return 0;
}
inf->enc.modified = 1;
@@ -358,7 +379,7 @@ int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r)
}
int X509_CRL_get0_by_serial(X509_CRL *crl,
- X509_REVOKED **ret, ASN1_INTEGER *serial)
+ X509_REVOKED **ret, const ASN1_INTEGER *serial)
{
if (crl->meth->crl_lookup)
return crl->meth->crl_lookup(crl, ret, serial, NULL);
@@ -369,18 +390,19 @@ int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x)
{
if (crl->meth->crl_lookup)
return crl->meth->crl_lookup(crl, ret,
- X509_get_serialNumber(x),
+ X509_get0_serialNumber(x),
X509_get_issuer_name(x));
return 0;
}
static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r)
{
- return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO),
- &crl->sig_alg, &crl->signature, &crl->crl, r));
+ return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_CRL_INFO),
+ &crl->sig_alg, &crl->signature, &crl->crl, NULL,
+ r, crl->libctx, crl->propq);
}
-static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm,
+static int crl_revoked_issuer_match(X509_CRL *crl, const X509_NAME *nm,
X509_REVOKED *rev)
{
int i;
@@ -408,8 +430,8 @@ static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm,
}
static int def_crl_lookup(X509_CRL *crl,
- X509_REVOKED **ret, ASN1_INTEGER *serial,
- X509_NAME *issuer)
+ X509_REVOKED **ret, const ASN1_INTEGER *serial,
+ const X509_NAME *issuer)
{
X509_REVOKED rtmp, *rev;
int idx, num;
@@ -422,7 +444,8 @@ static int def_crl_lookup(X509_CRL *crl,
* under a lock to avoid race condition.
*/
if (!sk_X509_REVOKED_is_sorted(crl->crl.revoked)) {
- CRYPTO_THREAD_write_lock(crl->lock);
+ if (!CRYPTO_THREAD_write_lock(crl->lock))
+ return 0;
sk_X509_REVOKED_sort(crl->crl.revoked);
CRYPTO_THREAD_unlock(crl->lock);
}
@@ -458,15 +481,15 @@ X509_CRL_METHOD *X509_CRL_METHOD_new(int (*crl_init) (X509_CRL *crl),
int (*crl_free) (X509_CRL *crl),
int (*crl_lookup) (X509_CRL *crl,
X509_REVOKED **ret,
- ASN1_INTEGER *ser,
- X509_NAME *issuer),
+ const ASN1_INTEGER *ser,
+ const X509_NAME *issuer),
int (*crl_verify) (X509_CRL *crl,
EVP_PKEY *pk))
{
X509_CRL_METHOD *m = OPENSSL_malloc(sizeof(*m));
if (m == NULL) {
- X509err(X509_F_X509_CRL_METHOD_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
m->crl_init = crl_init;
@@ -493,3 +516,19 @@ void *X509_CRL_get_meth_data(X509_CRL *crl)
{
return crl->meth_data;
}
+
+int ossl_x509_crl_set0_libctx(X509_CRL *x, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ if (x != NULL) {
+ x->libctx = libctx;
+ OPENSSL_free(x->propq);
+ x->propq = NULL;
+ if (propq != NULL) {
+ x->propq = OPENSSL_strdup(propq);
+ if (x->propq == NULL)
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/crypto/x509/x_exten.c b/crypto/x509/x_exten.c
index bd7518ef12bf..4e63b50caa62 100644
--- a/crypto/x509/x_exten.c
+++ b/crypto/x509/x_exten.c
@@ -1,7 +1,7 @@
/*
* Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
index dc4a494fb543..eded80246df9 100644
--- a/crypto/x509/x_name.c
+++ b/crypto/x509/x_name.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -28,7 +28,7 @@ static int x509_name_ex_d2i(ASN1_VALUE **val,
const ASN1_ITEM *it,
int tag, int aclass, char opt, ASN1_TLC *ctx);
-static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out,
+static int x509_name_ex_i2d(const ASN1_VALUE **val, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass);
static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it);
static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it);
@@ -36,10 +36,10 @@ static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it);
static int x509_name_encode(X509_NAME *a);
static int x509_name_canon(X509_NAME *a);
static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in);
-static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname,
+static int i2d_name_canon(const STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname,
unsigned char **in);
-static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
+static int x509_name_ex_print(BIO *out, const ASN1_VALUE **pval,
int indent,
const char *fname, const ASN1_PCTX *pctx);
@@ -102,7 +102,7 @@ static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it)
return 1;
memerr:
- ASN1err(ASN1_F_X509_NAME_EX_NEW, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
if (ret) {
sk_X509_NAME_ENTRY_free(ret->entries);
OPENSSL_free(ret);
@@ -114,7 +114,7 @@ static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
X509_NAME *a;
- if (!pval || !*pval)
+ if (pval == NULL || *pval == NULL)
return;
a = (X509_NAME *)*pval;
@@ -156,6 +156,7 @@ static int x509_name_ex_d2i(ASN1_VALUE **val,
int i, j, ret;
STACK_OF(X509_NAME_ENTRY) *entries;
X509_NAME_ENTRY *entry;
+
if (len > X509_NAME_MAX)
len = X509_NAME_MAX;
q = p;
@@ -185,7 +186,7 @@ static int x509_name_ex_d2i(ASN1_VALUE **val,
entry->set = i;
if (!sk_X509_NAME_ENTRY_push(nm.x->entries, entry))
goto err;
- sk_X509_NAME_ENTRY_set(entries, j, NULL);
+ (void)sk_X509_NAME_ENTRY_set(entries, j, NULL);
}
}
ret = x509_name_canon(nm.x);
@@ -203,15 +204,16 @@ static int x509_name_ex_d2i(ASN1_VALUE **val,
X509_NAME_free(nm.x);
sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s,
local_sk_X509_NAME_ENTRY_pop_free);
- ASN1err(ASN1_F_X509_NAME_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
return 0;
}
-static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out,
+static int x509_name_ex_i2d(const ASN1_VALUE **val, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass)
{
int ret;
X509_NAME *a = (X509_NAME *)*val;
+
if (a->modified) {
ret = x509_name_encode(a);
if (ret < 0)
@@ -232,7 +234,7 @@ static int x509_name_encode(X509_NAME *a)
{
union {
STACK_OF(STACK_OF_X509_NAME_ENTRY) *s;
- ASN1_VALUE *a;
+ const ASN1_VALUE *a;
} intname = {
NULL
};
@@ -241,6 +243,7 @@ static int x509_name_encode(X509_NAME *a)
STACK_OF(X509_NAME_ENTRY) *entries = NULL;
X509_NAME_ENTRY *entry;
int i, set = -1;
+
intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null();
if (!intname.s)
goto memerr;
@@ -273,11 +276,11 @@ static int x509_name_encode(X509_NAME *a)
memerr:
sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s,
local_sk_X509_NAME_ENTRY_free);
- ASN1err(ASN1_F_X509_NAME_ENCODE, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
return -1;
}
-static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
+static int x509_name_ex_print(BIO *out, const ASN1_VALUE **pval,
int indent,
const char *fname, const ASN1_PCTX *pctx)
{
@@ -295,6 +298,7 @@ static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
* comparison of Name structures can be rapidly performed by just using
* memcmp() of the canonical encoding. By omitting the leading SEQUENCE name
* constraints of type dirName can also be checked with a simple memcmp().
+ * NOTE: For empty X509_NAME (NULL-DN), canon_enclen == 0 && canon_enc == NULL
*/
static int x509_name_canon(X509_NAME *a)
@@ -314,7 +318,7 @@ static int x509_name_canon(X509_NAME *a)
}
intname = sk_STACK_OF_X509_NAME_ENTRY_new_null();
if (intname == NULL) {
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
@@ -325,25 +329,25 @@ static int x509_name_canon(X509_NAME *a)
goto err;
if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) {
sk_X509_NAME_ENTRY_free(entries);
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
set = entry->set;
}
tmpentry = X509_NAME_ENTRY_new();
if (tmpentry == NULL) {
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
tmpentry->object = OBJ_dup(entry->object);
if (tmpentry->object == NULL) {
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!asn1_string_canon(tmpentry->value, entry->value))
goto err;
if (!sk_X509_NAME_ENTRY_push(entries, tmpentry)) {
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
tmpentry = NULL;
@@ -357,7 +361,7 @@ static int x509_name_canon(X509_NAME *a)
p = OPENSSL_malloc(a->canon_enclen);
if (p == NULL) {
- X509err(X509_F_X509_NAME_CANON, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -460,11 +464,11 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
}
-static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname,
+static int i2d_name_canon(const STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname,
unsigned char **in)
{
int i, len, ltmp;
- ASN1_VALUE *v;
+ const ASN1_VALUE *v;
STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname;
len = 0;
@@ -472,21 +476,23 @@ static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname,
v = sk_ASN1_VALUE_value(intname, i);
ltmp = ASN1_item_ex_i2d(&v, in,
ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1);
- if (ltmp < 0)
- return ltmp;
+ if (ltmp < 0 || len > INT_MAX - ltmp)
+ return -1;
len += ltmp;
}
return len;
}
-int X509_NAME_set(X509_NAME **xn, X509_NAME *name)
+int X509_NAME_set(X509_NAME **xn, const X509_NAME *name)
{
+ X509_NAME *name_copy;
+
if (*xn == name)
return *xn != NULL;
- if ((name = X509_NAME_dup(name)) == NULL)
+ if ((name_copy = X509_NAME_dup(name)) == NULL)
return 0;
X509_NAME_free(*xn);
- *xn = name;
+ *xn = name_copy;
return 1;
}
@@ -496,9 +502,9 @@ int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase)
int i;
b = X509_NAME_oneline(name, NULL, 0);
- if (!b)
+ if (b == NULL)
return 0;
- if (!*b) {
+ if (*b == '\0') {
OPENSSL_free(b);
return 1;
}
@@ -528,12 +534,12 @@ int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase)
OPENSSL_free(b);
return 1;
err:
- X509err(X509_F_X509_NAME_PRINT, ERR_R_BUF_LIB);
+ ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
OPENSSL_free(b);
return 0;
}
-int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder,
+int X509_NAME_get0_der(const X509_NAME *nm, const unsigned char **pder,
size_t *pderlen)
{
/* Make sure encoding is valid */
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index 9be7e9286571..b290075c8589 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -1,92 +1,386 @@
/*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
*/
+/*
+ * DSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/x509.h>
+#include <openssl/engine.h>
#include "crypto/asn1.h"
#include "crypto/evp.h"
#include "crypto/x509.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
+#include <openssl/decoder.h>
+#include <openssl/encoder.h>
+#include "internal/provider.h"
+#include "internal/sizes.h"
struct X509_pubkey_st {
X509_ALGOR *algor;
ASN1_BIT_STRING *public_key;
+
EVP_PKEY *pkey;
+
+ /* extra data for the callback, used by d2i_PUBKEY_ex */
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+
+ /* Flag to force legacy keys */
+ unsigned int flag_force_legacy : 1;
};
-static int x509_pubkey_decode(EVP_PKEY **pk, X509_PUBKEY *key);
+static int x509_pubkey_decode(EVP_PKEY **pk, const X509_PUBKEY *key);
-/* Minor tweak to operation: free up EVP_PKEY */
-static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
- void *exarg)
+static int x509_pubkey_set0_libctx(X509_PUBKEY *x, OSSL_LIB_CTX *libctx,
+ const char *propq)
{
- if (operation == ASN1_OP_FREE_POST) {
- X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
- EVP_PKEY_free(pubkey->pkey);
- } else if (operation == ASN1_OP_D2I_POST) {
- /* Attempt to decode public key and cache in pubkey structure. */
- X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
- EVP_PKEY_free(pubkey->pkey);
- pubkey->pkey = NULL;
- /*
- * Opportunistically decode the key but remove any non fatal errors
- * from the queue. Subsequent explicit attempts to decode/use the key
- * will return an appropriate error.
- */
- ERR_set_mark();
- if (x509_pubkey_decode(&pubkey->pkey, pubkey) == -1)
- return 0;
- ERR_pop_to_mark();
+ if (x != NULL) {
+ x->libctx = libctx;
+ OPENSSL_free(x->propq);
+ x->propq = NULL;
+ if (propq != NULL) {
+ x->propq = OPENSSL_strdup(propq);
+ if (x->propq == NULL)
+ return 0;
+ }
}
return 1;
}
-ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = {
+ASN1_SEQUENCE(X509_PUBKEY_INTERNAL) = {
ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR),
ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING)
-} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY)
+} static_ASN1_SEQUENCE_END_name(X509_PUBKEY, X509_PUBKEY_INTERNAL)
+
+X509_PUBKEY *ossl_d2i_X509_PUBKEY_INTERNAL(const unsigned char **pp,
+ long len, OSSL_LIB_CTX *libctx)
+{
+ X509_PUBKEY *xpub = OPENSSL_zalloc(sizeof(*xpub));
+
+ if (xpub == NULL)
+ return NULL;
+ return (X509_PUBKEY *)ASN1_item_d2i_ex((ASN1_VALUE **)&xpub, pp, len,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL),
+ libctx, NULL);
+}
+
+void ossl_X509_PUBKEY_INTERNAL_free(X509_PUBKEY *xpub)
+{
+ ASN1_item_free((ASN1_VALUE *)xpub, ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL));
+}
+
+static void x509_pubkey_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ X509_PUBKEY *pubkey;
+
+ if (pval != NULL && (pubkey = (X509_PUBKEY *)*pval) != NULL) {
+ X509_ALGOR_free(pubkey->algor);
+ ASN1_BIT_STRING_free(pubkey->public_key);
+ EVP_PKEY_free(pubkey->pkey);
+ OPENSSL_free(pubkey->propq);
+ OPENSSL_free(pubkey);
+ *pval = NULL;
+ }
+}
+
+static int x509_pubkey_ex_populate(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
+
+ return (pubkey->algor != NULL
+ || (pubkey->algor = X509_ALGOR_new()) != NULL)
+ && (pubkey->public_key != NULL
+ || (pubkey->public_key = ASN1_BIT_STRING_new()) != NULL);
+}
+
+
+static int x509_pubkey_ex_new_ex(ASN1_VALUE **pval, const ASN1_ITEM *it,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509_PUBKEY *ret;
+
+ if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL
+ || !x509_pubkey_ex_populate((ASN1_VALUE **)&ret, NULL)
+ || !x509_pubkey_set0_libctx(ret, libctx, propq)) {
+ x509_pubkey_ex_free((ASN1_VALUE **)&ret, NULL);
+ ret = NULL;
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ } else {
+ *pval = (ASN1_VALUE *)ret;
+ }
+
+ return ret != NULL;
+}
+
+static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
+ const unsigned char **in, long len,
+ const ASN1_ITEM *it, int tag, int aclass,
+ char opt, ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ const unsigned char *in_saved = *in;
+ size_t publen;
+ X509_PUBKEY *pubkey;
+ int ret;
+ OSSL_DECODER_CTX *dctx = NULL;
+ unsigned char *tmpbuf = NULL;
+
+ if (*pval == NULL && !x509_pubkey_ex_new_ex(pval, it, libctx, propq))
+ return 0;
+ if (!x509_pubkey_ex_populate(pval, NULL)) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* This ensures that |*in| advances properly no matter what */
+ if ((ret = ASN1_item_ex_d2i(pval, in, len,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL),
+ tag, aclass, opt, ctx)) <= 0)
+ return ret;
+
+ publen = *in - in_saved;
+ if (!ossl_assert(publen > 0)) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ pubkey = (X509_PUBKEY *)*pval;
+ EVP_PKEY_free(pubkey->pkey);
+ pubkey->pkey = NULL;
+
+ /*
+ * Opportunistically decode the key but remove any non fatal errors
+ * from the queue. Subsequent explicit attempts to decode/use the key
+ * will return an appropriate error.
+ */
+ ERR_set_mark();
+ /*
+ * Try to decode with legacy method first. This ensures that engines
+ * aren't overriden by providers.
+ */
+ if ((ret = x509_pubkey_decode(&pubkey->pkey, pubkey)) == -1) {
+ /* -1 indicates a fatal error, like malloc failure */
+ ERR_clear_last_mark();
+ goto end;
+ }
+
+ /* Try to decode it into an EVP_PKEY with OSSL_DECODER */
+ if (ret <= 0 && !pubkey->flag_force_legacy) {
+ const unsigned char *p;
+ char txtoidname[OSSL_MAX_NAME_SIZE];
+ size_t slen = publen;
+
+ /*
+ * The decoders don't know how to handle anything other than Universal
+ * class so we modify the data accordingly.
+ */
+ if (aclass != V_ASN1_UNIVERSAL) {
+ tmpbuf = OPENSSL_memdup(in_saved, publen);
+ if (tmpbuf == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ in_saved = tmpbuf;
+ *tmpbuf = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE;
+ }
+ p = in_saved;
+
+ if (OBJ_obj2txt(txtoidname, sizeof(txtoidname),
+ pubkey->algor->algorithm, 0) <= 0) {
+ ERR_clear_last_mark();
+ goto end;
+ }
+ if ((dctx =
+ OSSL_DECODER_CTX_new_for_pkey(&pubkey->pkey,
+ "DER", "SubjectPublicKeyInfo",
+ txtoidname, EVP_PKEY_PUBLIC_KEY,
+ pubkey->libctx,
+ pubkey->propq)) != NULL)
+ /*
+ * As said higher up, we're being opportunistic. In other words,
+ * we don't care if we fail.
+ */
+ if (OSSL_DECODER_from_data(dctx, &p, &slen)) {
+ if (slen != 0) {
+ /*
+ * If we successfully decoded then we *must* consume all the
+ * bytes.
+ */
+ ERR_clear_last_mark();
+ ERR_raise(ERR_LIB_ASN1, EVP_R_DECODE_ERROR);
+ goto end;
+ }
+ }
+ }
+
+ ERR_pop_to_mark();
+ ret = 1;
+ end:
+ OSSL_DECODER_CTX_free(dctx);
+ OPENSSL_free(tmpbuf);
+ return ret;
+}
+
+static int x509_pubkey_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass)
+{
+ return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL),
+ tag, aclass);
+}
+
+static int x509_pubkey_ex_print(BIO *out, const ASN1_VALUE **pval, int indent,
+ const char *fname, const ASN1_PCTX *pctx)
+{
+ return ASN1_item_print(out, *pval, indent,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL), pctx);
+}
+
+static const ASN1_EXTERN_FUNCS x509_pubkey_ff = {
+ NULL,
+ NULL,
+ x509_pubkey_ex_free,
+ 0, /* Default clear behaviour is OK */
+ NULL,
+ x509_pubkey_ex_i2d,
+ x509_pubkey_ex_print,
+ x509_pubkey_ex_new_ex,
+ x509_pubkey_ex_d2i_ex,
+};
+
+IMPLEMENT_EXTERN_ASN1(X509_PUBKEY, V_ASN1_SEQUENCE, x509_pubkey_ff)
IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
+X509_PUBKEY *X509_PUBKEY_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509_PUBKEY *pubkey = NULL;
+
+ pubkey = (X509_PUBKEY *)ASN1_item_new_ex(X509_PUBKEY_it(), libctx, propq);
+ if (!x509_pubkey_set0_libctx(pubkey, libctx, propq)) {
+ X509_PUBKEY_free(pubkey);
+ pubkey = NULL;
+ }
+ return pubkey;
+}
+
+/*
+ * X509_PUBKEY_dup() must be implemented manually, because there is no
+ * support for it in ASN1_EXTERN_FUNCS.
+ */
+X509_PUBKEY *X509_PUBKEY_dup(const X509_PUBKEY *a)
+{
+ X509_PUBKEY *pubkey = OPENSSL_zalloc(sizeof(*pubkey));
+
+ if (pubkey == NULL
+ || !x509_pubkey_set0_libctx(pubkey, a->libctx, a->propq)
+ || (pubkey->algor = X509_ALGOR_dup(a->algor)) == NULL
+ || (pubkey->public_key = ASN1_BIT_STRING_new()) == NULL
+ || !ASN1_BIT_STRING_set(pubkey->public_key,
+ a->public_key->data,
+ a->public_key->length)) {
+ x509_pubkey_ex_free((ASN1_VALUE **)&pubkey,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL));
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if (a->pkey != NULL) {
+ ERR_set_mark();
+ pubkey->pkey = EVP_PKEY_dup(a->pkey);
+ if (pubkey->pkey == NULL) {
+ pubkey->flag_force_legacy = 1;
+ if (x509_pubkey_decode(&pubkey->pkey, pubkey) <= 0) {
+ x509_pubkey_ex_free((ASN1_VALUE **)&pubkey,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL));
+ ERR_clear_last_mark();
+ return NULL;
+ }
+ }
+ ERR_pop_to_mark();
+ }
+ return pubkey;
+}
+
int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
{
X509_PUBKEY *pk = NULL;
- if (x == NULL)
+ if (x == NULL || pkey == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
return 0;
+ }
- if ((pk = X509_PUBKEY_new()) == NULL)
- goto error;
-
- if (pkey->ameth) {
- if (pkey->ameth->pub_encode) {
+ if (pkey->ameth != NULL) {
+ if ((pk = X509_PUBKEY_new()) == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ goto error;
+ }
+ if (pkey->ameth->pub_encode != NULL) {
if (!pkey->ameth->pub_encode(pk, pkey)) {
- X509err(X509_F_X509_PUBKEY_SET,
- X509_R_PUBLIC_KEY_ENCODE_ERROR);
+ ERR_raise(ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
goto error;
}
} else {
- X509err(X509_F_X509_PUBKEY_SET, X509_R_METHOD_NOT_SUPPORTED);
+ ERR_raise(ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED);
goto error;
}
- } else {
- X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM);
+ } else if (evp_pkey_is_provided(pkey)) {
+ unsigned char *der = NULL;
+ size_t derlen = 0;
+ OSSL_ENCODER_CTX *ectx =
+ OSSL_ENCODER_CTX_new_for_pkey(pkey, EVP_PKEY_PUBLIC_KEY,
+ "DER", "SubjectPublicKeyInfo",
+ NULL);
+
+ if (OSSL_ENCODER_to_data(ectx, &der, &derlen)) {
+ const unsigned char *pder = der;
+
+ pk = d2i_X509_PUBKEY(NULL, &pder, (long)derlen);
+ }
+
+ OSSL_ENCODER_CTX_free(ectx);
+ OPENSSL_free(der);
+ }
+
+ if (pk == NULL) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
goto error;
}
X509_PUBKEY_free(*x);
+ if (!EVP_PKEY_up_ref(pkey)) {
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+ goto error;
+ }
*x = pk;
+
+ /*
+ * pk->pkey is NULL when using the legacy routine, but is non-NULL when
+ * going through the encoder, and for all intents and purposes, it's
+ * a perfect copy of the public key portions of |pkey|, just not the same
+ * instance. If that's all there was to pkey then we could simply return
+ * early, right here. However, some application might very well depend on
+ * the passed |pkey| being used and none other, so we spend a few more
+ * cycles throwing away the newly created |pk->pkey| and replace it with
+ * |pkey|.
+ */
+ if (pk->pkey != NULL)
+ EVP_PKEY_free(pk->pkey);
+
pk->pkey = pkey;
- EVP_PKEY_up_ref(pkey);
return 1;
error:
@@ -98,20 +392,36 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
* Attempt to decode a public key.
* Returns 1 on success, 0 for a decode failure and -1 for a fatal
* error e.g. malloc failure.
+ *
+ * This function is #legacy.
*/
+static int x509_pubkey_decode(EVP_PKEY **ppkey, const X509_PUBKEY *key)
+{
+ EVP_PKEY *pkey;
+ int nid;
+ nid = OBJ_obj2nid(key->algor->algorithm);
+ if (!key->flag_force_legacy) {
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE *e = NULL;
-static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key)
-{
- EVP_PKEY *pkey = EVP_PKEY_new();
+ e = ENGINE_get_pkey_meth_engine(nid);
+ if (e == NULL)
+ return 0;
+ ENGINE_finish(e);
+#else
+ return 0;
+#endif
+ }
+ pkey = EVP_PKEY_new();
if (pkey == NULL) {
- X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return -1;
}
- if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(key->algor->algorithm))) {
- X509err(X509_F_X509_PUBKEY_DECODE, X509_R_UNSUPPORTED_ALGORITHM);
+ if (!EVP_PKEY_set_type(pkey, nid)) {
+ ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
goto error;
}
@@ -121,12 +431,10 @@ static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key)
* future we could have different return codes for decode
* errors and fatal errors such as malloc failure.
*/
- if (!pkey->ameth->pub_decode(pkey, key)) {
- X509err(X509_F_X509_PUBKEY_DECODE, X509_R_PUBLIC_KEY_DECODE_ERROR);
+ if (!pkey->ameth->pub_decode(pkey, key))
goto error;
- }
} else {
- X509err(X509_F_X509_PUBKEY_DECODE, X509_R_METHOD_NOT_SUPPORTED);
+ ERR_raise(ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED);
goto error;
}
@@ -138,110 +446,181 @@ static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key)
return 0;
}
-EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key)
+EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key)
{
- EVP_PKEY *ret = NULL;
-
- if (key == NULL || key->public_key == NULL)
+ if (key == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
+ }
- if (key->pkey != NULL)
- return key->pkey;
-
- /*
- * When the key ASN.1 is initially parsed an attempt is made to
- * decode the public key and cache the EVP_PKEY structure. If this
- * operation fails the cached value will be NULL. Parsing continues
- * to allow parsing of unknown key types or unsupported forms.
- * We repeat the decode operation so the appropriate errors are left
- * in the queue.
- */
- x509_pubkey_decode(&ret, key);
- /* If decode doesn't fail something bad happened */
- if (ret != NULL) {
- X509err(X509_F_X509_PUBKEY_GET0, ERR_R_INTERNAL_ERROR);
- EVP_PKEY_free(ret);
+ if (key->pkey == NULL) {
+ /* We failed to decode the key when we loaded it, or it was never set */
+ ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR);
+ return NULL;
}
- return NULL;
+ return key->pkey;
}
-EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
+EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key)
{
EVP_PKEY *ret = X509_PUBKEY_get0(key);
if (ret != NULL && !EVP_PKEY_up_ref(ret)) {
- X509err(X509_F_X509_PUBKEY_GET, ERR_R_INTERNAL_ERROR);
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
ret = NULL;
}
return ret;
}
/*
- * Now two pseudo ASN1 routines that take an EVP_PKEY structure and encode or
- * decode as X509_PUBKEY
+ * Now three pseudo ASN1 routines that take an EVP_PKEY structure and encode
+ * or decode as X509_PUBKEY
*/
-
-EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length)
+static EVP_PKEY *d2i_PUBKEY_int(EVP_PKEY **a,
+ const unsigned char **pp, long length,
+ OSSL_LIB_CTX *libctx, const char *propq,
+ unsigned int force_legacy,
+ X509_PUBKEY *
+ (*d2i_x509_pubkey)(X509_PUBKEY **a,
+ const unsigned char **in,
+ long len))
{
- X509_PUBKEY *xpk;
- EVP_PKEY *pktmp;
+ X509_PUBKEY *xpk, *xpk2 = NULL, **pxpk = NULL;
+ EVP_PKEY *pktmp = NULL;
const unsigned char *q;
+
q = *pp;
- xpk = d2i_X509_PUBKEY(NULL, &q, length);
- if (!xpk)
- return NULL;
+
+ /*
+ * If libctx or propq are non-NULL, we take advantage of the reuse
+ * feature. It's not generally recommended, but is safe enough for
+ * newly created structures.
+ */
+ if (libctx != NULL || propq != NULL || force_legacy) {
+ xpk2 = OPENSSL_zalloc(sizeof(*xpk2));
+ if (xpk2 == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (!x509_pubkey_set0_libctx(xpk2, libctx, propq))
+ goto end;
+ xpk2->flag_force_legacy = !!force_legacy;
+ pxpk = &xpk2;
+ }
+ xpk = d2i_x509_pubkey(pxpk, &q, length);
+ if (xpk == NULL)
+ goto end;
pktmp = X509_PUBKEY_get(xpk);
X509_PUBKEY_free(xpk);
- if (!pktmp)
- return NULL;
+ xpk2 = NULL; /* We know that xpk == xpk2 */
+ if (pktmp == NULL)
+ goto end;
*pp = q;
- if (a) {
+ if (a != NULL) {
EVP_PKEY_free(*a);
*a = pktmp;
}
+ end:
+ X509_PUBKEY_free(xpk2);
return pktmp;
}
-int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp)
+/* For the algorithm specific d2i functions further down */
+EVP_PKEY *ossl_d2i_PUBKEY_legacy(EVP_PKEY **a, const unsigned char **pp,
+ long length)
{
- X509_PUBKEY *xpk = NULL;
- int ret;
- if (!a)
+ return d2i_PUBKEY_int(a, pp, length, NULL, NULL, 1, d2i_X509_PUBKEY);
+}
+
+EVP_PKEY *d2i_PUBKEY_ex(EVP_PKEY **a, const unsigned char **pp, long length,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ return d2i_PUBKEY_int(a, pp, length, libctx, propq, 0, d2i_X509_PUBKEY);
+}
+
+EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length)
+{
+ return d2i_PUBKEY_ex(a, pp, length, NULL, NULL);
+}
+
+int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp)
+{
+ int ret = -1;
+
+ if (a == NULL)
return 0;
- if (!X509_PUBKEY_set(&xpk, a))
- return -1;
- ret = i2d_X509_PUBKEY(xpk, pp);
- X509_PUBKEY_free(xpk);
+ if (a->ameth != NULL) {
+ X509_PUBKEY *xpk = NULL;
+
+ if ((xpk = X509_PUBKEY_new()) == NULL)
+ return -1;
+
+ /* pub_encode() only encode parameters, not the key itself */
+ if (a->ameth->pub_encode != NULL && a->ameth->pub_encode(xpk, a)) {
+ xpk->pkey = (EVP_PKEY *)a;
+ ret = i2d_X509_PUBKEY(xpk, pp);
+ xpk->pkey = NULL;
+ }
+ X509_PUBKEY_free(xpk);
+ } else if (a->keymgmt != NULL) {
+ OSSL_ENCODER_CTX *ctx =
+ OSSL_ENCODER_CTX_new_for_pkey(a, EVP_PKEY_PUBLIC_KEY,
+ "DER", "SubjectPublicKeyInfo",
+ NULL);
+ BIO *out = BIO_new(BIO_s_mem());
+ BUF_MEM *buf = NULL;
+
+ if (OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0
+ && out != NULL
+ && OSSL_ENCODER_to_bio(ctx, out)
+ && BIO_get_mem_ptr(out, &buf) > 0) {
+ ret = buf->length;
+
+ if (pp != NULL) {
+ if (*pp == NULL) {
+ *pp = (unsigned char *)buf->data;
+ buf->length = 0;
+ buf->data = NULL;
+ } else {
+ memcpy(*pp, buf->data, ret);
+ *pp += ret;
+ }
+ }
+ }
+ BIO_free(out);
+ OSSL_ENCODER_CTX_free(ctx);
+ }
+
return ret;
}
/*
* The following are equivalents but which return RSA and DSA keys
*/
-#ifndef OPENSSL_NO_RSA
RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length)
{
EVP_PKEY *pkey;
- RSA *key;
+ RSA *key = NULL;
const unsigned char *q;
+
q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
return NULL;
key = EVP_PKEY_get1_RSA(pkey);
EVP_PKEY_free(pkey);
- if (!key)
+ if (key == NULL)
return NULL;
*pp = q;
- if (a) {
+ if (a != NULL) {
RSA_free(*a);
*a = key;
}
return key;
}
-int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp)
+int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp)
{
EVP_PKEY *pktmp;
int ret;
@@ -249,11 +628,95 @@ int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp)
return 0;
pktmp = EVP_PKEY_new();
if (pktmp == NULL) {
- ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
return -1;
}
- EVP_PKEY_set1_RSA(pktmp, a);
+ (void)EVP_PKEY_assign_RSA(pktmp, (RSA *)a);
ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
+#ifndef OPENSSL_NO_DH
+DH *ossl_d2i_DH_PUBKEY(DH **a, const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ DH *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_DH)
+ key = EVP_PKEY_get1_DH(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ DH_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_DH_PUBKEY(const DH *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+ if (!a)
+ return 0;
+ pktmp = EVP_PKEY_new();
+ if (pktmp == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign_DH(pktmp, (DH *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
+DH *ossl_d2i_DHx_PUBKEY(DH **a, const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ DH *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_DHX)
+ key = EVP_PKEY_get1_DH(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ DH_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_DHx_PUBKEY(const DH *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+ if (!a)
+ return 0;
+ pktmp = EVP_PKEY_new();
+ if (pktmp == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign(pktmp, EVP_PKEY_DHX, (DH *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
EVP_PKEY_free(pktmp);
return ret;
}
@@ -263,25 +726,50 @@ int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp)
DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
{
EVP_PKEY *pkey;
- DSA *key;
+ DSA *key = NULL;
const unsigned char *q;
+
q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
return NULL;
key = EVP_PKEY_get1_DSA(pkey);
EVP_PKEY_free(pkey);
- if (!key)
+ if (key == NULL)
return NULL;
*pp = q;
- if (a) {
+ if (a != NULL) {
+ DSA_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+/* Called from decoders; disallows provided DSA keys without parameters. */
+DSA *ossl_d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
+{
+ DSA *key = NULL;
+ const unsigned char *data;
+ const BIGNUM *p, *q, *g;
+
+ data = *pp;
+ key = d2i_DSA_PUBKEY(NULL, &data, length);
+ if (key == NULL)
+ return NULL;
+ DSA_get0_pqg(key, &p, &q, &g);
+ if (p == NULL || q == NULL || g == NULL) {
+ DSA_free(key);
+ return NULL;
+ }
+ *pp = data;
+ if (a != NULL) {
DSA_free(*a);
*a = key;
}
return key;
}
-int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp)
+int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
{
EVP_PKEY *pktmp;
int ret;
@@ -289,11 +777,12 @@ int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp)
return 0;
pktmp = EVP_PKEY_new();
if (pktmp == NULL) {
- ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
return -1;
}
- EVP_PKEY_set1_DSA(pktmp, a);
+ (void)EVP_PKEY_assign_DSA(pktmp, (DSA *)a);
ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
EVP_PKEY_free(pktmp);
return ret;
}
@@ -303,39 +792,213 @@ int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp)
EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
{
EVP_PKEY *pkey;
- EC_KEY *key;
+ EC_KEY *key = NULL;
const unsigned char *q;
+ int type;
+
q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
return NULL;
- key = EVP_PKEY_get1_EC_KEY(pkey);
+ type = EVP_PKEY_get_id(pkey);
+ if (type == EVP_PKEY_EC || type == EVP_PKEY_SM2)
+ key = EVP_PKEY_get1_EC_KEY(pkey);
EVP_PKEY_free(pkey);
- if (!key)
+ if (key == NULL)
return NULL;
*pp = q;
- if (a) {
+ if (a != NULL) {
EC_KEY_free(*a);
*a = key;
}
return key;
}
-int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp)
+int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp)
{
EVP_PKEY *pktmp;
int ret;
- if (!a)
+
+ if (a == NULL)
return 0;
if ((pktmp = EVP_PKEY_new()) == NULL) {
- ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
return -1;
}
- EVP_PKEY_set1_EC_KEY(pktmp, a);
+ (void)EVP_PKEY_assign_EC_KEY(pktmp, (EC_KEY *)a);
ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
EVP_PKEY_free(pktmp);
return ret;
}
+
+ECX_KEY *ossl_d2i_ED25519_PUBKEY(ECX_KEY **a,
+ const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ ECX_KEY *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ key = ossl_evp_pkey_get1_ED25519(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ ossl_ecx_key_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_ED25519_PUBKEY(const ECX_KEY *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+
+ if (a == NULL)
+ return 0;
+ if ((pktmp = EVP_PKEY_new()) == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign(pktmp, EVP_PKEY_ED25519, (ECX_KEY *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
+ECX_KEY *ossl_d2i_ED448_PUBKEY(ECX_KEY **a,
+ const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ ECX_KEY *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_ED448)
+ key = ossl_evp_pkey_get1_ED448(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ ossl_ecx_key_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_ED448_PUBKEY(const ECX_KEY *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+
+ if (a == NULL)
+ return 0;
+ if ((pktmp = EVP_PKEY_new()) == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign(pktmp, EVP_PKEY_ED448, (ECX_KEY *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
+ECX_KEY *ossl_d2i_X25519_PUBKEY(ECX_KEY **a,
+ const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ ECX_KEY *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_X25519)
+ key = ossl_evp_pkey_get1_X25519(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ ossl_ecx_key_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_X25519_PUBKEY(const ECX_KEY *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+
+ if (a == NULL)
+ return 0;
+ if ((pktmp = EVP_PKEY_new()) == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign(pktmp, EVP_PKEY_X25519, (ECX_KEY *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
+ECX_KEY *ossl_d2i_X448_PUBKEY(ECX_KEY **a,
+ const unsigned char **pp, long length)
+{
+ EVP_PKEY *pkey;
+ ECX_KEY *key = NULL;
+ const unsigned char *q;
+
+ q = *pp;
+ pkey = ossl_d2i_PUBKEY_legacy(NULL, &q, length);
+ if (pkey == NULL)
+ return NULL;
+ if (EVP_PKEY_get_id(pkey) == EVP_PKEY_X448)
+ key = ossl_evp_pkey_get1_X448(pkey);
+ EVP_PKEY_free(pkey);
+ if (key == NULL)
+ return NULL;
+ *pp = q;
+ if (a != NULL) {
+ ossl_ecx_key_free(*a);
+ *a = key;
+ }
+ return key;
+}
+
+int ossl_i2d_X448_PUBKEY(const ECX_KEY *a, unsigned char **pp)
+{
+ EVP_PKEY *pktmp;
+ int ret;
+
+ if (a == NULL)
+ return 0;
+ if ((pktmp = EVP_PKEY_new()) == NULL) {
+ ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ (void)EVP_PKEY_assign(pktmp, EVP_PKEY_X448, (ECX_KEY *)a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ pktmp->pkey.ptr = NULL;
+ EVP_PKEY_free(pktmp);
+ return ret;
+}
+
#endif
int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj,
@@ -357,7 +1020,7 @@ int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj,
int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
const unsigned char **pk, int *ppklen,
- X509_ALGOR **pa, X509_PUBKEY *pub)
+ X509_ALGOR **pa, const X509_PUBKEY *pub)
{
if (ppkalg)
*ppkalg = pub->algor->algorithm;
@@ -376,3 +1039,34 @@ ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x)
return NULL;
return x->cert_info.key->public_key;
}
+
+/* Returns 1 for equal, 0, for non-equal, < 0 on error */
+int X509_PUBKEY_eq(const X509_PUBKEY *a, const X509_PUBKEY *b)
+{
+ X509_ALGOR *algA, *algB;
+ EVP_PKEY *pA, *pB;
+
+ if (a == b)
+ return 1;
+ if (a == NULL || b == NULL)
+ return 0;
+ if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algA, a) || algA == NULL
+ || !X509_PUBKEY_get0_param(NULL, NULL, NULL, &algB, b) || algB == NULL)
+ return -2;
+ if (X509_ALGOR_cmp(algA, algB) != 0)
+ return 0;
+ if ((pA = X509_PUBKEY_get0(a)) == NULL
+ || (pB = X509_PUBKEY_get0(b)) == NULL)
+ return -2;
+ return EVP_PKEY_eq(pA, pB);
+}
+
+int ossl_x509_PUBKEY_get0_libctx(OSSL_LIB_CTX **plibctx, const char **ppropq,
+ const X509_PUBKEY *key)
+{
+ if (plibctx)
+ *plibctx = key->libctx;
+ if (ppropq)
+ *ppropq = key->propq;
+ return 1;
+}
diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c
index d2b02f6dae86..293d4be71335 100644
--- a/crypto/x509/x_req.c
+++ b/crypto/x509/x_req.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -45,6 +45,67 @@ static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
return 1;
}
+static int req_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ X509_REQ *ret = (X509_REQ *)*pval;
+
+ switch (operation) {
+ case ASN1_OP_D2I_PRE:
+ ASN1_OCTET_STRING_free(ret->distinguishing_id);
+ /* fall thru */
+ case ASN1_OP_NEW_POST:
+ ret->distinguishing_id = NULL;
+ break;
+
+ case ASN1_OP_FREE_POST:
+ ASN1_OCTET_STRING_free(ret->distinguishing_id);
+ OPENSSL_free(ret->propq);
+ break;
+ case ASN1_OP_DUP_POST:
+ {
+ X509_REQ *old = exarg;
+
+ if (!ossl_x509_req_set0_libctx(ret, old->libctx, old->propq))
+ return 0;
+ if (old->req_info.pubkey != NULL) {
+ EVP_PKEY *pkey = X509_PUBKEY_get0(old->req_info.pubkey);
+
+ if (pkey != NULL) {
+ pkey = EVP_PKEY_dup(pkey);
+ if (pkey == NULL) {
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (!X509_PUBKEY_set(&ret->req_info.pubkey, pkey)) {
+ EVP_PKEY_free(pkey);
+ ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ EVP_PKEY_free(pkey);
+ }
+ }
+ }
+ break;
+ case ASN1_OP_GET0_LIBCTX:
+ {
+ OSSL_LIB_CTX **libctx = exarg;
+
+ *libctx = ret->libctx;
+ }
+ break;
+ case ASN1_OP_GET0_PROPQ:
+ {
+ const char **propq = exarg;
+
+ *propq = ret->propq;
+ }
+ break;
+ }
+
+ return 1;
+}
+
ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = {
ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER),
ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME),
@@ -57,7 +118,7 @@ ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = {
IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO)
-ASN1_SEQUENCE_ref(X509_REQ, 0) = {
+ASN1_SEQUENCE_ref(X509_REQ, req_cb) = {
ASN1_EMBED(X509_REQ, req_info, X509_REQ_INFO),
ASN1_EMBED(X509_REQ, sig_alg, X509_ALGOR),
ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING)
@@ -66,3 +127,47 @@ ASN1_SEQUENCE_ref(X509_REQ, 0) = {
IMPLEMENT_ASN1_FUNCTIONS(X509_REQ)
IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ)
+
+void X509_REQ_set0_distinguishing_id(X509_REQ *x, ASN1_OCTET_STRING *d_id)
+{
+ ASN1_OCTET_STRING_free(x->distinguishing_id);
+ x->distinguishing_id = d_id;
+}
+
+ASN1_OCTET_STRING *X509_REQ_get0_distinguishing_id(X509_REQ *x)
+{
+ return x->distinguishing_id;
+}
+
+/*
+ * This should only be used if the X509_REQ object was embedded inside another
+ * asn1 object and it needs a libctx to operate.
+ * Use X509_REQ_new_ex() instead if possible.
+ */
+int ossl_x509_req_set0_libctx(X509_REQ *x, OSSL_LIB_CTX *libctx,
+ const char *propq)
+{
+ if (x != NULL) {
+ x->libctx = libctx;
+ OPENSSL_free(x->propq);
+ x->propq = NULL;
+ if (propq != NULL) {
+ x->propq = OPENSSL_strdup(propq);
+ if (x->propq == NULL)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+X509_REQ *X509_REQ_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509_REQ *req = NULL;
+
+ req = (X509_REQ *)ASN1_item_new((X509_REQ_it()));
+ if (!ossl_x509_req_set0_libctx(req, libctx, propq)) {
+ X509_REQ_free(req);
+ req = NULL;
+ }
+ return req;
+}
diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c
index 7aa8b77ae73a..010578b19a31 100644
--- a/crypto/x509/x_x509.c
+++ b/crypto/x509/x_x509.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -31,7 +31,7 @@ ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = {
IMPLEMENT_ASN1_FUNCTIONS(X509_CINF)
/* X509 top level structure needs a bit of customisation */
-extern void policy_cache_free(X509_POLICY_CACHE *cache);
+extern void ossl_policy_cache_free(X509_POLICY_CACHE *cache);
static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
@@ -46,13 +46,14 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
ASN1_OCTET_STRING_free(ret->skid);
AUTHORITY_KEYID_free(ret->akid);
CRL_DIST_POINTS_free(ret->crldp);
- policy_cache_free(ret->policy_cache);
+ ossl_policy_cache_free(ret->policy_cache);
GENERAL_NAMES_free(ret->altname);
NAME_CONSTRAINTS_free(ret->nc);
#ifndef OPENSSL_NO_RFC3779
sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free);
ASIdentifiers_free(ret->rfc3779_asid);
#endif
+ ASN1_OCTET_STRING_free(ret->distinguishing_id);
/* fall thru */
@@ -73,6 +74,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
ret->rfc3779_addr = NULL;
ret->rfc3779_asid = NULL;
#endif
+ ret->distinguishing_id = NULL;
ret->aux = NULL;
ret->crldp = NULL;
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data))
@@ -85,19 +87,46 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
ASN1_OCTET_STRING_free(ret->skid);
AUTHORITY_KEYID_free(ret->akid);
CRL_DIST_POINTS_free(ret->crldp);
- policy_cache_free(ret->policy_cache);
+ ossl_policy_cache_free(ret->policy_cache);
GENERAL_NAMES_free(ret->altname);
NAME_CONSTRAINTS_free(ret->nc);
#ifndef OPENSSL_NO_RFC3779
sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free);
ASIdentifiers_free(ret->rfc3779_asid);
#endif
+ ASN1_OCTET_STRING_free(ret->distinguishing_id);
+ OPENSSL_free(ret->propq);
break;
+ case ASN1_OP_DUP_POST:
+ {
+ X509 *old = exarg;
+
+ if (!ossl_x509_set0_libctx(ret, old->libctx, old->propq))
+ return 0;
+ }
+ break;
+ case ASN1_OP_GET0_LIBCTX:
+ {
+ OSSL_LIB_CTX **libctx = exarg;
+
+ *libctx = ret->libctx;
+ }
+ break;
+
+ case ASN1_OP_GET0_PROPQ:
+ {
+ const char **propq = exarg;
+
+ *propq = ret->propq;
+ }
+ break;
+
+ default:
+ break;
}
return 1;
-
}
ASN1_SEQUENCE_ref(X509, x509_cb) = {
@@ -107,15 +136,46 @@ ASN1_SEQUENCE_ref(X509, x509_cb) = {
} ASN1_SEQUENCE_END_ref(X509, X509)
IMPLEMENT_ASN1_FUNCTIONS(X509)
-
IMPLEMENT_ASN1_DUP_FUNCTION(X509)
+/*
+ * This should only be used if the X509 object was embedded inside another
+ * asn1 object and it needs a libctx to operate.
+ * Use X509_new_ex() instead if possible.
+ */
+int ossl_x509_set0_libctx(X509 *x, OSSL_LIB_CTX *libctx, const char *propq)
+{
+ if (x != NULL) {
+ x->libctx = libctx;
+ OPENSSL_free(x->propq);
+ x->propq = NULL;
+ if (propq != NULL) {
+ x->propq = OPENSSL_strdup(propq);
+ if (x->propq == NULL)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+X509 *X509_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
+{
+ X509 *cert = NULL;
+
+ cert = (X509 *)ASN1_item_new_ex(X509_it(), libctx, propq);
+ if (!ossl_x509_set0_libctx(cert, libctx, propq)) {
+ X509_free(cert);
+ cert = NULL;
+ }
+ return cert;
+}
+
int X509_set_ex_data(X509 *r, int idx, void *arg)
{
return CRYPTO_set_ex_data(&r->ex_data, idx, arg);
}
-void *X509_get_ex_data(X509 *r, int idx)
+void *X509_get_ex_data(const X509 *r, int idx)
{
return CRYPTO_get_ex_data(&r->ex_data, idx);
}
@@ -163,7 +223,7 @@ X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length)
* error path, but that depends on similar hygiene in lower-level functions.
* Here we avoid compounding the problem.
*/
-static int i2d_x509_aux_internal(X509 *a, unsigned char **pp)
+static int i2d_x509_aux_internal(const X509 *a, unsigned char **pp)
{
int length, tmplen;
unsigned char *start = pp != NULL ? *pp : NULL;
@@ -197,7 +257,7 @@ static int i2d_x509_aux_internal(X509 *a, unsigned char **pp)
* the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the
* allocated buffer.
*/
-int i2d_X509_AUX(X509 *a, unsigned char **pp)
+int i2d_X509_AUX(const X509 *a, unsigned char **pp)
{
int length;
unsigned char *tmp;
@@ -213,7 +273,7 @@ int i2d_X509_AUX(X509 *a, unsigned char **pp)
/* Allocate requisite combined storage */
*pp = tmp = OPENSSL_malloc(length);
if (tmp == NULL) {
- X509err(X509_F_I2D_X509_AUX, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
return -1;
}
@@ -245,3 +305,14 @@ int X509_get_signature_nid(const X509 *x)
{
return OBJ_obj2nid(x->sig_alg.algorithm);
}
+
+void X509_set0_distinguishing_id(X509 *x, ASN1_OCTET_STRING *d_id)
+{
+ ASN1_OCTET_STRING_free(x->distinguishing_id);
+ x->distinguishing_id = d_id;
+}
+
+ASN1_OCTET_STRING *X509_get0_distinguishing_id(X509 *x)
+{
+ return x->distinguishing_id;
+}
diff --git a/crypto/x509/x_x509a.c b/crypto/x509/x_x509a.c
index c5175faef7af..f7953c269e7c 100644
--- a/crypto/x509/x_x509a.c
+++ b/crypto/x509/x_x509a.c
@@ -1,7 +1,7 @@
/*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * 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
@@ -125,6 +125,8 @@ int X509_add1_reject_object(X509 *x, const ASN1_OBJECT *obj)
{
X509_CERT_AUX *aux;
ASN1_OBJECT *objtmp;
+ int res = 0;
+
if ((objtmp = OBJ_dup(obj)) == NULL)
return 0;
if ((aux = aux_get(x)) == NULL)
@@ -132,10 +134,13 @@ int X509_add1_reject_object(X509 *x, const ASN1_OBJECT *obj)
if (aux->reject == NULL
&& (aux->reject = sk_ASN1_OBJECT_new_null()) == NULL)
goto err;
- return sk_ASN1_OBJECT_push(aux->reject, objtmp);
+ if (sk_ASN1_OBJECT_push(aux->reject, objtmp) > 0)
+ res = 1;
+
err:
- ASN1_OBJECT_free(objtmp);
- return 0;
+ if (!res)
+ ASN1_OBJECT_free(objtmp);
+ return res;
}
void X509_trust_clear(X509 *x)