summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2014-02-21 19:42:03 +0000
committerDr. Stephen Henson <steve@openssl.org>2014-02-23 13:49:21 +0000
commit58b86e4235cd420f607819727d372af9f7a80224 (patch)
treea9dae8d7eb4c5fb07d7b8914d1b789b8860de420
parenta466be6243b54cf26bbdbd6c9b9c48ad75b18a09 (diff)
Option to set current cert to server certificate.
(cherry picked from commit daddd9a950e491c31f9500d5e570bc7eb96b2823)
-rw-r--r--doc/ssl/SSL_CTX_add1_chain_cert.pod8
-rw-r--r--ssl/s3_lib.c18
-rw-r--r--ssl/ssl.h1
-rw-r--r--ssl/ssl_lib.c2
4 files changed, 29 insertions, 0 deletions
diff --git a/doc/ssl/SSL_CTX_add1_chain_cert.pod b/doc/ssl/SSL_CTX_add1_chain_cert.pod
index 0c977aa1a7..7676a882ea 100644
--- a/doc/ssl/SSL_CTX_add1_chain_cert.pod
+++ b/doc/ssl/SSL_CTX_add1_chain_cert.pod
@@ -77,6 +77,14 @@ the first valid certificate or B<SSL_CERT_SET_NEXT> to set the next valid
certificate after the current certificate. These two operations can be
used to iterate over all certificates in an B<SSL_CTX> structure.
+SSL_set_current_cert() also supports the option B<SSL_CERT_SET_SERVER>.
+If B<ssl> is a server and has sent a certificate to a connected client
+this option sets that certificate to the current certificate and returns 1.
+If the negotiated ciphersuite is anonymous (and thus no certificate will
+be sent) 2 is returned and the current certificate is unchanged. If B<ssl>
+is not a server or a certificate has not been sent 0 is returned and
+the current certificate is unchanged.
+
All these functions are implemented as macros. Those containing a B<1>
increment the reference count of the supplied certificate or chain so it must
be freed at some point after the operation. Those containing a B<0> do
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 72ef809fed..f02bb7613d 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3432,6 +3432,24 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
return ssl_cert_select_current(s->cert, (X509 *)parg);
case SSL_CTRL_SET_CURRENT_CERT:
+ if (larg == SSL_CERT_SET_SERVER)
+ {
+ CERT_PKEY *cpk;
+ const SSL_CIPHER *cipher;
+ if (!s->server)
+ return 0;
+ cipher = s->s3->tmp.new_cipher;
+ if (!cipher)
+ return 0;
+ /* No certificate for unauthenticated ciphersuites */
+ if (cipher->algorithm_auth & SSL_aNULL)
+ return 2;
+ cpk = ssl_get_server_send_pkey(s);
+ if (!cpk)
+ return 0;
+ s->cert->key = cpk;
+ return 1;
+ }
return ssl_cert_set_current(s->cert, larg);
#ifndef OPENSSL_NO_EC
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 85c7966634..88ee3db672 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1942,6 +1942,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CERT_SET_FIRST 1
#define SSL_CERT_SET_NEXT 2
+#define SSL_CERT_SET_SERVER 3
#define DTLSv1_get_timeout(ssl, arg) \
SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a893dbaf0e..0103296aa9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2672,6 +2672,8 @@ CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
int i;
c = s->cert;
+ if (!s->s3 || !s->s3->tmp.new_cipher)
+ return NULL;
ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL