X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_cert.c;h=2f43d2ede1437c1965cd09de8823fa826d7221a1;hp=997528e97dfa80e5a1d399a39ad4f60d17a43b36;hb=f71c6e52f769af0d2d40ed7e1dcb4fff837837a0;hpb=3eeaab4bed46e3320947d0f609b82007b65b5a46 diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 997528e97d..2f43d2ede1 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,6 +102,11 @@ * 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. @@ -130,24 +135,46 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void) { 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) { - /* any write lock will do; usually this branch - * will only be taken once anyway */ + 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); } - - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); } + + 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; } +static 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_dss1(); +#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_ecdsa(); +#endif + } + CERT *ssl_cert_new(void) { CERT *ret; @@ -162,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); } @@ -185,8 +212,10 @@ 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 OPENSSL_NO_RSA if (cert->rsa_tmp != NULL) @@ -200,7 +229,6 @@ CERT *ssl_cert_dup(CERT *cert) #ifndef OPENSSL_NO_DH if (cert->dh_tmp != NULL) { - /* DH parameters don't have a reference count */ ret->dh_tmp = DHparams_dup(cert->dh_tmp); if (ret->dh_tmp == NULL) { @@ -234,25 +262,30 @@ CERT *ssl_cert_dup(CERT *cert) #ifndef OPENSSL_NO_ECDH if (cert->ecdh_tmp) { - EC_KEY_up_ref(cert->ecdh_tmp); - ret->ecdh_tmp = 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; #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) @@ -284,16 +317,32 @@ CERT *ssl_cert_dup(CERT *cert) SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); } } + + if (cpk->chain) + { + rpk->chain = sk_X509_dup(cpk->chain); + if (!rpk->chain) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + goto err; + } + for (i = 0; i < sk_X509_num(rpk->chain); i++) + { + X509 *x = sk_X509_value(rpk->chain, i); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + } + } } - /* 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); return(ret); -#ifndef OPENSSL_NO_DH /* avoid 'unreferenced label' warning if OPENSSL_NO_DH is defined */ +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH) err: #endif #ifndef OPENSSL_NO_RSA @@ -311,12 +360,16 @@ err: 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); + CERT_PKEY *rpk = ret->pkeys + i; + if (rpk->x509 != NULL) + X509_free(rpk->x509); + if (rpk->privatekey != NULL) + EVP_PKEY_free(rpk->privatekey); + if (rpk->chain) + sk_X509_pop_free(rpk->chain, X509_free); } + return NULL; } @@ -353,10 +406,13 @@ void ssl_cert_free(CERT *c) 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); + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509 != NULL) + X509_free(cpk->x509); + if (cpk->privatekey != NULL) + EVP_PKEY_free(cpk->privatekey); + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); #if 0 if (c->pkeys[i].publickey != NULL) EVP_PKEY_free(c->pkeys[i].publickey); @@ -393,6 +449,59 @@ 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; + } SESS_CERT *ssl_sess_cert_new(void) { @@ -485,9 +594,6 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB); return(0); } - if (s->param) - X509_VERIFY_PARAM_inherit(X509_STORE_CTX_get0_param(&ctx), - s->param); #if 0 if (SSL_get_verify_depth(s) >= 0) X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s)); @@ -501,6 +607,10 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) 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); @@ -737,6 +847,8 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, sk_X509_NAME_push(stack,xn); } + ERR_clear_error(); + if (0) { err: @@ -747,7 +859,7 @@ err: if(x != NULL) X509_free(x); - sk_X509_NAME_set_cmp_func(stack,oldcmp); + (void)sk_X509_NAME_set_cmp_func(stack,oldcmp); return ret; } @@ -812,3 +924,100 @@ err: 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) + { + 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; + } + +/* Add certificate chain to internal SSL BUF_MEM strcuture */ +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) + { + BUF_MEM *buf = s->init_buf; + int no_chain; + int i; + + X509 *x; + STACK_OF(X509) *extra_certs; + + if (cpk) + x = cpk->x509; + else + x = NULL; + + /* 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,s->ctx->cert_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; i