#include "ssl_locl.h"
int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+ {
+ static volatile int ssl_x509_store_ctx_idx= -1;
+ int got_write_lock = 0;
+
+ if (((size_t)&ssl_x509_store_ctx_idx&(sizeof(ssl_x509_store_ctx_idx)-1))
+ ==0) /* check alignment, practically always true */
{
- static volatile int ssl_x509_store_ctx_idx= -1;
- int got_write_lock = 0;
+ int ret;
+
+ if ((ret=ssl_x509_store_ctx_idx) < 0)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+ if ((ret=ssl_x509_store_ctx_idx) < 0)
+ {
+ ret=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 ret;
+ }
+ else /* commonly eliminated */
+ {
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
if (ssl_x509_store_ctx_idx < 0)
return ssl_x509_store_ctx_idx;
}
+ }
void ssl_cert_set_default_md(CERT *cert)
{
rpk->privatekey = cpk->privatekey;
CRYPTO_add(&cpk->privatekey->references, 1,
CRYPTO_LOCK_EVP_PKEY);
-
- switch(i)
- {
- /* If there was anything special to do for
- * certain types of keys, we'd do it here.
- * (Nothing at the moment, I think.) */
-
- case SSL_PKEY_RSA_ENC:
- case SSL_PKEY_RSA_SIGN:
- /* We have an RSA key. */
- break;
-
- case SSL_PKEY_DSA_SIGN:
- /* We have a DSA key. */
- break;
-
- case SSL_PKEY_DH_RSA:
- 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)
ret->ciphers_raw = NULL;
+#ifndef OPENSSL_NO_TLSEXT
+ if (!custom_exts_copy(&ret->cli_ext, &cert->cli_ext))
+ goto err;
+ if (!custom_exts_copy(&ret->srv_ext, &cert->srv_ext))
+ goto err;
+#endif
+
return(ret);
#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
EC_KEY_free(ret->ecdh_tmp);
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ custom_exts_free(&ret->cli_ext);
+ custom_exts_free(&ret->srv_ext);
+#endif
+
ssl_cert_clear_certs(ret);
return NULL;
X509_STORE_free(c->chain_store);
if (c->ciphers_raw)
OPENSSL_free(c->ciphers_raw);
+#ifndef OPENSSL_NO_TLSEXT
+ custom_exts_free(&c->cli_ext);
+ custom_exts_free(&c->srv_ext);
+#endif
OPENSSL_free(c);
}
return 0;
for (i = 0; i < SSL_PKEY_NUM; i++)
{
- if (c->pkeys[i].x509 == x)
+ CERT_PKEY *cpk = c->pkeys + i;
+ if (cpk->x509 == x && cpk->privatekey)
{
- c->key = &c->pkeys[i];
+ c->key = cpk;
return 1;
}
}
for (i = 0; i < SSL_PKEY_NUM; i++)
{
- if (c->pkeys[i].x509 && !X509_cmp(c->pkeys[i].x509, x))
+ CERT_PKEY *cpk = c->pkeys + i;
+ if (cpk->privatekey && cpk->x509 && !X509_cmp(cpk->x509, x))
{
- c->key = &c->pkeys[i];
+ c->key = cpk;
return 1;
}
}
return 0;
for (i = idx; i < SSL_PKEY_NUM; i++)
{
- if (c->pkeys[i].x509)
+ CERT_PKEY *cpk = c->pkeys + i;
+ if (cpk->x509 && cpk->privatekey)
{
- c->key = &c->pkeys[i];
+ c->key = cpk;
return 1;
}
}
return(1);
}
-#ifndef OPENSSL_NO_DANE
-/*
- * return value:
- * -1: format or digest error
- * 0: match
- * 1: no match
- */
-int tlsa_cmp(const X509 *cert, const unsigned char *tlsa_record, unsigned int reclen)
-{
- const EVP_MD *md;
- unsigned char digest[EVP_MAX_MD_SIZE];
- unsigned int len, selector, matching_type;
- int ret;
-
- if (reclen<3) return -1;
-
- selector = tlsa_record[1];
- matching_type = tlsa_record[2];
- tlsa_record += 3;
- reclen -= 3;
-
- switch (matching_type) {
- case 0: /* exact match */
- if (selector==0) { /* full certificate */
- ret = EVP_Digest(tlsa_record,reclen,digest,&len,EVP_sha1(),NULL);
- return ret ? memcmp(cert->sha1_hash,digest,len)!=0 : -1;
- }
- else if (selector==1) { /* SubjectPublicKeyInfo */
- ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert);
-
- if (key == NULL) return -1;
- if (key->length != reclen) return 1;
-
- return memcmp(key->data,tlsa_record,reclen)!=0;
- }
- return -1;
-
- case 1: /* SHA256 */
- case 2: /* SHA512 */
- md = matching_type==1 ? EVP_sha256() : EVP_sha512();
-
- if (reclen!=EVP_MD_size(md)) return -1;
-
- if (selector==0) { /* full certificate */
- ret = X509_digest(cert,md,digest,&len);
- }
- else if (selector==1) { /* SubjectPublicKeyInfo */
- ret = X509_pubkey_digest(cert,md,digest,&len);
- }
- else
- return -1;
-
- return ret ? memcmp(tlsa_record,digest,len)!=0 : -1;
- default:
- return -1;
- }
-}
-
-int dane_verify_callback(int ok, X509_STORE_CTX *ctx)
-{
- SSL *s = X509_STORE_CTX_get_ex_data(ctx,SSL_get_ex_data_X509_STORE_CTX_idx());
- int depth=X509_STORE_CTX_get_error_depth(ctx);
- X509 *cert = sk_X509_value(ctx->chain,depth);
- unsigned int reclen, certificate_usage, witness_usage=0x100;
- const unsigned char *tlsa_record = s->tlsa_record;
- int tlsa_ret = -1;
-
- if (s->verify_callback) ok = s->verify_callback(ok,ctx);
-
- if (tlsa_record == NULL) return ok;
-
- if (tlsa_record == (void*)-1) {
- ctx->error = X509_V_ERR_INVALID_CA; /* temporary code? */
- return 0;
- }
-
- while ((reclen = *(unsigned int *)tlsa_record)) {
- tlsa_record += sizeof(unsigned int);
-
- /*
- * tlsa_record[0] Certificate Usage field
- * tlsa_record[1] Selector field
- * tlsa_record[2] Matching Type Field
- * tlsa_record+3 Certificate Association data
- */
- certificate_usage = tlsa_record[0];
-
- if (depth==0 || certificate_usage==0 || certificate_usage==2) {
- tlsa_ret = tlsa_cmp(cert,tlsa_record,reclen);
- if (tlsa_ret==0) {
- s->tlsa_witness = depth<<8|certificate_usage;
- break;
- }
- else if (tlsa_ret==-1)
- s->tlsa_witness = -1; /* something phishy? */
- }
-
- tlsa_record += reclen;
- }
-
- if (depth==0) {
- switch (s->tlsa_witness&0xff) { /* witnessed usage */
- case 0: /* CA constraint */
- if (s->tlsa_witness<0 && ctx->error==X509_V_OK)
- ctx->error = X509_V_ERR_INVALID_CA;
- return 0;
- case 1: /* service certificate constraint */
- if (tlsa_ret!=0 && ctx->error==X509_V_OK)
- ctx->error = X509_V_ERR_CERT_UNTRUSTED;
- return 0;
- case 2: /* trust anchor assertion */
- if ((s->tlsa_witness>>8)>0 && ctx->error==X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
- ctx->error = X509_V_OK;
- break;
- case 3: /* domain-issued certificate */
- if (tlsa_ret==0)
- ctx->error = X509_V_OK; /* override all errors? */
- break;
- default:/* there were TLSA records, but something phishy happened */
- ctx->error = X509_V_ERR_CERT_UNTRUSTED;
- return ok;
- }
- }
-
- /*
- * returning 1 makes verify procedure traverse the whole chain,
- * not actually approve it...
- */
- return 1;
-}
-#endif
-
int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
{
X509 *x;
*/
X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
-#ifndef OPENSSL_NO_DANE
- X509_STORE_CTX_set_verify_cb(&ctx, dane_verify_callback);
- s->tlsa_witness = -1;
-#else
if (s->verify_callback)
X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
-#endif
if (s->ctx->app_verify_callback != NULL)
#if 1 /* new with OpenSSL 0.9.7 */
X509_STORE_CTX xs_ctx;
STACK_OF(X509) *chain = NULL, *untrusted = NULL;
X509 *x;
- int i;
+ int i, rv = 0;
+ unsigned long error;
if (!cpk->x509)
{
SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET);
- return 0;
+ 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))
+ {
+ error = ERR_peek_last_error();
+ if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
+ ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
+ goto err;
+ ERR_clear_error();
+ }
+ }
+ /* Add EE cert too: it might be self signed */
+ if (!X509_STORE_add_cert(chain_store, cpk->x509))
+ {
+ error = ERR_peek_last_error();
+ if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
+ ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
+ goto err;
+ ERR_clear_error();
+ }
+ }
+ else
+ {
+ if (c->chain_store)
+ chain_store = c->chain_store;
- if (c->chain_store)
- chain_store = c->chain_store;
-
- if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
- untrusted = cpk->chain;
+ 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;
+ 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)
+ {
+ if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR)
+ ERR_clear_error();
+ i = 1;
+ rv = 2;
+ }
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;
+ 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 */
X509_free(x);
if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT)
{
- x = sk_X509_pop(chain);
- X509_free(x);
+ 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;
+ if (rv == 0)
+ rv = 1;
+ err:
+ if (flags & SSL_BUILD_CHAIN_FLAG_CHECK)
+ X509_STORE_free(chain_store);
- return 1;
+ return rv;
}
int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)