update NEWS
[openssl.git] / ssl / ssl_cert.c
index c1e7ec1b7edb506d24e2f160bdd2f9a048834f67..784300e26a6401e1976a7c953acfeb90599529c5 100644 (file)
@@ -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,35 @@ CERT *ssl_cert_dup(CERT *cert)
                                SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG);
                                }
                        }
+
+               if (cpk->chain)
+                       {
+                       int j;
+                       rpk->chain = sk_X509_dup(cpk->chain);
+                       if (!rpk->chain)
+                               {
+                               SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+                               goto err;
+                               }
+                       for (j = 0; j < sk_X509_num(rpk->chain); j++)
+                               {
+                               X509 *x = sk_X509_value(rpk->chain, j);
+                               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);
+       /* Sigalgs set to NULL as we get these from handshake too */
+       ret->sigalgs = NULL;
+       ret->sigalgslen = 0;
+
+       ret->cert_cb = cert->cert_cb;
+       ret->cert_cb_arg = cert->cert_cb_arg;
 
        return(ret);
        
@@ -345,17 +366,36 @@ 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;
+       for (i = 0; i<SSL_PKEY_NUM; i++)
+               {
+               CERT_PKEY *cpk = c->pkeys + 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;
+                       }
+               }
+       }
 
 void ssl_cert_free(CERT *c)
        {
@@ -387,17 +427,10 @@ void ssl_cert_free(CERT *c)
        if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
 #endif
 
-       for (i=0; i<SSL_PKEY_NUM; i++)
-               {
-               if (c->pkeys[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->sigalgs)
+               OPENSSL_free(c->sigalgs);
        OPENSSL_free(c);
        }
 
@@ -429,6 +462,65 @@ 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;
+       }
+
+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)
        {
@@ -873,13 +965,29 @@ static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
        }
 
 /* Add certificate chain to internal SSL BUF_MEM strcuture */
-int ssl_add_cert_chain(SSL *s, X509 *x, unsigned long *l)
+int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
        {
        BUF_MEM *buf = s->init_buf;
        int no_chain;
        int i;
 
-       if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs)
+       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;
@@ -913,7 +1021,7 @@ int ssl_add_cert_chain(SSL *s, X509 *x, unsigned long *l)
                                {
                                x = sk_X509_value(xs_ctx.chain, i);
 
-                               if (ssl_add_cert_to_buf(buf, l, x))
+                               if (!ssl_add_cert_to_buf(buf, l, x))
                                        {
                                        X509_STORE_CTX_cleanup(&xs_ctx);
                                        return 0;
@@ -922,10 +1030,9 @@ int ssl_add_cert_chain(SSL *s, X509 *x, unsigned long *l)
                        X509_STORE_CTX_cleanup(&xs_ctx);
                        }
                }
-       /* Thawte special :-) */
-       for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
+       for (i=0; i<sk_X509_num(extra_certs); i++)
                {
-               x=sk_X509_value(s->ctx->extra_certs,i);
+               x=sk_X509_value(extra_certs,i);
                if (!ssl_add_cert_to_buf(buf, l, x))
                        return 0;
                }