X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_cert.c;h=258da8b21d134dd0ad26ab53a4d8d973b50ada77;hp=0d1c57011311a7c45111b2fff59ff09073145443;hb=d095b68d63ca91d8e42afb5dc46bb16ed4e4e25d;hpb=ca8e5b9b8ad3c199943ad7850bf66bc03279c0b9 diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 0d1c570113..258da8b21d 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -103,48 +103,72 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ +/* ==================================================================== + * 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 + +#include "e_os.h" +#ifndef NO_SYS_TYPES_H +# include +#endif + +#if !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_VMS) && !defined(NeXT) && !defined(MAC_OS_pre_X) #include #endif + +#if defined(WIN32) +#include +#endif + +#ifdef NeXT +#include +#define dirent direct +#endif + #include #include #include +#include +#include +#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; 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); + /* any write lock will do; usually this branch + * will only be taken once anyway */ + CRYPTO_w_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_w_unlock(CRYPTO_LOCK_SSL_CTX); } - return(ssl_x509_store_ctx_idx); + return ssl_x509_store_ctx_idx; } 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); return(NULL); } memset(ret,0,sizeof(CERT)); -/* - ret->valid=0; - ret->mask=0; - ret->export_mask=0; - ret->cert_type=0; - ret->key->x509=NULL; - ret->key->publickey=NULL; - ret->key->privatekey=NULL; */ ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]); ret->references=1; @@ -157,7 +181,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); @@ -166,8 +190,6 @@ CERT *ssl_cert_dup(CERT *cert) memset(ret, 0, sizeof(CERT)); - ret->cert_type = cert->cert_type; - ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]]; /* or ret->key = ret->pkeys + (cert->key - cert->pkeys), * if you find that more readable */ @@ -176,32 +198,58 @@ CERT *ssl_cert_dup(CERT *cert) ret->mask = cert->mask; ret->export_mask = cert->export_mask; -#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) */ + /* DH parameters don't have a reference count */ 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) + { + EC_KEY_up_ref(cert->ecdh_tmp); + ret->ecdh_tmp = cert->ecdh_tmp; + } + ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; +#endif + for (i = 0; i < SSL_PKEY_NUM; i++) { if (cert->pkeys[i].x509 != NULL) @@ -236,7 +284,11 @@ 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); @@ -244,11 +296,6 @@ CERT *ssl_cert_dup(CERT *cert) } } - - /* ret->cert_chain should not exist: that's pure per-connection data. - * Anyway, we never use this function when it is non-NULL, - * so we just don't look at it. */ - /* ret->extra_certs *should* exist, but currently the own certificate * chain is held inside SSL_CTX */ @@ -256,15 +303,21 @@ CERT *ssl_cert_dup(CERT *cert) return(ret); +#ifndef OPENSSL_NO_DH /* avoid 'unreferenced label' warning if OPENSSL_NO_DH is defined */ 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++) { @@ -298,12 +351,15 @@ 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 +#ifndef OPENSSL_NO_ECDH + if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp); +#endif for (i=0; ipkeys[i].publickey); #endif } - if (c->cert_chain != NULL) - sk_X509_pop_free(c->cert_chain,X509_free); - Free(c); + OPENSSL_free(c); } -#if 1 int ssl_cert_inst(CERT **o) { /* Create a CERT if there isn't already one * (which cannot really happen, as it is initially created in * SSL_CTX_new; but the earlier code usually allows for that one * being non-existant, so we follow that behaviour, as it might - * turn out that there actually is a reason for it.). */ - + * turn out that there actually is a reason for it -- but I'm + * not sure that *all* of the existing code could cope with + * s->cert being NULL, otherwise we could do without the + * initialization in SSL_CTX_new). + */ + if (o == NULL) { SSLerr(SSL_F_SSL_CERT_INST, ERR_R_PASSED_NULL_PARAMETER); @@ -346,32 +403,80 @@ int ssl_cert_inst(CERT **o) return(1); } -#else /* Not needed any longer: SSL's always have their own copy */ -int ssl_cert_instantiate(CERT **o, CERT *d) + +SESS_CERT *ssl_sess_cert_new(void) { - CERT *n; - if (o == NULL) + SESS_CERT *ret; + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) { - SSLerr(SSL_F_SSL_CERT_INSTANTIATE, ERR_R_PASSED_NULL_PARAMETER); - return(0); + SSLerr(SSL_F_SSL_SESS_CERT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; } - if (*o != NULL && (d == NULL || *o != d)) - return(1); - if ((n = ssl_cert_new()) == NULL) + + memset(ret, 0 ,sizeof *ret); + ret->peer_key = &(ret->peer_pkeys[SSL_PKEY_RSA_ENC]); + ret->references = 1; + + return ret; + } + +void ssl_sess_cert_free(SESS_CERT *sc) + { + int i; + + if (sc == NULL) + return; + + i = CRYPTO_add(&sc->references, -1, CRYPTO_LOCK_SSL_SESS_CERT); +#ifdef REF_PRINT + REF_PRINT("SESS_CERT", sc); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { - SSLerr(SSL_F_SSL_CERT_INSTANTIATE, ERR_R_MALLOC_FAILURE); - return(0); + fprintf(stderr,"ssl_sess_cert_free, bad reference count\n"); + abort(); /* ok */ } - if (*o != NULL) - ssl_cert_free(*o); - *o = n; - return(1); - } #endif -int ssl_set_cert_type(CERT *c,int type) + /* i == 0 */ + if (sc->cert_chain != NULL) + sk_X509_pop_free(sc->cert_chain, X509_free); + for (i = 0; i < SSL_PKEY_NUM; i++) + { + if (sc->peer_pkeys[i].x509 != NULL) + X509_free(sc->peer_pkeys[i].x509); +#if 0 /* We don't have the peer's private key. These lines are just + * here as a reminder that we're still using a not-quite-appropriate + * data structure. */ + if (sc->peer_pkeys[i].privatekey != NULL) + EVP_PKEY_free(sc->peer_pkeys[i].privatekey); +#endif + } + +#ifndef OPENSSL_NO_RSA + if (sc->peer_rsa_tmp != NULL) + RSA_free(sc->peer_rsa_tmp); +#endif +#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 + + OPENSSL_free(sc); + } + +int ssl_set_peer_cert_type(SESS_CERT *sc,int type) { - c->cert_type=type; + sc->peer_cert_type = type; return(1); } @@ -385,17 +490,38 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) 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,s->ctx->cert_store,x,sk)) + { + SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB); + return(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); + X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s); + + /* We need to set the verify purpose. The purpose can be determined by + * the context: if its a server it will verify SSL client certificates + * or vice versa. + */ + if (s->server) + i = X509_PURPOSE_SSL_CLIENT; + else + i = X509_PURPOSE_SSL_SERVER; + + X509_STORE_CTX_purpose_inherit(&ctx, i, s->purpose, s->trust); + + 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; @@ -410,41 +536,41 @@ 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) @@ -500,12 +626,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 @@ -521,8 +647,8 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) X509_NAME *xn=NULL; STACK_OF(X509_NAME) *ret,*sk; - ret=sk_X509_NAME_new(NULL); - sk=sk_X509_NAME_new(name_cmp); + ret=sk_X509_NAME_new_null(); + sk=sk_X509_NAME_new(xname_cmp); in=BIO_new(BIO_s_file_internal()); @@ -537,7 +663,7 @@ 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 ((xn=X509_get_subject_name(x)) == NULL) goto err; /* check for duplicates */ @@ -576,53 +702,53 @@ 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) - { + if (0) + { err: - ret=0; - } - if(in != NULL) - BIO_free(in); - if(x != NULL) - X509_free(x); - - sk_X509_NAME_set_cmp_func(stack,oldcmp); + ret=0; + } + if(in != NULL) + BIO_free(in); + if(x != NULL) + X509_free(x); + + sk_X509_NAME_set_cmp_func(stack,oldcmp); - return ret; - } + return ret; + } /*! * Add a directory of certs to a stack. @@ -635,37 +761,131 @@ err: * certs may have been added to \c stack. */ -#ifndef WIN32 +#ifndef OPENSSL_SYS_WIN32 +#ifndef OPENSSL_SYS_VMS /* XXXX This may be fixed in the future */ +#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! */ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *dir) - { - DIR *d=opendir(dir); - struct dirent *dstruct; - - /* Note that a side effect is that the CAs will be sorted by name */ - if(!d) { - SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE); - return 0; + DIR *d; + struct dirent *dstruct; + int ret = 0; + + CRYPTO_w_lock(CRYPTO_LOCK_READDIR); + d = opendir(dir); + + /* Note that a side effect is that the CAs will be sorted by name */ + if(!d) + { + SYSerr(SYS_F_OPENDIR, get_last_sys_error()); + ERR_add_error_data(3, "opendir('", dir, "')"); + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB); + goto err; + } + + while((dstruct=readdir(d))) + { + char buf[1024]; + int r; + + 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; + } + + r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,dstruct->d_name); + if (r <= 0 || r >= (int)sizeof(buf)) + goto err; + if(!SSL_add_file_cert_subjects_to_stack(stack,buf)) + goto err; + } + ret = 1; + +err: + if (d) closedir(d); + CRYPTO_w_unlock(CRYPTO_LOCK_READDIR); + return ret; } - while((dstruct=readdir(d))) +#endif +#endif + +#else /* OPENSSL_SYS_WIN32 */ + +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *dir) { - char buf[1024]; + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + int ret = 0; +#ifdef OPENSSL_SYS_WINCE + WCHAR* wdir = NULL; +#endif - 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); - return 0; - } + CRYPTO_w_lock(CRYPTO_LOCK_READDIR); - sprintf(buf,"%s/%s",dir,dstruct->d_name); - if(!SSL_add_file_cert_subjects_to_stack(stack,buf)) - return 0; +#ifdef OPENSSL_SYS_WINCE + /* convert strings to UNICODE */ + { + BOOL result = FALSE; + int i; + wdir = malloc((strlen(dir)+1)*2); + if (wdir == NULL) + goto err_noclose; + for (i=0; i<(int)strlen(dir)+1; i++) + wdir[i] = (short)dir[i]; } +#endif - return 1; - } +#ifdef OPENSSL_SYS_WINCE + hFind = FindFirstFile(wdir, &FindFileData); +#else + hFind = FindFirstFile(dir, &FindFileData); +#endif + /* Note that a side effect is that the CAs will be sorted by name */ + if(hFind == INVALID_HANDLE_VALUE) + { + SYSerr(SYS_F_OPENDIR, get_last_sys_error()); + ERR_add_error_data(3, "opendir('", dir, "')"); + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB); + goto err_noclose; + } + + do + { + char buf[1024]; + int r; + +#ifdef OPENSSL_SYS_WINCE + if(strlen(dir)+_tcslen(FindFileData.cFileName)+2 > sizeof buf) +#else + if(strlen(dir)+strlen(FindFileData.cFileName)+2 > sizeof buf) +#endif + { + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG); + goto err; + } + + r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,FindFileData.cFileName); + if (r <= 0 || r >= sizeof buf) + goto err; + if(!SSL_add_file_cert_subjects_to_stack(stack,buf)) + goto err; + } + while (FindNextFile(hFind, &FindFileData) != FALSE); + ret = 1; + +err: + FindClose(hFind); +err_noclose: +#ifdef OPENSSL_SYS_WINCE + if (wdir != NULL) + free(wdir); +#endif + CRYPTO_w_unlock(CRYPTO_LOCK_READDIR); + return ret; + } #endif