Add support for certificate stores in CERT structure. This makes it
[openssl.git] / ssl / ssl_cert.c
index 72443ec1f549964cdf179a45efb7d0154a9449eb..95478141a8a8b5058ee89da43e85bde9c61d53fa 100644 (file)
@@ -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
        }
 
@@ -334,6 +334,7 @@ CERT *ssl_cert_dup(CERT *cert)
                                CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
                                }
                        }
+               rpk->valid_flags = 0;
                 if (cert->pkeys[i].authz != NULL)
                        {
                        /* Just copy everything. */
@@ -360,20 +361,60 @@ CERT *ssl_cert_dup(CERT *cert)
        /* Peer sigalgs set to NULL as we get these from handshake too */
        ret->peer_sigalgs = NULL;
        ret->peer_sigalgslen = 0;
-       /* Configure sigalgs however we copy across */
+       /* Configured sigalgs however we copy across */
+
        if (cert->conf_sigalgs)
                {
-               ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen
-                                                       * sizeof(TLS_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 * sizeof(TLS_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)
@@ -426,6 +467,7 @@ void ssl_cert_clear_certs(CERT *c)
                 if (cpk->authz != NULL)
                        OPENSSL_free(cpk->authz);
 #endif
+               cpk->valid_flags = 0;
                }
        }
 
@@ -464,6 +506,16 @@ void ssl_cert_free(CERT *c)
                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);
        }
 
@@ -549,6 +601,12 @@ int ssl_cert_add1_chain_cert(CERT *c, X509 *x)
        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;
@@ -629,13 +687,19 @@ 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);
@@ -1000,12 +1064,18 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
 
        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.
         */
@@ -1036,7 +1106,7 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
                        {
                        X509_STORE_CTX xs_ctx;
 
-                       if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
+                       if (!X509_STORE_CTX_init(&xs_ctx,chain_store,x,NULL))
                                {
                                SSLerr(SSL_F_SSL_ADD_CERT_CHAIN,ERR_R_X509_LIB);
                                return(0);
@@ -1067,3 +1137,69 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
        return 1;
        }
 
+/* Build a certificate chain for current certificate */
+int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
+       {
+       CERT_PKEY *cpk = c->key;
+       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;
+       }
+