X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_cert.c;h=eb41cfda93e70afd05ac98b0dea26a96256189fd;hp=bd68730cd3723806d6c85565c771b45be58e96eb;hb=6660baee66e474058229911950e26e56f31fb0bf;hpb=2a82c7cf252387b67d79383d518fad4a10bb253e diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index bd68730cd3..eb41cfda93 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2007 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 @@ -73,12 +73,12 @@ * 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/)" + * 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 - * openssl-core@OpenSSL.org. + * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written @@ -87,7 +87,7 @@ * 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/)" + * 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 @@ -102,37 +102,84 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ #include -#include -#ifndef WIN32 -#ifndef VMS -#include -#endif + +#include "e_os.h" +#ifndef NO_SYS_TYPES_H +# include #endif + +#include "o_dir.h" #include #include #include +#include +#ifndef OPENSSL_NO_DH +#include +#endif +#include #include "ssl_locl.h" int SSL_get_ex_data_X509_STORE_CTX_idx(void) { - static int ssl_x509_store_ctx_idx= -1; + static volatile int ssl_x509_store_ctx_idx= -1; + int got_write_lock = 0; + + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); if (ssl_x509_store_ctx_idx < 0) { - ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index( - 0,"SSL for verify callback",NULL,NULL,NULL); + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + got_write_lock = 1; + + if (ssl_x509_store_ctx_idx < 0) + { + ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index( + 0,"SSL for verify callback",NULL,NULL,NULL); + } } - return(ssl_x509_store_ctx_idx); + + if (got_write_lock) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + else + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + + return ssl_x509_store_ctx_idx; + } + +void ssl_cert_set_default_md(CERT *cert) + { + /* Set digest values to defaults */ +#ifndef OPENSSL_NO_DSA + cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1(); +#endif +#ifndef OPENSSL_NO_RSA + cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1(); + cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1(); +#endif +#ifndef OPENSSL_NO_ECDSA + cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1(); +#endif } CERT *ssl_cert_new(void) { CERT *ret; - ret=(CERT *)Malloc(sizeof(CERT)); + ret=(CERT *)OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { SSLerr(SSL_F_SSL_CERT_NEW,ERR_R_MALLOC_FAILURE); @@ -142,7 +189,7 @@ CERT *ssl_cert_new(void) ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]); ret->references=1; - + ssl_cert_set_default_md(ret); return(ret); } @@ -151,7 +198,7 @@ CERT *ssl_cert_dup(CERT *cert) CERT *ret; int i; - ret = (CERT *)Malloc(sizeof(CERT)); + ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); @@ -165,48 +212,81 @@ CERT *ssl_cert_dup(CERT *cert) * if you find that more readable */ ret->valid = cert->valid; - ret->mask = cert->mask; - ret->export_mask = cert->export_mask; + ret->mask_k = cert->mask_k; + ret->mask_a = cert->mask_a; + ret->export_mask_k = cert->export_mask_k; + ret->export_mask_a = cert->export_mask_a; -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA if (cert->rsa_tmp != NULL) { + RSA_up_ref(cert->rsa_tmp); ret->rsa_tmp = cert->rsa_tmp; - CRYPTO_add(&ret->rsa_tmp->references, 1, CRYPTO_LOCK_RSA); } ret->rsa_tmp_cb = cert->rsa_tmp_cb; #endif -#ifndef NO_DH +#ifndef OPENSSL_NO_DH if (cert->dh_tmp != NULL) { - /* DH parameters don't have a reference count (and cannot - * reasonably be shared anyway, as the secret exponent may - * be created just when it is needed -- earlier library - * versions did not pay attention to this) */ ret->dh_tmp = DHparams_dup(cert->dh_tmp); if (ret->dh_tmp == NULL) { - SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_DH_LIB); + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_DH_LIB); goto err; } + if (cert->dh_tmp->priv_key) + { + BIGNUM *b = BN_dup(cert->dh_tmp->priv_key); + if (!b) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB); + goto err; + } + ret->dh_tmp->priv_key = b; + } + if (cert->dh_tmp->pub_key) + { + BIGNUM *b = BN_dup(cert->dh_tmp->pub_key); + if (!b) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB); + goto err; + } + ret->dh_tmp->pub_key = b; + } } ret->dh_tmp_cb = cert->dh_tmp_cb; #endif +#ifndef OPENSSL_NO_ECDH + if (cert->ecdh_tmp) + { + ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp); + if (ret->ecdh_tmp == NULL) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_EC_LIB); + goto err; + } + } + ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; + ret->ecdh_tmp_auto = cert->ecdh_tmp_auto; +#endif + for (i = 0; i < SSL_PKEY_NUM; i++) { - if (cert->pkeys[i].x509 != NULL) + CERT_PKEY *cpk = cert->pkeys + i; + CERT_PKEY *rpk = ret->pkeys + i; + if (cpk->x509 != NULL) { - ret->pkeys[i].x509 = cert->pkeys[i].x509; - CRYPTO_add(&ret->pkeys[i].x509->references, 1, - CRYPTO_LOCK_X509); + rpk->x509 = cpk->x509; + CRYPTO_add(&rpk->x509->references, 1, CRYPTO_LOCK_X509); } - if (cert->pkeys[i].privatekey != NULL) + if (cpk->privatekey != NULL) { - ret->pkeys[i].privatekey = cert->pkeys[i].privatekey; - CRYPTO_add(&ret->pkeys[i].privatekey->references, 1, + rpk->privatekey = cpk->privatekey; + CRYPTO_add(&cpk->privatekey->references, 1, CRYPTO_LOCK_EVP_PKEY); switch(i) @@ -228,42 +308,169 @@ CERT *ssl_cert_dup(CERT *cert) case SSL_PKEY_DH_DSA: /* We have a DH key. */ break; - + + case SSL_PKEY_ECC: + /* We have an ECC key */ + break; + default: /* Can't happen. */ SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); } } + + if (cpk->chain) + { + int j; + rpk->chain = sk_X509_dup(cpk->chain); + if (!rpk->chain) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + goto err; + } + for (j = 0; j < sk_X509_num(rpk->chain); j++) + { + X509 *x = sk_X509_value(rpk->chain, j); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + } + } + rpk->valid_flags = 0; + if (cert->pkeys[i].authz != NULL) + { + /* Just copy everything. */ + ret->pkeys[i].authz_length = + cert->pkeys[i].authz_length; + ret->pkeys[i].authz = + OPENSSL_malloc(ret->pkeys[i].authz_length); + if (ret->pkeys[i].authz == NULL) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + return(NULL); + } + memcpy(ret->pkeys[i].authz, + cert->pkeys[i].authz, + cert->pkeys[i].authz_length); + } } - /* ret->extra_certs *should* exist, but currently the own certificate - * chain is held inside SSL_CTX */ - ret->references=1; + /* Set digests to defaults. NB: we don't copy existing values as they + * will be set during handshake. + */ + ssl_cert_set_default_md(ret); + /* Peer sigalgs set to NULL as we get these from handshake too */ + ret->peer_sigalgs = NULL; + ret->peer_sigalgslen = 0; + /* Configured sigalgs however we copy across */ + + if (cert->conf_sigalgs) + { + ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen); + if (!ret->conf_sigalgs) + goto err; + memcpy(ret->conf_sigalgs, cert->conf_sigalgs, + cert->conf_sigalgslen); + ret->conf_sigalgslen = cert->conf_sigalgslen; + } + else + ret->conf_sigalgs = NULL; + + if (cert->client_sigalgs) + { + ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen); + if (!ret->client_sigalgs) + goto err; + memcpy(ret->client_sigalgs, cert->client_sigalgs, + cert->client_sigalgslen); + ret->client_sigalgslen = cert->client_sigalgslen; + } + else + ret->client_sigalgs = NULL; + /* Shared sigalgs also NULL */ + ret->shared_sigalgs = NULL; + /* Copy any custom client certificate types */ + if (cert->ctypes) + { + ret->ctypes = OPENSSL_malloc(cert->ctype_num); + if (!ret->ctypes) + goto err; + memcpy(ret->ctypes, cert->ctypes, cert->ctype_num); + ret->ctype_num = cert->ctype_num; + } + + ret->cert_flags = cert->cert_flags; + + ret->cert_cb = cert->cert_cb; + ret->cert_cb_arg = cert->cert_cb_arg; + + if (cert->verify_store) + { + CRYPTO_add(&cert->verify_store->references, 1, CRYPTO_LOCK_X509_STORE); + ret->verify_store = cert->verify_store; + } + + if (cert->chain_store) + { + CRYPTO_add(&cert->chain_store->references, 1, CRYPTO_LOCK_X509_STORE); + ret->chain_store = cert->chain_store; + } return(ret); +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH) err: -#ifndef NO_RSA +#endif +#ifndef OPENSSL_NO_RSA if (ret->rsa_tmp != NULL) RSA_free(ret->rsa_tmp); #endif -#ifndef NO_DH +#ifndef OPENSSL_NO_DH if (ret->dh_tmp != NULL) DH_free(ret->dh_tmp); #endif +#ifndef OPENSSL_NO_ECDH + if (ret->ecdh_tmp != NULL) + EC_KEY_free(ret->ecdh_tmp); +#endif - for (i = 0; i < SSL_PKEY_NUM; i++) - { - if (ret->pkeys[i].x509 != NULL) - X509_free(ret->pkeys[i].x509); - if (ret->pkeys[i].privatekey != NULL) - EVP_PKEY_free(ret->pkeys[i].privatekey); - } + ssl_cert_clear_certs(ret); return NULL; } +/* Free up and clear all certificates and chains */ + +void ssl_cert_clear_certs(CERT *c) + { + int i; + if (c == NULL) + return; + for (i = 0; ipkeys + i; + if (cpk->x509) + { + X509_free(cpk->x509); + cpk->x509 = NULL; + } + if (cpk->privatekey) + { + EVP_PKEY_free(cpk->privatekey); + cpk->privatekey = NULL; + } + if (cpk->chain) + { + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = NULL; + } +#ifndef OPENSSL_NO_TLSEXT + if (cpk->authz != NULL) + OPENSSL_free(cpk->authz); +#endif + /* Clear all flags apart from explicit sign */ + cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN; + } + } void ssl_cert_free(CERT *c) { @@ -285,25 +492,32 @@ void ssl_cert_free(CERT *c) } #endif -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA if (c->rsa_tmp) RSA_free(c->rsa_tmp); #endif -#ifndef NO_DH +#ifndef OPENSSL_NO_DH if (c->dh_tmp) DH_free(c->dh_tmp); #endif - - for (i=0; ipkeys[i].x509 != NULL) - X509_free(c->pkeys[i].x509); - if (c->pkeys[i].privatekey != NULL) - EVP_PKEY_free(c->pkeys[i].privatekey); -#if 0 - if (c->pkeys[i].publickey != NULL) - EVP_PKEY_free(c->pkeys[i].publickey); +#ifndef OPENSSL_NO_ECDH + if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp); #endif - } - Free(c); + + ssl_cert_clear_certs(c); + if (c->peer_sigalgs) + OPENSSL_free(c->peer_sigalgs); + if (c->conf_sigalgs) + OPENSSL_free(c->conf_sigalgs); + if (c->client_sigalgs) + OPENSSL_free(c->client_sigalgs); + if (c->shared_sigalgs) + OPENSSL_free(c->shared_sigalgs); + if (c->ctypes) + OPENSSL_free(c->ctypes); + if (c->verify_store) + X509_STORE_free(c->verify_store); + if (c->chain_store) + X509_STORE_free(c->chain_store); + OPENSSL_free(c); } int ssl_cert_inst(CERT **o) @@ -334,12 +548,71 @@ int ssl_cert_inst(CERT **o) return(1); } +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) + { + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = chain; + return 1; + } + +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) + { + STACK_OF(X509) *dchain; + X509 *x; + int i; + if (!chain) + return ssl_cert_set0_chain(c, NULL); + dchain = sk_X509_dup(chain); + if (!dchain) + return 0; + for (i = 0; i < sk_X509_num(dchain); i++) + { + x = sk_X509_value(dchain, i); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + } + if (!ssl_cert_set0_chain(c, dchain)) + { + sk_X509_pop_free(dchain, X509_free); + return 0; + } + return 1; + } + +int ssl_cert_add0_chain_cert(CERT *c, X509 *x) + { + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (!cpk->chain) + cpk->chain = sk_X509_new_null(); + if (!cpk->chain || !sk_X509_push(cpk->chain, x)) + return 0; + return 1; + } + +int ssl_cert_add1_chain_cert(CERT *c, X509 *x) + { + if (!ssl_cert_add0_chain_cert(c, x)) + return 0; + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + return 1; + } + +void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) + { + c->cert_cb = cb; + c->cert_cb_arg = arg; + } SESS_CERT *ssl_sess_cert_new(void) { SESS_CERT *ret; - ret = Malloc(sizeof *ret); + ret = OPENSSL_malloc(sizeof *ret); if (ret == NULL) { SSLerr(SSL_F_SSL_SESS_CERT_NEW, ERR_R_MALLOC_FAILURE); @@ -389,16 +662,20 @@ void ssl_sess_cert_free(SESS_CERT *sc) #endif } -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA if (sc->peer_rsa_tmp != NULL) RSA_free(sc->peer_rsa_tmp); #endif -#ifndef NO_DH +#ifndef OPENSSL_NO_DH if (sc->peer_dh_tmp != NULL) DH_free(sc->peer_dh_tmp); #endif +#ifndef OPENSSL_NO_ECDH + if (sc->peer_ecdh_tmp != NULL) + EC_KEY_free(sc->peer_ecdh_tmp); +#endif - Free(sc); + OPENSSL_free(sc); } int ssl_set_peer_cert_type(SESS_CERT *sc,int type) @@ -411,23 +688,53 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) { X509 *x; int i; + X509_STORE *verify_store; X509_STORE_CTX ctx; + if (s->cert->verify_store) + verify_store = s->cert->verify_store; + else + verify_store = s->ctx->cert_store; + if ((sk == NULL) || (sk_X509_num(sk) == 0)) return(0); x=sk_X509_value(sk,0); - X509_STORE_CTX_init(&ctx,s->ctx->cert_store,x,sk); + if(!X509_STORE_CTX_init(&ctx,verify_store,x,sk)) + { + SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB); + return(0); + } +#if 0 if (SSL_get_verify_depth(s) >= 0) X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s)); - X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(), - (char *)s); +#endif + X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s); + + /* We need to inherit the verify parameters. These can be determined by + * the context: if its a server it will verify SSL client certificates + * or vice versa. + */ + + X509_STORE_CTX_set_default(&ctx, + s->server ? "ssl_client" : "ssl_server"); + /* Anything non-default in "param" should overwrite anything in the + * ctx. + */ + X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param); + + if (s->verify_callback) + X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); if (s->ctx->app_verify_callback != NULL) - i=s->ctx->app_verify_callback(&ctx); +#if 1 /* new with OpenSSL 0.9.7 */ + i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg); +#else + i=s->ctx->app_verify_callback(&ctx); /* should pass app_verify_arg */ +#endif else { -#ifndef NO_X509_VERIFY +#ifndef OPENSSL_NO_X509_VERIFY i=X509_verify_cert(&ctx); #else i=0; @@ -442,49 +749,49 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) return(i); } -static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,STACK_OF(X509_NAME) *list) +static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,STACK_OF(X509_NAME) *name_list) { if (*ca_list != NULL) sk_X509_NAME_pop_free(*ca_list,X509_NAME_free); - *ca_list=list; + *ca_list=name_list; } -STACK *SSL_dup_CA_list(STACK *sk) +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) { int i; - STACK *ret; + STACK_OF(X509_NAME) *ret; X509_NAME *name; - ret=sk_new_null(); - for (i=0; iclient_CA),list); + set_client_CA_list(&(s->client_CA),name_list); } -void SSL_CTX_set_client_CA_list(SSL_CTX *ctx,STACK_OF(X509_NAME) *list) +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx,STACK_OF(X509_NAME) *name_list) { - set_client_CA_list(&(ctx->client_CA),list); + set_client_CA_list(&(ctx->client_CA),name_list); } -STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(SSL_CTX *ctx) +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) { return(ctx->client_CA); } -STACK_OF(X509_NAME) *SSL_get_client_CA_list(SSL *s) +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) { if (s->type == SSL_ST_CONNECT) { /* we are in the client */ @@ -532,12 +839,12 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x) return(add_client_CA(&(ctx->client_CA),x)); } -static int name_cmp(X509_NAME **a,X509_NAME **b) +static int xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b) { return(X509_NAME_cmp(*a,*b)); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO /*! * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed; * it doesn't really have anything to do with clients (except that a common use @@ -551,14 +858,13 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) BIO *in; X509 *x=NULL; X509_NAME *xn=NULL; - STACK_OF(X509_NAME) *ret,*sk; + STACK_OF(X509_NAME) *ret = NULL,*sk; - ret=sk_X509_NAME_new(NULL); - sk=sk_X509_NAME_new(name_cmp); + sk=sk_X509_NAME_new(xname_cmp); in=BIO_new(BIO_s_file_internal()); - if ((ret == NULL) || (sk == NULL) || (in == NULL)) + if ((sk == NULL) || (in == NULL)) { SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE); goto err; @@ -569,8 +875,17 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) for (;;) { - if (PEM_read_bio_X509(in,&x,NULL) == NULL) + if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL) break; + if (ret == NULL) + { + ret = sk_X509_NAME_new_null(); + if (ret == NULL) + { + SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE); + goto err; + } + } if ((xn=X509_get_subject_name(x)) == NULL) goto err; /* check for duplicates */ xn=X509_NAME_dup(xn); @@ -593,6 +908,8 @@ err: if (sk != NULL) sk_X509_NAME_free(sk); if (in != NULL) BIO_free(in); if (x != NULL) X509_free(x); + if (ret != NULL) + ERR_clear_error(); return(ret); } #endif @@ -608,53 +925,55 @@ err: int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *file) - { - BIO *in; - X509 *x=NULL; - X509_NAME *xn=NULL; - int ret=1; - int (*oldcmp)(X509_NAME **a, X509_NAME **b); - - oldcmp=sk_X509_NAME_set_cmp_func(stack,name_cmp); - - in=BIO_new(BIO_s_file_internal()); - - if (in == NULL) { - SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE); - goto err; - } + BIO *in; + X509 *x=NULL; + X509_NAME *xn=NULL; + int ret=1; + int (*oldcmp)(const X509_NAME * const *a, const X509_NAME * const *b); - if (!BIO_read_filename(in,file)) - goto err; - - for (;;) - { - if (PEM_read_bio_X509(in,&x,NULL) == NULL) - break; - if ((xn=X509_get_subject_name(x)) == NULL) goto err; - xn=X509_NAME_dup(xn); - if (xn == NULL) goto err; - if (sk_X509_NAME_find(stack,xn) >= 0) - X509_NAME_free(xn); - else - sk_X509_NAME_push(stack,xn); - } + oldcmp=sk_X509_NAME_set_cmp_func(stack,xname_cmp); + + in=BIO_new(BIO_s_file_internal()); + + if (in == NULL) + { + SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BIO_read_filename(in,file)) + goto err; + + for (;;) + { + if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL) + break; + if ((xn=X509_get_subject_name(x)) == NULL) goto err; + xn=X509_NAME_dup(xn); + if (xn == NULL) goto err; + if (sk_X509_NAME_find(stack,xn) >= 0) + X509_NAME_free(xn); + else + sk_X509_NAME_push(stack,xn); + } - if (0) - { -err: - ret=0; - } - if(in != NULL) - BIO_free(in); - if(x != NULL) - X509_free(x); + ERR_clear_error(); - sk_X509_NAME_set_cmp_func(stack,oldcmp); + if (0) + { +err: + ret=0; + } + if(in != NULL) + BIO_free(in); + if(x != NULL) + X509_free(x); + + (void)sk_X509_NAME_set_cmp_func(stack,oldcmp); - return ret; - } + return ret; + } /*! * Add a directory of certs to a stack. @@ -667,46 +986,221 @@ err: * certs may have been added to \c stack. */ -#ifndef WIN32 -#ifndef VMS /* XXXX This may be fixed in the future */ - int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *dir) - { - DIR *d; - struct dirent *dstruct; - int ret = 0; + { + OPENSSL_DIR_CTX *d = NULL; + const char *filename; + int ret = 0; + + CRYPTO_w_lock(CRYPTO_LOCK_READDIR); - CRYPTO_w_lock(CRYPTO_LOCK_READDIR); - d = opendir(dir); + /* Note that a side effect is that the CAs will be sorted by name */ + + while((filename = OPENSSL_DIR_read(&d, dir))) + { + char buf[1024]; + int r; - /* Note that a side effect is that the CAs will be sorted by name */ - if(!d) + if(strlen(dir)+strlen(filename)+2 > sizeof buf) + { + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG); + goto err; + } + +#ifdef OPENSSL_SYS_VMS + r = BIO_snprintf(buf,sizeof buf,"%s%s",dir,filename); +#else + r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,filename); +#endif + if (r <= 0 || r >= (int)sizeof(buf)) + goto err; + if(!SSL_add_file_cert_subjects_to_stack(stack,buf)) + goto err; + } + + if (errno) + { + SYSerr(SYS_F_OPENDIR, get_last_sys_error()); + ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB); + goto err; + } + + ret = 1; + +err: + if (d) OPENSSL_DIR_end(&d); + CRYPTO_w_unlock(CRYPTO_LOCK_READDIR); + return ret; + } + +/* Add a certificate to a BUF_MEM structure */ + +static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) { - SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE); - goto err; + int n; + unsigned char *p; + + n=i2d_X509(x,NULL); + if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3))) + { + SSLerr(SSL_F_SSL_ADD_CERT_TO_BUF,ERR_R_BUF_LIB); + return 0; + } + p=(unsigned char *)&(buf->data[*l]); + l2n3(n,p); + i2d_X509(x,&p); + *l+=n+3; + + return 1; } - while((dstruct=readdir(d))) +/* Add certificate chain to internal SSL BUF_MEM strcuture */ +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) { - char buf[1024]; + BUF_MEM *buf = s->init_buf; + int no_chain; + int i; - if(strlen(dir)+strlen(dstruct->d_name)+2 > sizeof buf) - { - SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG); - goto err; - } - - sprintf(buf,"%s/%s",dir,dstruct->d_name); - if(!SSL_add_file_cert_subjects_to_stack(stack,buf)) - goto err; + X509 *x; + STACK_OF(X509) *extra_certs; + X509_STORE *chain_store; + + if (cpk) + x = cpk->x509; + else + x = NULL; + + if (s->cert->chain_store) + chain_store = s->cert->chain_store; + else + chain_store = s->ctx->cert_store; + + /* If we have a certificate specific chain use it, else use + * parent ctx. + */ + if (cpk && cpk->chain) + extra_certs = cpk->chain; + else + extra_certs = s->ctx->extra_certs; + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) + no_chain = 1; + else + no_chain = 0; + + /* TLSv1 sends a chain with nothing in it, instead of an alert */ + if (!BUF_MEM_grow_clean(buf,10)) + { + SSLerr(SSL_F_SSL_ADD_CERT_CHAIN,ERR_R_BUF_LIB); + return 0; + } + if (x != NULL) + { + if (no_chain) + { + if (!ssl_add_cert_to_buf(buf, l, x)) + return 0; + } + else + { + X509_STORE_CTX xs_ctx; + + if (!X509_STORE_CTX_init(&xs_ctx,chain_store,x,NULL)) + { + SSLerr(SSL_F_SSL_ADD_CERT_CHAIN,ERR_R_X509_LIB); + return(0); + } + X509_verify_cert(&xs_ctx); + /* Don't leave errors in the queue */ + ERR_clear_error(); + for (i=0; i < sk_X509_num(xs_ctx.chain); i++) + { + x = sk_X509_value(xs_ctx.chain, i); + + if (!ssl_add_cert_to_buf(buf, l, x)) + { + X509_STORE_CTX_cleanup(&xs_ctx); + return 0; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); + } + } + for (i=0; ikey; + X509_STORE_CTX xs_ctx; + STACK_OF(X509) *chain = NULL, *untrusted = NULL; + X509 *x; + int i; + + if (!cpk->x509) + { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET); + return 0; + } + + if (c->chain_store) + chain_store = c->chain_store; + + if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED) + untrusted = cpk->chain; + + if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted)) + { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB); + return 0; + } + + i = X509_verify_cert(&xs_ctx); + if (i > 0) + chain = X509_STORE_CTX_get1_chain(&xs_ctx); + X509_STORE_CTX_cleanup(&xs_ctx); + if (i <= 0) + { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED); + return 0; + } + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); + /* Remove EE certificate from chain */ + x = sk_X509_shift(chain); + X509_free(x); + if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) + { + x = sk_X509_pop(chain); + X509_free(x); + } + cpk->chain = chain; + + return 1; + } + +int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) + { + X509_STORE **pstore; + if (chain) + pstore = &c->chain_store; + else + pstore = &c->verify_store; + if (*pstore) + X509_STORE_free(*pstore); + *pstore = store; + if (ref && store) + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + return 1; + } -#endif -#endif