mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Changed ap_ssl_answer_challenge() and its hook to provide PEM data for
certificate and key instead of file names. Added support for this in mod_ssl and verified with a local mod_md version that uses it. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1887151 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -30,7 +30,8 @@ Changes with Apache 2.5.1
|
|||||||
available for an SSL module like mod_ssl.
|
available for an SSL module like mod_ssl.
|
||||||
- ap_ssl_answer_challenge() to enable other modules like mod_md to
|
- ap_ssl_answer_challenge() to enable other modules like mod_md to
|
||||||
provide a certificate as used in the RFC 8555 'tls-alpn-01' challenge
|
provide a certificate as used in the RFC 8555 'tls-alpn-01' challenge
|
||||||
for the ACME protocol for an SSL module like mod_ssl.
|
for the ACME protocol for an SSL module like mod_ssl. The function
|
||||||
|
and its hook provide PEM encoded data instead of file names.
|
||||||
- Hooks for 'ssl_add_cert_files', 'ssl_add_fallback_cert_files' and
|
- Hooks for 'ssl_add_cert_files', 'ssl_add_fallback_cert_files' and
|
||||||
'ssl_answer_challenge' where modules like mod_md can provide providers
|
'ssl_answer_challenge' where modules like mod_md can provide providers
|
||||||
to the above mentioned functions.
|
to the above mentioned functions.
|
||||||
|
@@ -1174,23 +1174,34 @@ AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_
|
|||||||
apr_array_header_t *key_files);
|
apr_array_header_t *key_files);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On TLS connections that do not relate to a configured virtual host,
|
* On TLS connections that do not relate to a configured virtual host
|
||||||
* allow modules to provide a certificate and key to
|
* allow modules to provide a certificate and key to be used on the connection.
|
||||||
* be used on the connection.
|
*
|
||||||
|
* A Certificate PEM added must be accompanied by a private key PEM. The private
|
||||||
|
* key PEM may be given by a NULL pointer, in which case it is expected to be found in
|
||||||
|
* the certificate PEM string.
|
||||||
*/
|
*/
|
||||||
AP_DECLARE_HOOK(int, ssl_answer_challenge, (conn_rec *c, const char *server_name,
|
AP_DECLARE_HOOK(int, ssl_answer_challenge, (conn_rec *c, const char *server_name,
|
||||||
const char **pcert_file, const char **pkey_file))
|
const char **pcert_pem, const char **pkey_pem))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns != 0 iff the connection is a challenge to the server, for example
|
* Returns != 0 iff the connection is a challenge to the server, for example
|
||||||
* as defined in RFC 8555 for the 'tls-alpn-01' domain verification, and needs
|
* as defined in RFC 8555 for the 'tls-alpn-01' domain verification, and needs
|
||||||
* a specific certificate as answer in the handshake.
|
* a specific certificate as answer in the handshake.
|
||||||
|
*
|
||||||
* ALPN protocol negotiation via the hooks 'protocol_propose' and 'protocol_switch'
|
* ALPN protocol negotiation via the hooks 'protocol_propose' and 'protocol_switch'
|
||||||
* need to have run before this call is made.
|
* need to have run before this call is made.
|
||||||
|
*
|
||||||
|
* Certificate PEMs added must be accompanied by a private key PEM. The private
|
||||||
|
* key PEM may be given by a NULL pointer, in which case it is expected to be found in
|
||||||
|
* the certificate PEM string.
|
||||||
|
*
|
||||||
|
* A certificate provided this way needs to replace any other certificates selected
|
||||||
|
* by configuration or 'ssl_add_cert_pems` on this connection.
|
||||||
*/
|
*/
|
||||||
AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
|
AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
|
||||||
const char **pcert_file, const char **pkey_file);
|
const char **pcert_pem, const char **pkey_pem);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -199,12 +199,12 @@ static void ssl_add_version_components(apr_pool_t *ptemp, apr_pool_t *pconf,
|
|||||||
|
|
||||||
int ssl_is_challenge(conn_rec *c, const char *servername,
|
int ssl_is_challenge(conn_rec *c, const char *servername,
|
||||||
X509 **pcert, EVP_PKEY **pkey,
|
X509 **pcert, EVP_PKEY **pkey,
|
||||||
const char **pcert_file, const char **pkey_file)
|
const char **pcert_pem, const char **pkey_pem)
|
||||||
{
|
{
|
||||||
*pcert = NULL;
|
*pcert = NULL;
|
||||||
*pkey = NULL;
|
*pkey = NULL;
|
||||||
*pcert_file = *pkey_file = NULL;
|
*pcert_pem = *pkey_pem = NULL;
|
||||||
if (ap_ssl_answer_challenge(c, servername, pcert_file, pkey_file)) {
|
if (ap_ssl_answer_challenge(c, servername, pcert_pem, pkey_pem)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (OK == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
|
else if (OK == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
|
||||||
|
@@ -2317,33 +2317,32 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
|
|||||||
|
|
||||||
static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
|
static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
|
||||||
SSL *ssl, X509 *cert, EVP_PKEY *key,
|
SSL *ssl, X509 *cert, EVP_PKEY *key,
|
||||||
const char *cert_file, const char *key_file)
|
const char *cert_pem, const char *key_pem)
|
||||||
{
|
{
|
||||||
SSLConnRec *sslcon = myConnConfig(c);
|
SSLConnRec *sslcon = myConnConfig(c);
|
||||||
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
int our_data = 0;
|
||||||
|
|
||||||
sslcon->service_unavailable = 1;
|
sslcon->service_unavailable = 1;
|
||||||
if (cert_file) {
|
if (cert_pem) {
|
||||||
if (SSL_use_certificate_file(ssl, cert_file, SSL_FILETYPE_PEM) < 1) {
|
cert = NULL;
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10264)
|
key = NULL;
|
||||||
"Failed to configure challenge certificate %s",
|
our_data = 1;
|
||||||
|
|
||||||
|
rv = modssl_read_cert(c->pool, cert_pem, key_pem, NULL, NULL, &cert, &key);
|
||||||
|
if (rv != APR_SUCCESS) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO()
|
||||||
|
"Failed to parse PEM of challenge certificate %s",
|
||||||
servername);
|
servername);
|
||||||
return APR_EGENERAL;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (key_file == NULL) key_file = cert_file;
|
|
||||||
if (SSL_use_PrivateKey_file(ssl, key_file, SSL_FILETYPE_PEM) < 1) {
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10265)
|
|
||||||
"Failed to configure challenge private key %s",
|
|
||||||
servername);
|
|
||||||
return APR_EGENERAL;
|
|
||||||
}
|
|
||||||
goto check;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((SSL_use_certificate(ssl, cert) < 1)) {
|
if ((SSL_use_certificate(ssl, cert) < 1)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
|
||||||
"Failed to configure challenge certificate %s",
|
"Failed to configure challenge certificate %s",
|
||||||
servername);
|
servername);
|
||||||
return APR_EGENERAL;
|
rv = APR_EGENERAL; goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SSL_use_PrivateKey(ssl, key)) {
|
if (!SSL_use_PrivateKey(ssl, key)) {
|
||||||
@@ -2351,16 +2350,19 @@ static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
|
|||||||
"error '%s' using Challenge key: %s",
|
"error '%s' using Challenge key: %s",
|
||||||
ERR_error_string(ERR_peek_last_error(), NULL),
|
ERR_error_string(ERR_peek_last_error(), NULL),
|
||||||
servername);
|
servername);
|
||||||
return APR_EGENERAL;
|
rv = APR_EGENERAL; goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
check:
|
|
||||||
if (SSL_check_private_key(ssl) < 1) {
|
if (SSL_check_private_key(ssl) < 1) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
|
||||||
"Challenge certificate and private key %s "
|
"Challenge certificate and private key %s "
|
||||||
"do not match", servername);
|
"do not match", servername);
|
||||||
return APR_EGENERAL;
|
rv = APR_EGENERAL; goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (our_data && cert) X509_free(cert);
|
||||||
|
if (our_data && key) EVP_PKEY_free(key);
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2370,10 +2372,6 @@ check:
|
|||||||
*/
|
*/
|
||||||
static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
|
static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
|
||||||
{
|
{
|
||||||
X509 *cert;
|
|
||||||
EVP_PKEY *key;
|
|
||||||
const char *cert_file, *key_file;
|
|
||||||
|
|
||||||
if (c) {
|
if (c) {
|
||||||
SSLConnRec *sslcon = myConnConfig(c);
|
SSLConnRec *sslcon = myConnConfig(c);
|
||||||
|
|
||||||
@@ -2396,16 +2394,6 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
|
|||||||
sslcon->vhost_found = +1;
|
sslcon->vhost_found = +1;
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (ssl_is_challenge(c, servername, &cert, &key, &cert_file, &key_file)) {
|
|
||||||
/* With ACMEv1 we can have challenge connections to a unknown domains
|
|
||||||
* that need to be answered with a special certificate and will
|
|
||||||
* otherwise not answer any requests. */
|
|
||||||
if (set_challenge_creds(c, servername, ssl, cert, key,
|
|
||||||
cert_file, key_file) != APR_SUCCESS) {
|
|
||||||
return APR_EGENERAL;
|
|
||||||
}
|
|
||||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044)
|
||||||
"No matching SSL virtual host for servername "
|
"No matching SSL virtual host for servername "
|
||||||
@@ -2792,11 +2780,11 @@ int ssl_callback_alpn_select(SSL *ssl,
|
|||||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||||
X509 *cert;
|
X509 *cert;
|
||||||
EVP_PKEY *key;
|
EVP_PKEY *key;
|
||||||
const char *cert_file, *key_file;
|
const char *cert_pem, *key_pem;
|
||||||
|
|
||||||
if (ssl_is_challenge(c, servername, &cert, &key, &cert_file, &key_file)) {
|
if (ssl_is_challenge(c, servername, &cert, &key, &cert_pem, &key_pem)) {
|
||||||
if (set_challenge_creds(c, servername, ssl, cert, key,
|
if (set_challenge_creds(c, servername, ssl, cert, key,
|
||||||
cert_file, key_file) != APR_SUCCESS) {
|
cert_pem, key_pem) != APR_SUCCESS) {
|
||||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||||
}
|
}
|
||||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify);
|
SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify);
|
||||||
|
@@ -527,3 +527,54 @@ void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state)
|
|||||||
sslconn->reneg_state = state;
|
sslconn->reneg_state = state;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* _________________________________________________________________
|
||||||
|
**
|
||||||
|
** Certficate/Key Stuff
|
||||||
|
** _________________________________________________________________
|
||||||
|
*/
|
||||||
|
|
||||||
|
apr_status_t modssl_read_cert(apr_pool_t *p,
|
||||||
|
const char *cert_pem, const char *key_pem,
|
||||||
|
pem_password_cb *cb, void *ud,
|
||||||
|
X509 **pcert, EVP_PKEY **pkey)
|
||||||
|
{
|
||||||
|
BIO *in;
|
||||||
|
X509 *x = NULL;
|
||||||
|
EVP_PKEY *key = NULL;
|
||||||
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
|
||||||
|
in = BIO_new_mem_buf(cert_pem, -1);
|
||||||
|
if (in == NULL) {
|
||||||
|
rv = APR_ENOMEM; goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = PEM_read_bio_X509(in, NULL, cb, ud);
|
||||||
|
if (x == NULL) {
|
||||||
|
rv = APR_ENOENT; goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO_free(in);
|
||||||
|
in = BIO_new_mem_buf(key_pem? key_pem : cert_pem, -1);
|
||||||
|
if (in == NULL) {
|
||||||
|
rv = APR_ENOMEM; goto cleanup;
|
||||||
|
}
|
||||||
|
key = PEM_read_bio_PrivateKey(in, NULL, cb, ud);
|
||||||
|
if (key == NULL) {
|
||||||
|
rv = APR_ENOENT; goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (rv == APR_SUCCESS) {
|
||||||
|
*pcert = x;
|
||||||
|
*pkey = key;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*pcert = NULL;
|
||||||
|
*pkey = NULL;
|
||||||
|
if (x) X509_free(x);
|
||||||
|
if (key) EVP_PKEY_free(key);
|
||||||
|
}
|
||||||
|
if (in != NULL) BIO_free(in);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
@@ -82,7 +82,15 @@ char *modssl_SSL_SESSION_id2sz(IDCONST unsigned char *, int, char *, int);
|
|||||||
* pool-allocated string. If empty, returns NULL. BIO_free(bio) is
|
* pool-allocated string. If empty, returns NULL. BIO_free(bio) is
|
||||||
* called for both cases. */
|
* called for both cases. */
|
||||||
char *modssl_bio_free_read(apr_pool_t *p, BIO *bio);
|
char *modssl_bio_free_read(apr_pool_t *p, BIO *bio);
|
||||||
|
|
||||||
|
/* Read a single certificate and its private key from the give string in PEM format.
|
||||||
|
* If `key_pem` is NULL, it will expect the key in `cert_pem`.
|
||||||
|
*/
|
||||||
|
apr_status_t modssl_read_cert(apr_pool_t *p,
|
||||||
|
const char *cert_pem, const char *key_pem,
|
||||||
|
pem_password_cb *cb, void *ud,
|
||||||
|
X509 **pcert, EVP_PKEY **pkey);
|
||||||
|
|
||||||
#endif /* __SSL_UTIL_SSL_H__ */
|
#endif /* __SSL_UTIL_SSL_H__ */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
@@ -2717,9 +2717,9 @@ AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_
|
|||||||
}
|
}
|
||||||
|
|
||||||
AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
|
AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
|
||||||
const char **pcert_file, const char **pkey_file)
|
const char **pcert_pem, const char **pkey_pem)
|
||||||
{
|
{
|
||||||
return (ap_run_ssl_answer_challenge(c, server_name, pcert_file, pkey_file) == OK);
|
return (ap_run_ssl_answer_challenge(c, server_name, pcert_pem, pkey_pem) == OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
AP_IMPLEMENT_HOOK_VOID(pre_read_request,
|
AP_IMPLEMENT_HOOK_VOID(pre_read_request,
|
||||||
@@ -2761,6 +2761,6 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_fallback_cert_files,
|
|||||||
apr_array_header_t *cert_files, apr_array_header_t *key_files),
|
apr_array_header_t *cert_files, apr_array_header_t *key_files),
|
||||||
(s, p, cert_files, key_files), OK, DECLINED)
|
(s, p, cert_files, key_files), OK, DECLINED)
|
||||||
AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_answer_challenge,
|
AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_answer_challenge,
|
||||||
(conn_rec *c, const char *server_name, const char **pcert_file, const char **pkey_file),
|
(conn_rec *c, const char *server_name, const char **pcert_pem, const char **pkey_pem),
|
||||||
(c, server_name, pcert_file, pkey_file), DECLINED)
|
(c, server_name, pcert_pem, pkey_pem), DECLINED)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user