diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2016-11-05 20:15:00 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2016-11-05 20:15:00 +0000 |
commit | 204f5f6e5b4d7ce1d8a9e7c8a2538fece2903761 (patch) | |
tree | 2630efb82903d3910b584dbc686e5e7f566bf4a9 | |
parent | 7d245fce835dec15b4abffb7d78d11b427489825 (diff) |
Part one of the alt chains changes, bring in newer modifications to
VERIFY_PARAMS - based on boringssl.
ok jsing@ miod@
-rw-r--r-- | lib/libcrypto/x509/vpm_int.h | 70 | ||||
-rw-r--r-- | lib/libcrypto/x509/x509_vfy.h | 34 | ||||
-rw-r--r-- | lib/libcrypto/x509/x509_vpm.c | 380 |
3 files changed, 411 insertions, 73 deletions
diff --git a/lib/libcrypto/x509/vpm_int.h b/lib/libcrypto/x509/vpm_int.h index e69de29bb2d..3bd357bddd9 100644 --- a/lib/libcrypto/x509/vpm_int.h +++ b/lib/libcrypto/x509/vpm_int.h @@ -0,0 +1,70 @@ +/* $OpenBSD: vpm_int.h,v 1.2 2016/11/05 20:14:59 beck Exp $ */ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2013. + */ +/* ==================================================================== + * Copyright (c) 2013 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* internal only structure to hold additional X509_VERIFY_PARAM data */ + +struct X509_VERIFY_PARAM_ID_st { + STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */ + unsigned int hostflags; /* Flags to control matching features */ + char *peername; /* Matching hostname in peer certificate */ + char *email; /* If not NULL email address to match */ + size_t emaillen; + unsigned char *ip; /* If not NULL IP address to match */ + size_t iplen; /* Length of IP address */ +}; diff --git a/lib/libcrypto/x509/x509_vfy.h b/lib/libcrypto/x509/x509_vfy.h index e3a1db24078..4b81e8a2cdd 100644 --- a/lib/libcrypto/x509/x509_vfy.h +++ b/lib/libcrypto/x509/x509_vfy.h @@ -1,4 +1,4 @@ -/* $OpenBSD: x509_vfy.h,v 1.16 2015/09/14 16:13:39 jsing Exp $ */ +/* $OpenBSD: x509_vfy.h,v 1.17 2016/11/05 20:14:59 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -147,6 +147,8 @@ typedef struct x509_lookup_method_st X509_OBJECT *ret); } X509_LOOKUP_METHOD; +typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID; + /* This structure hold all parameters associated with a verify operation * by including an X509_VERIFY_PARAM structure in related structures the * parameters used can be customized @@ -162,7 +164,8 @@ typedef struct X509_VERIFY_PARAM_st int trust; /* trust setting to check */ int depth; /* Verify depth */ STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ - } X509_VERIFY_PARAM; + X509_VERIFY_PARAM_ID *id; /* opaque ID data */ +} X509_VERIFY_PARAM; DECLARE_STACK_OF(X509_VERIFY_PARAM) @@ -288,8 +291,7 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); (long)(type),NULL) #define X509_V_OK 0 -/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ - +#define X509_V_ERR_UNSPECIFIED 1 #define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 #define X509_V_ERR_UNABLE_TO_GET_CRL 3 #define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 @@ -351,6 +353,16 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); /* The application is not happy */ #define X509_V_ERR_APPLICATION_VERIFICATION 50 +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 + +/* Caller error */ +#define X509_V_ERR_INVALID_CALL 65 +/* Issuer lookup error */ +#define X509_V_ERR_STORE_LOOKUP 66 + /* Certificate verify flags */ /* Send issuer+subject checks to verify_cb */ @@ -383,6 +395,16 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_V_FLAG_USE_DELTAS 0x2000 /* Check selfsigned CA signature */ #define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 +/* Use trusted store first */ +#define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Allow partial chains if at least one certificate is in trusted store */ +#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 + +/* If the initial chain is not trusted, do not attempt to build an alternative + * chain. Alternate chain checking was introduced in 1.0.2b. Setting this flag + * will force the behaviour to match that of previous versions. */ +#define X509_V_FLAG_NO_ALT_CHAINS 0x100000 + /* Do not check certificate or CRL validity against current time. */ #define X509_V_FLAG_NO_CHECK_TIME 0x200000 @@ -519,6 +541,10 @@ int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy); int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, STACK_OF(ASN1_OBJECT) *policies); +int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, + size_t emaillen); +int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip, + size_t iplen); int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); diff --git a/lib/libcrypto/x509/x509_vpm.c b/lib/libcrypto/x509/x509_vpm.c index 8ec972050d4..46375d798b6 100644 --- a/lib/libcrypto/x509/x509_vpm.c +++ b/lib/libcrypto/x509/x509_vpm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509_vpm.c,v 1.11 2014/09/29 04:16:49 miod Exp $ */ +/* $OpenBSD: x509_vpm.c,v 1.12 2016/11/05 20:14:59 beck Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2004. */ @@ -62,14 +62,108 @@ #include <openssl/buffer.h> #include <openssl/crypto.h> #include <openssl/lhash.h> +#include <openssl/stack.h> #include <openssl/x509.h> #include <openssl/x509v3.h> +#include "vpm_int.h" + /* X509_VERIFY_PARAM functions */ +#define SET_HOST 0 +#define ADD_HOST 1 + +static void +str_free(char *s) +{ + free(s); +} + +#define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free) + + +/* + * Post 1.0.1 sk function "deep_copy". For the moment we simply make + * these take void * and use them directly without a glorious blob of + * obfuscating macros of dubious value in front of them. All this in + * preparation for a rototilling of safestack.h (likely inspired by + * this). + */ +static void * +sk_deep_copy(void *sk_void, void *copy_func_void, void *free_func_void) +{ + _STACK *sk = sk_void; + void *(*copy_func)(void *) = copy_func_void; + void (*free_func)(void *) = copy_func_void; + _STACK *ret = sk_dup(sk); + + if (ret == NULL) + return NULL; + + size_t i; + for (i = 0; i < ret->num; i++) { + if (ret->data[i] == NULL) + continue; + ret->data[i] = copy_func(ret->data[i]); + if (ret->data[i] == NULL) { + size_t j; + for (j = 0; j < i; j++) { + if (ret->data[j] != NULL) + free_func(ret->data[j]); + } + sk_free(ret); + return NULL; + } + } + + return ret; +} + +static int +int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, + const char *name, size_t namelen) +{ + char *copy; + + /* + * Refuse names with embedded NUL bytes. + * XXX: Do we need to push an error onto the error stack? + */ + if (name && memchr(name, '\0', namelen)) + return 0; + + if (mode == SET_HOST && id->hosts) { + string_stack_free(id->hosts); + id->hosts = NULL; + } + if (name == NULL || namelen == 0) + return 1; + copy = strndup(name, namelen); + if (copy == NULL) + return 0; + + if (id->hosts == NULL && + (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) { + free(copy); + return 0; + } + + if (!sk_OPENSSL_STRING_push(id->hosts, copy)) { + free(copy); + if (sk_OPENSSL_STRING_num(id->hosts) == 0) { + sk_OPENSSL_STRING_free(id->hosts); + id->hosts = NULL; + } + return 0; + } + + return 1; +} + static void x509_verify_param_zero(X509_VERIFY_PARAM *param) { + X509_VERIFY_PARAM_ID *paramid; if (!param) return; param->name = NULL; @@ -83,14 +177,35 @@ x509_verify_param_zero(X509_VERIFY_PARAM *param) sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); param->policies = NULL; } + paramid = param->id; + if (paramid->hosts) { + string_stack_free(paramid->hosts); + paramid->hosts = NULL; + } + free(paramid->peername); + paramid->peername = NULL; + free(paramid->email); + paramid->email = NULL; + paramid->emaillen = 0; + free(paramid->ip); + paramid->ip = NULL; + paramid->iplen = 0; } X509_VERIFY_PARAM * X509_VERIFY_PARAM_new(void) { X509_VERIFY_PARAM *param; - + X509_VERIFY_PARAM_ID *paramid; param = calloc(1, sizeof(X509_VERIFY_PARAM)); + if (param == NULL) + return NULL; + paramid = calloc (1, sizeof(X509_VERIFY_PARAM_ID)); + if (paramid == NULL) { + free(param); + return NULL; + } + param->id = paramid; x509_verify_param_zero(param); return param; } @@ -98,7 +213,10 @@ X509_VERIFY_PARAM_new(void) void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) { + if (param == NULL) + return; x509_verify_param_zero(param); + free(param->id); free(param); } @@ -139,21 +257,27 @@ X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) (to_overwrite || \ ((src->field != def) && (to_default || (dest->field == def)))) +/* As above but for ID fields */ + +#define test_x509_verify_param_copy_id(idf, def) \ + test_x509_verify_param_copy(id->idf, 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 - int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, const X509_VERIFY_PARAM *src) { unsigned long inh_flags; int to_default, to_overwrite; + X509_VERIFY_PARAM_ID *id; if (!src) return 1; + id = src->id; inh_flags = dest->inh_flags | src->inh_flags; if (inh_flags & X509_VP_FLAG_ONCE) @@ -194,6 +318,32 @@ X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, const X509_VERIFY_PARAM *src) return 0; } + /* Copy the host flags if and only if we're copying the host list */ + if (test_x509_verify_param_copy_id(hosts, NULL)) { + if (dest->id->hosts) { + string_stack_free(dest->id->hosts); + dest->id->hosts = NULL; + } + if (id->hosts) { + dest->id->hosts = + sk_deep_copy(id->hosts, strdup, str_free); + if (dest->id->hosts == NULL) + return 0; + dest->id->hostflags = id->hostflags; + } + } + + if (test_x509_verify_param_copy_id(email, NULL)) { + if (!X509_VERIFY_PARAM_set1_email(dest, id->email, + id->emaillen)) + return 0; + } + + if (test_x509_verify_param_copy_id(ip, NULL)) { + if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen)) + return 0; + } + return 1; } @@ -209,6 +359,33 @@ X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, const X509_VERIFY_PARAM *from) return ret; } +static int +int_x509_param_set1(char **pdest, size_t *pdestlen, const char *src, + size_t srclen) +{ + char *tmp; + if (src) { + if (srclen == 0) { + if ((tmp = strdup(src)) == NULL) + return 0; + srclen = strlen(src); + } else { + if ((tmp = malloc(srclen)) == NULL) + return 0; + memcpy(tmp, src, srclen); + } + } else { + tmp = NULL; + srclen = 0; + } + if (*pdest) + free(*pdest); + *pdest = tmp; + if (pdestlen) + *pdestlen = srclen; + return 1; +} + int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) { @@ -318,82 +495,121 @@ X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, } int +X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) +{ + return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen); +} + +int +X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) +{ + return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen); +} + +void +X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, unsigned int flags) +{ + param->id->hostflags = flags; +} + +char * +X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) +{ + return param->id->peername; +} + +int +X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, + size_t emaillen) +{ + return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen, + email, emaillen); +} + +int +X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip, + size_t iplen) +{ + if (iplen != 0 && iplen != 4 && iplen != 16) + return 0; + return int_x509_param_set1((char **)¶m->id->ip, ¶m->id->iplen, + (char *)ip, iplen); +} + +int +X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) +{ + unsigned char ipout[16]; + size_t iplen; + + iplen = (size_t)a2i_ipadd(ipout, ipasc); + if (iplen == 0) + return 0; + return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); +} + +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) { return param->depth; } -/* Default verify parameters: these are used for various - * applications and can be overridden by the user specified table. - * NB: the 'name' field *must* be in alphabetical order because it - * will be searched using OBJ_search. +const char * +X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) +{ + return param->name; +} + +static const X509_VERIFY_PARAM_ID _empty_id = { NULL }; + +#define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id + +/* + * Default verify parameters: these are used for various applications and can + * be overridden by the user specified table. */ static const X509_VERIFY_PARAM default_table[] = { { - "default", /* X509 default parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - 0, /* purpose */ - 0, /* trust */ - 100, /* depth */ - NULL /* policies */ + .name = "default", + .depth = 100, + .id = vpm_empty_id }, { - "pkcs7", /* S/MIME sign parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509_PURPOSE_SMIME_SIGN, /* purpose */ - X509_TRUST_EMAIL, /* trust */ - -1, /* depth */ - NULL /* policies */ + .name = "pkcs7", + .purpose = X509_PURPOSE_SMIME_SIGN, + .trust = X509_TRUST_EMAIL, + .depth = -1, + .id = vpm_empty_id }, { - "smime_sign", /* S/MIME sign parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509_PURPOSE_SMIME_SIGN, /* purpose */ - X509_TRUST_EMAIL, /* trust */ - -1, /* depth */ - NULL /* policies */ + .name = "smime_sign", + .purpose = X509_PURPOSE_SMIME_SIGN, + .trust = X509_TRUST_EMAIL, + .depth = -1, + .id = vpm_empty_id }, { - "ssl_client", /* SSL/TLS client parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509_PURPOSE_SSL_CLIENT, /* purpose */ - X509_TRUST_SSL_CLIENT, /* trust */ - -1, /* depth */ - NULL /* policies */ + .name = "ssl_client", + .purpose = X509_PURPOSE_SSL_CLIENT, + .trust = X509_TRUST_SSL_CLIENT, + .depth = -1, + .id = vpm_empty_id }, { - "ssl_server", /* SSL/TLS server parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509_PURPOSE_SSL_SERVER, /* purpose */ - X509_TRUST_SSL_SERVER, /* trust */ - -1, /* depth */ - NULL /* policies */ + .name = "ssl_server", + .purpose = X509_PURPOSE_SSL_SERVER, + .trust = X509_TRUST_SSL_SERVER, + .depth = -1, + .id = vpm_empty_id } }; static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; static int -table_cmp(const X509_VERIFY_PARAM *a, const X509_VERIFY_PARAM *b) -{ - return strcmp(a->name, b->name); -} - -DECLARE_OBJ_BSEARCH_CMP_FN(X509_VERIFY_PARAM, X509_VERIFY_PARAM, table); -IMPLEMENT_OBJ_BSEARCH_CMP_FN(X509_VERIFY_PARAM, X509_VERIFY_PARAM, table); - -static int param_cmp(const X509_VERIFY_PARAM * const *a, const X509_VERIFY_PARAM * const *b) { @@ -403,19 +619,21 @@ param_cmp(const X509_VERIFY_PARAM * const *a, int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) { - int idx; X509_VERIFY_PARAM *ptmp; - if (!param_table) { param_table = sk_X509_VERIFY_PARAM_new(param_cmp); if (!param_table) return 0; } else { - idx = sk_X509_VERIFY_PARAM_find(param_table, param); - if (idx != -1) { - ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); + size_t idx; + + if ((idx = sk_X509_VERIFY_PARAM_find(param_table, param)) + != -1) { + ptmp = sk_X509_VERIFY_PARAM_value(param_table, + idx); X509_VERIFY_PARAM_free(ptmp); - (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); + (void)sk_X509_VERIFY_PARAM_delete(param_table, + idx); } } if (!sk_X509_VERIFY_PARAM_push(param_table, param)) @@ -423,20 +641,44 @@ X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) return 1; } -const X509_VERIFY_PARAM * -X509_VERIFY_PARAM_lookup(const char *name) +int +X509_VERIFY_PARAM_get_count(void) +{ + int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); + if (param_table) + num += sk_X509_VERIFY_PARAM_num(param_table); + return num; +} + +const +X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id) +{ + int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); + if (id < num) + return default_table + id; + return sk_X509_VERIFY_PARAM_value(param_table, id - num); +} + +const +X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) { - int idx; X509_VERIFY_PARAM pm; + unsigned int i, limit; pm.name = (char *)name; if (param_table) { - idx = sk_X509_VERIFY_PARAM_find(param_table, &pm); - if (idx != -1) + size_t idx; + if ((idx = sk_X509_VERIFY_PARAM_find(param_table, &pm)) != -1) return sk_X509_VERIFY_PARAM_value(param_table, idx); } - return OBJ_bsearch_table(&pm, default_table, - sizeof(default_table)/sizeof(X509_VERIFY_PARAM)); + + limit = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); + for (i = 0; i < limit; i++) { + if (strcmp(default_table[i].name, name) == 0) { + return &default_table[i]; + } + } + return NULL; } void |