From 2011b169fa90edd4d986e7dbbd3d64587d316a22 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 16 Feb 2015 13:44:22 +0000 Subject: [PATCH] Support key loading from certificate file 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 --- doc/ssl/SSL_CONF_CTX_set_flags.pod | 7 +++++ doc/ssl/SSL_CONF_cmd.pod | 6 ++-- ssl/ssl.h | 1 + ssl/ssl_conf.c | 47 ++++++++++++++++++++++++++++-- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/doc/ssl/SSL_CONF_CTX_set_flags.pod b/doc/ssl/SSL_CONF_CTX_set_flags.pod index 4e34280469..fdff4706c7 100644 --- a/doc/ssl/SSL_CONF_CTX_set_flags.pod +++ b/doc/ssl/SSL_CONF_CTX_set_flags.pod @@ -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 diff --git a/doc/ssl/SSL_CONF_cmd.pod b/doc/ssl/SSL_CONF_cmd.pod index 90a20d6c49..c4f1309c03 100644 --- a/doc/ssl/SSL_CONF_cmd.pod +++ b/doc/ssl/SSL_CONF_cmd.pod @@ -101,7 +101,7 @@ are permitted. Attempts to use the file B 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 is set. =item B<-dhparam> @@ -192,8 +192,8 @@ are permitted. Attempts to use the file B 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 file. +are permitted. Note: if no B option is set then a private key is +not loaded unless the B is set. =item B diff --git a/ssl/ssl.h b/ssl/ssl.h index 84de6a8653..c0a368b8f5 100644 --- 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 diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index 25af065233..0fd6c1f1be 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -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); -- 2.40.0