X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_cert.c;h=2c66460fe43c490db26ae327d374035d3df1b93a;hp=917be318760f509aa90dbdaaabc5949b2735b7d5;hb=5693a30813a031d3921a016a870420e7eb93ec90;hpb=6b7be581e52761b2a0dc5dcf35214ff813b9f9f0 diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 917be31876..2c66460fe4 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -160,18 +160,18 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void) return ssl_x509_store_ctx_idx; } -static void ssl_cert_set_default_md(CERT *cert) +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(); + 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_ecdsa(); + cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1(); #endif } @@ -270,21 +270,23 @@ CERT *ssl_cert_dup(CERT *cert) } } 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) @@ -316,16 +318,100 @@ CERT *ssl_cert_dup(CERT *cert) SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); } } + + if (cpk->chain) + { + rpk->chain = X509_chain_up_ref(cpk->chain); + if (!rpk->chain) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + goto err; + } + } + rpk->valid_flags = 0; +#ifndef OPENSSL_NO_TLSEXT + if (cert->pkeys[i].serverinfo != NULL) + { + /* Just copy everything. */ + ret->pkeys[i].serverinfo = + OPENSSL_malloc(cert->pkeys[i].serverinfo_length); + if (ret->pkeys[i].serverinfo == NULL) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->pkeys[i].serverinfo_length = + cert->pkeys[i].serverinfo_length; + memcpy(ret->pkeys[i].serverinfo, + cert->pkeys[i].serverinfo, + cert->pkeys[i].serverinfo_length); + } +#endif } - /* 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; + } + + ret->ciphers_raw = NULL; return(ret); @@ -345,17 +431,48 @@ err: 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->serverinfo) + { + OPENSSL_free(cpk->serverinfo); + cpk->serverinfo = NULL; + cpk->serverinfo_length = 0; + } +#endif + /* Clear all flags apart from explicit sign */ + cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN; + } + } void ssl_cert_free(CERT *c) { @@ -387,17 +504,23 @@ void ssl_cert_free(CERT *c) if (c->ecdh_tmp) EC_KEY_free(c->ecdh_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); -#endif - } + 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); + if (c->ciphers_raw) + OPENSSL_free(c->ciphers_raw); OPENSSL_free(c); } @@ -429,6 +552,112 @@ 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; + if (!chain) + return ssl_cert_set0_chain(c, NULL); + dchain = X509_chain_up_ref(chain); + if (!dchain) + return 0; + 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; + } + +int ssl_cert_select_current(CERT *c, X509 *x) + { + int i; + if (x == NULL) + return 0; + for (i = 0; i < SSL_PKEY_NUM; i++) + { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509 == x && cpk->privatekey) + { + c->key = cpk; + return 1; + } + } + + for (i = 0; i < SSL_PKEY_NUM; i++) + { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->privatekey && cpk->x509 && !X509_cmp(cpk->x509, x)) + { + c->key = cpk; + return 1; + } + } + return 0; + } + +int ssl_cert_set_current(CERT *c, long op) + { + int i, idx; + if (!c) + return 0; + if (op == SSL_CERT_SET_FIRST) + idx = 0; + else if (op == SSL_CERT_SET_NEXT) + { + idx = (int)(c->key - c->pkeys + 1); + if (idx >= SSL_PKEY_NUM) + return 0; + } + else + return 0; + for (i = idx; i < SSL_PKEY_NUM; i++) + { + CERT_PKEY *cpk = c->key + i; + if (cpk->x509 && cpk->privatekey) + { + c->key = cpk; + return 1; + } + } + return 0; + } + +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) { @@ -510,17 +739,25 @@ 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); - if(!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); } + /* Set suite B flags if needed */ + X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s)); #if 0 if (SSL_get_verify_depth(s) >= 0) X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s)); @@ -851,3 +1088,215 @@ 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; + 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, rv = 0; + + if (!cpk->x509) + { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET); + goto err; + } + /* Rearranging and check the chain: add everything to a store */ + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) + { + chain_store = X509_STORE_new(); + if (!chain_store) + goto err; + for (i = 0; i < sk_X509_num(cpk->chain); i++) + { + x = sk_X509_value(cpk->chain, i); + if (!X509_STORE_add_cert(chain_store, x)) + goto err; + } + /* Add EE cert too: it might be self signed */ + if (!X509_STORE_add_cert(chain_store, cpk->x509)) + goto err; + } + else + { + 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); + goto err; + } + /* Set suite B flags if needed */ + X509_STORE_CTX_set_flags(&xs_ctx, c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS); + + i = X509_verify_cert(&xs_ctx); + if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) + { + ERR_clear_error(); + i = 1; + } + if (i > 0) + chain = X509_STORE_CTX_get1_chain(&xs_ctx); + if (i <= 0) + { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED); + i = X509_STORE_CTX_get_error(&xs_ctx); + ERR_add_error_data(2, "Verify error:", + X509_verify_cert_error_string(i)); + + X509_STORE_CTX_cleanup(&xs_ctx); + goto err; + } + X509_STORE_CTX_cleanup(&xs_ctx); + 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) + { + if (sk_X509_num(chain) > 0) + { + /* See if last cert is self signed */ + x = sk_X509_value(chain, sk_X509_num(chain) - 1); + X509_check_purpose(x, -1, 0); + if (x->ex_flags & EXFLAG_SS) + { + x = sk_X509_pop(chain); + X509_free(x); + } + } + } + cpk->chain = chain; + rv = 1; + err: + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) + X509_STORE_free(chain_store); + + return rv; + } + +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; + } +