Support key loading from certificate file
authorDr. Stephen Henson <steve@openssl.org>
Mon, 16 Feb 2015 13:44:22 +0000 (13:44 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 25 Mar 2015 14:19:04 +0000 (14:19 +0000)
Support loading of key and certificate from the same file if
SSL_CONF_FLAG_REQUIRE_PRIVATE is set. This is done by remembering the
filename used for each certificate type and attempting to load a private
key from the file when SSL_CONF_CTX_finish is called.

Update docs.

Reviewed-by: Richard Levitte <levitte@openssl.org>
doc/ssl/SSL_CONF_CTX_set_flags.pod
doc/ssl/SSL_CONF_cmd.pod
ssl/ssl.h
ssl/ssl_conf.c

index 4e34280..fdff470 100644 (file)
@@ -40,6 +40,13 @@ both of these flags must be set.
 
 recognise certificate and private key options.
 
+=item SSL_CONF_FLAG_REQUIRE_PRIVATE
+
+If this option is set then if a private key is not specified for a certificate
+it will attempt to load a private key from the certificate file when
+SSL_CONF_CTX_finish() is called. If a key cannot be loaded from the certificate
+file an error occurs.
+
 =item SSL_CONF_FLAG_SHOW_ERRORS
 
 indicate errors relating to unrecognised options or missing arguments in
index 90a20d6..c4f1309 100644 (file)
@@ -101,7 +101,7 @@ are permitted.
 Attempts to use the file B<value> as the private key for the appropriate
 context. This option is only supported if certificate operations
 are permitted. Note: if no B<-key> option is set then a private key is
-not loaded: it does not currently use the B<-cert> file.
+not loaded unless the flag B<SSL_CONF_FLAG_REQUIRE_PRIVATE> is set.
 
 =item B<-dhparam>
 
@@ -192,8 +192,8 @@ are permitted.
 
 Attempts to use the file B<value> as the private key for the appropriate
 context. This option is only supported if certificate operations
-are permitted. Note: if no B<-key> option is set then a private key is
-not loaded: it does not currently use the B<Certificate> file.
+are permitted. Note: if no B<PrivateKey> option is set then a private key is
+not loaded unless the B<SSL_CONF_FLAG_REQUIRE_PRIVATE> is set.
 
 =item B<ServerInfoFile>
 
index 84de6a8..c0a368b 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -588,6 +588,7 @@ typedef int (*custom_ext_parse_cb) (SSL *s, unsigned int ext_type,
 # define SSL_CONF_FLAG_SERVER            0x8
 # define SSL_CONF_FLAG_SHOW_ERRORS       0x10
 # define SSL_CONF_FLAG_CERTIFICATE       0x20
+# define SSL_CONF_FLAG_REQUIRE_PRIVATE   0x40
 /* Configuration value types */
 # define SSL_CONF_TYPE_UNKNOWN           0x0
 # define SSL_CONF_TYPE_STRING            0x1
index 25af065..0fd6c1f 100644 (file)
@@ -119,6 +119,8 @@ struct ssl_conf_ctx_st {
     SSL *ssl;
     /* Pointer to SSL or SSL_CTX options field or NULL if none */
     unsigned long *poptions;
+    /* Certificate filenames for each type */
+    char *cert_filename[SSL_PKEY_NUM];
     /* Pointer to SSL or SSL_CTX cert_flags or NULL if none */
     unsigned int *pcert_flags;
     /* Current flag table being worked on */
@@ -364,12 +366,26 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
 static int cmd_Certificate(SSL_CONF_CTX *cctx, const char *value)
 {
     int rv = 1;
+    CERT *c = NULL;
     if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE))
         return -2;
-    if (cctx->ctx)
+    if (cctx->ctx) {
         rv = SSL_CTX_use_certificate_chain_file(cctx->ctx, value);
-    if (cctx->ssl)
+        c = cctx->ctx->cert;
+    }
+    if (cctx->ssl) {
         rv = SSL_use_certificate_file(cctx->ssl, value, SSL_FILETYPE_PEM);
+        c = cctx->ssl->cert;
+    }
+    if (rv > 0 && c && cctx->flags & SSL_CONF_FLAG_REQUIRE_PRIVATE) {
+        char **pfilename = &cctx->cert_filename[c->key - c->pkeys];
+        if (*pfilename)
+            OPENSSL_free(*pfilename);
+        *pfilename = BUF_strdup(value);
+        if (!*pfilename)
+            rv = 0;
+    }
+
     return rv > 0;
 }
 
@@ -595,6 +611,7 @@ int SSL_CONF_cmd_value_type(SSL_CONF_CTX *cctx, const char *cmd)
 SSL_CONF_CTX *SSL_CONF_CTX_new(void)
 {
     SSL_CONF_CTX *ret;
+    size_t i;
     ret = OPENSSL_malloc(sizeof(SSL_CONF_CTX));
     if (ret) {
         ret->flags = 0;
@@ -606,18 +623,44 @@ SSL_CONF_CTX *SSL_CONF_CTX_new(void)
         ret->pcert_flags = NULL;
         ret->tbl = NULL;
         ret->ntbl = 0;
+        for (i = 0; i < SSL_PKEY_NUM; i++)
+            ret->cert_filename[i] = NULL;
     }
     return ret;
 }
 
 int SSL_CONF_CTX_finish(SSL_CONF_CTX *cctx)
 {
+    /* See if any certificates are missing private keys */
+    size_t i;
+    CERT *c = NULL;
+    if (cctx->ctx)
+        c = cctx->ctx->cert;
+    else if (cctx->ssl)
+        c = cctx->ssl->cert;
+    if (c && cctx->flags & SSL_CONF_FLAG_REQUIRE_PRIVATE) {
+        for (i = 0; i < SSL_PKEY_NUM; i++) {
+            const char *p = cctx->cert_filename[i];
+            /*
+             * If missing private key try to load one from certificate file
+             */
+            if (p && !c->pkeys[i].privatekey) {
+                if (!cmd_PrivateKey(cctx, p))
+                    return 0;
+            }
+        }
+    }
     return 1;
 }
 
 void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx)
 {
     if (cctx) {
+        size_t i;
+        for (i = 0; i < SSL_PKEY_NUM; i++) {
+            if (cctx->cert_filename[i])
+                OPENSSL_free(cctx->cert_filename[i]);
+        }
         if (cctx->prefix)
             OPENSSL_free(cctx->prefix);
         OPENSSL_free(cctx);