Support key loading from certificate file
[openssl.git] / ssl / ssl_conf.c
index 354f218cee9ee8d803e99a3880066c6eb70639aa..0fd6c1f1be8422b0ddf56c70cc15fb0241f1ba58 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 */
@@ -257,7 +259,7 @@ static int cmd_Curves(SSL_CONF_CTX *cctx, const char *value)
     return rv > 0;
 }
 
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
 /* ECDH temporary parameters */
 static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value)
 {
@@ -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;
 }
 
@@ -421,8 +437,7 @@ static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value)
     if (cctx->ssl)
         rv = SSL_set_tmp_dh(cctx->ssl, dh);
  end:
-    if (dh)
-        DH_free(dh);
+    DH_free(dh);
     if (in)
         BIO_free(in);
     return rv > 0;
@@ -447,7 +462,7 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
     SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs"),
     SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs"),
     SSL_CONF_CMD_STRING(Curves, "curves"),
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
     SSL_CONF_CMD_STRING(ECDHParameters, "named_curve"),
 #endif
     SSL_CONF_CMD_STRING(CipherString, "cipher"),
@@ -596,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;
@@ -607,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);