Hi
Some times ago I posted a proposition as how to extend the SSLProxy stuff. I
implemented most of it and tested it for quite a time. It works as it should -
at least as much as I know!
I have done the following things for which I added the needed patches:
- If some preconditions for a quick renegotiation fail a full renegotiation
is initiated insted of returning FORBIDDEN
- The reverification of cert-chain has been fixed to realy check the full chain
- I remove the current session from the cache before the renegotiation starts
- The whole private key handling has been adapted to same schema which is
used for the 'normal' keys. That means I read the private keys in phase
1 at the time the other keys get read, convert them to ASN1 and recreate the
objects in phase 2.
- I added support for dynamic client-certificate (which another (auth) module
has to provide)
- I added support for self-signed server certificate because I often want to
simply create a self signe server cert and install it in the client (apache)
as trusted 'CA'.
I accept a self-signed-server-cert if I find a CA-Cert with the same subject
as the issuer of the server-cert, and I can verify the sever-cert with it.
- I added a hostname (CN) name check for the server certificate. Only if the
CN of the server cert is the same as the hostname part of the URL called,
the cert is accepted.
( in my old ssl-session-cache I also cache the cert-chain )
regards
matthias
-------------------------------------------------------------------------------
Matthias Loepfe, AdNovum Informatik AG, Roentgenstr. 22, CH-8005 Zurich
Email: [EMAIL PROTECTED] Voice: +41 1 272 6111 Fax: +41 1 272 6312
*** apache_1.3.6/src/modules/ssl/ssl_engine_kernel.c Sun Jul 25 14:38:20 1999
--- apache_1.3.6-2.3.9/src/modules/ssl/ssl_engine_kernel.c Tue Jul 27 22:18:28
1999
***************
*** 910,936 ****
certstore = SSL_CTX_get_cert_store(ctx);
if (certstore == NULL) {
ssl_log(r->server, SSL_LOG_ERROR, "Cannot find certificate storage");
! return FORBIDDEN;
}
! certstack = SSL_get_peer_cert_chain(ssl);
! if (certstack == NULL || sk_X509_num(certstack) == 0) {
! ssl_log(r->server, SSL_LOG_ERROR, "Cannot find peer certificate
chain");
! return FORBIDDEN;
}
- cert = sk_X509_value(certstack, 0);
- X509_STORE_CTX_init(&certstorectx, certstore, cert, certstack);
- depth = SSL_get_verify_depth(ssl);
- if (depth >= 0)
- X509_STORE_CTX_set_depth(&certstorectx, depth);
- X509_STORE_CTX_set_ex_data(&certstorectx,
- SSL_get_ex_data_X509_STORE_CTX_idx(), (char *)ssl);
- if (!X509_verify_cert(&certstorectx))
- ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
- "Re-negotiation verification step failed");
- SSL_set_verify_result(ssl, certstorectx.error);
- X509_STORE_CTX_cleanup(&certstorectx);
}
! else {
/* do a full renegotiation */
ssl_log(r->server, SSL_LOG_TRACE,
"Performing full renegotiation: complete handshake protocol");
--- 910,943 ----
certstore = SSL_CTX_get_cert_store(ctx);
if (certstore == NULL) {
ssl_log(r->server, SSL_LOG_ERROR, "Cannot find certificate storage");
! /* do a full renegotiation */
! renegotiate_quick = 0;
}
! else {
! certstack = SSL_get_peer_cert_chain(ssl);
! if (certstack == NULL /* || sk_X509_num(certstack) == 0*/) {
! ssl_log(r->server, SSL_LOG_ERROR, "Cannot find peer certificate
chain");
! /* do a full renegotiation */
! renegotiate_quick = 0;
! }
! else {
! cert = SSL_get_peer_certificate(ssl);
! X509_STORE_CTX_init(&certstorectx, certstore, cert, certstack);
! depth = SSL_get_verify_depth(ssl);
! if (depth >= 0)
! X509_STORE_CTX_set_depth(&certstorectx, depth);
! X509_STORE_CTX_set_ex_data(&certstorectx,
! SSL_get_ex_data_X509_STORE_CTX_idx(), (char *)ssl);
! if (!X509_verify_cert(&certstorectx))
! ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
! "Re-negotiation verification step failed");
! SSL_set_verify_result(ssl, certstorectx.error);
! X509_STORE_CTX_cleanup(&certstorectx);
! }
}
}
!
! if (!renegotiate_quick) {
/* do a full renegotiation */
ssl_log(r->server, SSL_LOG_TRACE,
"Performing full renegotiation: complete handshake protocol");
***************
*** 938,943 ****
--- 945,955 ----
SSL_set_session_id_context(ssl, (unsigned char *)&(r->main),
sizeof(r->main));
else
SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r));
+
+ /* clear old cache entry */
+ SSL_CTX_remove_session(ctx, ssl->session);
+
+ ssl_io_suck(r, ssl);
SSL_renegotiate(ssl);
SSL_do_handshake(ssl);
if (SSL_get_state(ssl) != SSL_ST_OK) {
*** apache_1.3.6/src/modules/ssl/mod_ssl.h Tue Jul 27 22:24:32 1999
--- apache_1.3.6-2.3.9/src/modules/ssl/mod_ssl.h Tue Jul 27 15:52:30 1999
***************
*** 478,483 ****
--- 478,492 ----
} ssl_asn1_t;
/*
+ * Define the structure of an ASN.1 cert and key store
+ */
+ typedef struct {
+ ssl_asn1_t x509;
+ ssl_asn1_t pKey;
+ int pKeyType;
+ } ssl_asn1_cert_and_key_t;
+
+ /*
* Define the mod_ssl per-module configuration structure
* (i.e. the global configuration for each httpd process)
*/
***************
*** 508,513 ****
--- 517,523 ----
#ifdef SSL_VENDOR
ap_ctx *ctx;
#endif
+ array_header *aProxyASN1Certs;
} SSLModConfigRec;
/*
***************
*** 733,738 ****
--- 743,749 ----
void ssl_io_register(void);
void ssl_io_unregister(void);
long ssl_io_data_cb(BIO *, int, const char *, int, long, long);
+ void ssl_io_suck(request_rec *, SSL *);
/* PRNG */
int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t);
*** apache_1.3.6/src/modules/ssl/ssl_engine_config.c Tue Jul 27 22:24:33 1999
--- apache_1.3.6-2.3.9/src/modules/ssl/ssl_engine_config.c Tue Jul 27 09:01:24
1999
***************
*** 149,154 ****
--- 149,155 ----
ap_hook_use("ap::mod_ssl::vendor::config_global_create",
AP_HOOK_SIG2(void,ptr), AP_HOOK_MODE_ALL, mc);
#endif
+ mc->aProxyASN1Certs = NULL;
/*
* And push it into Apache's global context
*** apache_1.3.6/src/modules/ssl/ssl_engine_ext.c Tue Jul 27 22:24:33 1999
--- apache_1.3.6-2.3.9/src/modules/ssl/ssl_engine_ext.c Tue Jul 27 09:13:44 1999
***************
*** 262,267 ****
--- 262,268 ----
*/
static void ssl_ext_mp_init(server_rec *s, pool *p)
{
+ SSLModConfigRec *mc = myModConfig();
SSLSrvConfigRec *sc;
char *cpVHostID;
int nVerify;
***************
*** 314,320 ****
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
! sk = sk_X509_INFO_new_null();
if (sc->szProxyClientCertificateFile)
SSL_CA_load_certs_file(p, sk, sc->szProxyClientCertificateFile);
if (sc->szProxyClientCertificatePath)
--- 315,345 ----
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
! array_header *asn1_stack = mc->aProxyASN1Certs;
!
! if (asn1_stack && asn1_stack->nelts) {
! int i;
! ssl_asn1_cert_and_key_t *ck =
(ssl_asn1_cert_and_key_t*)asn1_stack->elts;
!
! sk = sk_X509_INFO_new_null();
!
! for (i = 0; i < asn1_stack->nelts; i++, ck++) {
! unsigned char * ucp;
! X509_INFO * xi;
!
! xi = X509_INFO_new();
!
! ucp = ck->x509.cpData;
! d2i_X509(&(xi->x509), &ucp, ck->x509.nData);
!
! xi->x_pkey = X509_PKEY_new();
! ucp = ck->pKey.cpData;
! d2i_PrivateKey(ck->pKeyType,
&(xi->x_pkey->dec_pkey), &ucp,
! ck->pKey.nData);
!
! sk_X509_INFO_push(sk, xi);
! }
! #ifdef old
if (sc->szProxyClientCertificateFile)
SSL_CA_load_certs_file(p, sk, sc->szProxyClientCertificateFile);
if (sc->szProxyClientCertificatePath)
***************
*** 321,329 ****
SSL_CA_load_certs_path(p, sk, sc->szProxyClientCertificatePath);
ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL
proxy",
cpVHostID, sk_X509_INFO_num(sk));
! if (sk_X509_INFO_num(sk) > 0) {
! SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
! ap_ctx_set(sc->ctx, "ssl::proxy::clientcerts", (void *)sk);
}
}
--- 346,360 ----
SSL_CA_load_certs_path(p, sk, sc->szProxyClientCertificatePath);
ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL
proxy",
cpVHostID, sk_X509_INFO_num(sk));
! #endif
!
! if (sk_X509_INFO_num(sk) > 0) {
! SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
! ap_ctx_set(sc->ctx, "ssl::proxy::clientcerts", (void *)sk);
! }
! else {
! sk_X509_INFO_free(sk);
! }
}
}
***************
*** 470,475 ****
--- 501,511 ----
ap_ctx_set(fb->ctx, "ssl::proxy::servername", cpVHostID);
ap_ctx_set(fb->ctx, "ssl::proxy::verifyerror", NULL);
+ {
+ char *dyncert = ap_ctx_get(r->ctx, "ssl::proxy::dyncert");
+ ap_ctx_set(fb->ctx, "ssl::proxy::dyncert", dyncert);
+ }
+
/*
* Give us a chance to gracefully close the connection
*/
***************
*** 546,568 ****
STACK_OF(X509_INFO) *pcerts;
char *cp;
int i, j;
! pCtx = (ap_ctx *)SSL_get_app_data(ssl);
! s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
! peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
! servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
!
sc = mySrvConfig(s);
pcerts = ap_ctx_get(sc->ctx, "ssl::proxy::clientcerts");
ssl_log(s, SSL_LOG_DEBUG, "Proxy client certificate callback: (%s) entered");
! if ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <= 0)) {
ssl_log(s, SSL_LOG_TRACE,
"Proxy client certificate callback: (%s) "
"site wanted client certificate but none available",
servername);
return 0;
}
sk = SSL_get_client_CA_list(ssl);
--- 582,628 ----
STACK_OF(X509_INFO) *pcerts;
char *cp;
int i, j;
+ int ret = 0;
+ char *msg;
+ char *dyncert_str;
+ X509_INFO *dyncert;
! pCtx = (ap_ctx *)SSL_get_app_data(ssl);
! s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
! peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
! servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
! dyncert_str = ap_ctx_get(pCtx, "ssl::proxy::dyncert");
! dyncert = NULL;
!
sc = mySrvConfig(s);
pcerts = ap_ctx_get(sc->ctx, "ssl::proxy::clientcerts");
ssl_log(s, SSL_LOG_DEBUG, "Proxy client certificate callback: (%s) entered");
! if ((dyncert_str == NULL) && ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <=
0))) {
ssl_log(s, SSL_LOG_TRACE,
"Proxy client certificate callback: (%s) "
"site wanted client certificate but none available",
servername);
return 0;
+ }
+
+ if (dyncert_str) {
+ BIO *in = BIO_new(BIO_s_mem());
+ STACK_OF(X509_INFO) *isk = sk_X509_INFO_new_null();
+
+ if (in && isk) {
+ BIO_reset(in);
+ BIO_puts(in, dyncert_str);
+
+ ERR_clear_error();
+ PEM_X509_INFO_read_bio(in, isk, NULL);
+
+ dyncert = sk_X509_INFO_shift(isk);
+ }
+
+ if (in) BIO_free(in);
+ if (isk) sk_X509_INFO_free(isk);
}
sk = SSL_get_client_CA_list(ssl);
***************
*** 572,582 ****
* remote site didn't send us a list of acceptable CA certs,
* so lets send the first one we came across
*/
! xi = sk_X509_INFO_value(pcerts, 0);
cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
! ssl_log(s, SSL_LOG_DEBUG,
! "SSL Proxy: (%s) no acceptable CA list, sending %s",
! servername, cp != NULL ? cp : "-unknown-");
free(cp);
(*x509) = xi->x509;
(*pkey) = xi->x_pkey->dec_pkey;
--- 632,673 ----
* remote site didn't send us a list of acceptable CA certs,
* so lets send the first one we came across
*/
! msg = "SSL Proxy: (%s) no acceptable CA list, sending %s";
!
! if (dyncert) {
! xi = dyncert;
! }
! else {
! xi = sk_X509_INFO_value(pcerts, 0);
! }
! ret = 1;
! }
! else {
! msg = "SSL Proxy: (%s) sending %s";
!
! for (i = 0; i < sk_X509_NAME_num(sk); i++) {
! xnx = sk_X509_NAME_value(sk, i);
!
! if (dyncert && X509_NAME_cmp(X509_get_issuer_name(dyncert->x509), xnx)
== 0) {
! /* use dynamic client cert */
! xi = dyncert;
! ret = 1;
! }
! else if (pcerts) {
! for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
! xi = sk_X509_INFO_value(pcerts,j);
! issuer = X509_get_issuer_name(xi->x509);
! if (X509_NAME_cmp(issuer, xnx) == 0) {
! ret = 1;
! }
! }
! }
! }
! }
!
! if (ret == 1) {
cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
! ssl_log(s, SSL_LOG_DEBUG, msg, servername, cp != NULL ? cp : "-unknown-");
free(cp);
(*x509) = xi->x509;
(*pkey) = xi->x_pkey->dec_pkey;
***************
*** 583,614 ****
/* Prevent OpenSSL from free'ing these structures */
(*x509)->references++;
(*pkey)->references++;
- return 1;
- }
-
- for (i = 0; i < sk_X509_NAME_num(sk); i++) {
- xnx = sk_X509_NAME_value(sk, i);
- for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
- xi = sk_X509_INFO_value(pcerts,j);
- issuer = X509_get_issuer_name(xi->x509);
- if (X509_NAME_cmp(issuer, xnx) == 0) {
- cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
- ssl_log(s, SSL_LOG_DEBUG, "SSL Proxy: (%s) sending %s",
- servername, cp != NULL ? cp : "-unknown-");
- free(cp);
- (*x509) = xi->x509;
- (*pkey) = xi->x_pkey->dec_pkey;
- /* Prevent OpenSSL freeing these structures */
- (*x509)->references++;
- (*pkey)->references++;
- return 1;
- }
- }
}
! ssl_log(s, SSL_LOG_TRACE,
! "Proxy client certificate callback: (%s) "
"no client certificate found!?", servername);
! return 0;
}
/*
--- 674,689 ----
/* Prevent OpenSSL from free'ing these structures */
(*x509)->references++;
(*pkey)->references++;
}
!
! if (dyncert) {
! X509_INFO_free(dyncert);
! }
! if (ret == 0) {
! ssl_log(s, SSL_LOG_TRACE,
"no client certificate found!?", servername);
! }
!
}
/*
***************
*** 660,667 ****
--- 735,815 ----
servername, peer != NULL ? peer : "-unknown-",
errdepth, cp != NULL ? cp : "-unknown-",
cp2 != NULL ? cp2 : "-unknown");
+
free(cp);
free(cp2);
+
+ /*
+ * if the issuer cert of the self signed cert (normally the identical)
+ * can be found in the store, and the signature can be verified then allow
+ * the use of self signed certs
+ */
+ if (!ok && (errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
+ X509_OBJECT obj;
+ int luret;
+
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) Certificate Verification for remote server %s: "
+ "try to verify self signed leaf certificate",
+ servername, peer != NULL ? peer : "-unknown-");
+
+ luret = X509_STORE_get_by_subject(ctx, X509_LU_X509,
+X509_get_issuer_name(xs), &obj);
+
+ if (luret == X509_LU_X509) {
+ EVP_PKEY *pkey = NULL;
+ X509 *xi = obj.data.x509;
+
+ if ((pkey = X509_get_pubkey(xi)) != NULL) {
+
+ if (X509_verify(xs, pkey) <= 0) {
+ int errnum2 =
+X509_V_ERR_CERT_SIGNATURE_FAILURE;
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification
+failed for %s: "
+ "Error (%d): %s", servername,
+ peer != NULL ? peer : "-unknown-",
+ errnum2, X509_verify_cert_error_string(errnum2));
+ EVP_PKEY_free(pkey);
+ }
+ else {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) Certificate Verification for remote
+server %s: "
+ "issuer found in trusted certificate
+store - "
+ "accept self signed server cert",
+ servername, peer != NULL ? peer : "-unknown-");
+ X509_OBJECT_free_contents(&obj);
+ EVP_PKEY_free(pkey);
+ return 1;
+ }
+ }
+ else {
+ int errnum2 =
+X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification failed for
+%s: "
+ "Error (%d): %s", servername,
+ peer != NULL ? peer : "-unknown-",
+ errnum2, X509_verify_cert_error_string(errnum2));
+ }
+ }
+ else {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) Certificate Verification for remote server %s: "
+ "issuer not found in trusted certificate store",
+ servername, peer != NULL ? peer : "-unknown-");
+ }
+
+ if (luret != X509_LU_FAIL) {
+ X509_OBJECT_free_contents(&obj);
+ }
+ }
+
+
+ /*
+ * Additionally perform CRL-based revocation checks
+ */
+ if (ok) {
+ ok = ssl_callback_SSLVerify_CRL(ok, ctx, s);
+ errnum = X509_STORE_CTX_get_error(ctx);
+ }
/*
* If we already know it's not ok, log the real reason
***************
*** 692,698 ****
ok = FALSE;
}
}
!
/*
* And finally signal OpenSSL the (perhaps changed) state
*/
--- 840,882 ----
ok = FALSE;
}
}
!
! /*
! * check if the peer hostname is the same as the CN in the leaf cert
! */
! if (errdepth == 0) {
! char *cn = NULL;
! int j, n;
! X509_NAME *subject;
!
! subject = X509_get_subject_name(xs);
! ok = FALSE;
!
! for (j = 0; j < sk_X509_NAME_ENTRY_num(subject->entries); j++) {
! X509_NAME_ENTRY *xsne = sk_X509_NAME_ENTRY_value(subject->entries, j);
! int n = OBJ_obj2nid(xsne->object);
! if (n == NID_commonName) {
! int len = strcspn(peer, ":");
!
! if ((len == xsne->value->length) &&
! (memcmp(peer, xsne->value->data,
xsne->value->length) == 0))
! {
! ok = TRUE;
! }
! else {
! ssl_log(s, SSL_LOG_ERROR,
! "SSL Proxy: (%s) Certificate Verification failed for
%s: "
! "common name in server cert '%.*s' does not match the
server's hostname '%.*s'",
! servername, peer, xsne->value->length,
(char*)xsne->value->data,
! len, peer);
! ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
! (void *)"common name in server cert does not match the
server's hostname");
! }
! break;
! }
! }
! }
!
/*
* And finally signal OpenSSL the (perhaps changed) state
*/
*** apache_1.3.6/src/modules/ssl/ssl_engine_pphrase.c Sun Jul 25 14:38:20 1999
--- apache_1.3.6-2.3.9/src/modules/ssl/ssl_engine_pphrase.c Tue Jul 27 15:34:07
1999
***************
*** 72,81 ****
--- 72,220 ----
** _________________________________________________________________
*/
+ typedef struct ssl_pphrase_cb_info_t {
+ SSLModConfigRec * mc;
+ pool * pool;
+ ssl_ds_array * aPassPhrase;
+ int nPassPhraseCur;
+ char * cpPassPhraseCur;
+ int nPassPhraseDialog;
+ int nPassPhraseDialogCur;
+ BOOL bPassPhraseDialogOnce;
+ int nPassPhraseRetry;
+ int nPassPhrase;
+ server_rec * pServ;
+ char * cpVHostID;
+ } ssl_pphrase_cb_info_t;
+
+ static void init_ssl_pphrase_cb_info(ssl_pphrase_cb_info_t *info, SSLModConfigRec
+*mc, pool *p)
+ {
+ memset(info, 0, sizeof(*info));
+
+ info->mc = mc;
+ info->pool = p;
+ info->aPassPhrase = ssl_ds_array_make(p, sizeof(char *));
+ }
+
+ static void init_ssl_pphrase_cb_begin(ssl_pphrase_cb_info_t *info, server_rec *s,
+char *cpVHostID)
+ {
+ SSLModConfigRec *mc = info->mc;
+
+ info->cpPassPhraseCur = NULL;
+ info->nPassPhraseCur = 0;
+ info->nPassPhraseRetry = 0;
+ info->nPassPhraseDialogCur = 0;
+ info->bPassPhraseDialogOnce = TRUE;
+ info->pServ = s;
+ info->cpVHostID = cpVHostID;
+
+ myCtxVarSet(mc, 1, info->pServ);
+ myCtxVarSet(mc, 2, info->pool);
+ myCtxVarSet(mc, 3, info->aPassPhrase);
+ myCtxVarSet(mc, 4, &info->nPassPhraseCur);
+ myCtxVarSet(mc, 5, &info->cpPassPhraseCur);
+ myCtxVarSet(mc, 6, info->cpVHostID);
+ myCtxVarSet(mc, 7, &info->nPassPhraseDialog);
+ myCtxVarSet(mc, 8, &info->nPassPhraseDialogCur);
+ myCtxVarSet(mc, 9, &info->bPassPhraseDialogOnce);
+ }
+
#define STDERR_FILENO_STORE 10
#define BUILTIN_DIALOG_BACKOFF 2
#define BUILTIN_DIALOG_RETRIES 5
+ static void init_ssl_pphrase_cb_check(ssl_pphrase_cb_info_t *info, int dialog_type)
+ {
+ /*
+ * when we have more remembered pass phrases
+ * try to reuse these first.
+ */
+ if (info->nPassPhraseCur < info->nPassPhrase) {
+ info->nPassPhraseCur++;
+ info->cpPassPhraseCur = NULL;
+ return;
+ }
+
+ /*
+ * else it's not readable and we have no more
+ * remembered pass phrases. Then this has to mean
+ * that the callback function popped up the dialog
+ * but a wrong pass phrase was entered. We give the
+ * user (but not the dialog program) a few more
+ * chances...
+ */
+ if ( (dialog_type == SSL_PPTYPE_BUILTIN) &&
+ (info->cpPassPhraseCur != NULL) &&
+ (info->nPassPhraseRetry < BUILTIN_DIALOG_RETRIES) )
+ {
+ fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase incorrect "
+ "(%d more retr%s permitted).\n",
+ (BUILTIN_DIALOG_RETRIES - info->nPassPhraseRetry),
+ (BUILTIN_DIALOG_RETRIES - info->nPassPhraseRetry) == 1 ? "y" : "ies");
+ info->nPassPhraseRetry++;
+ if (info->nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF)
+ sleep((info->nPassPhraseRetry - BUILTIN_DIALOG_BACKOFF) * 5);
+ info->cpPassPhraseCur = NULL;
+ return;
+ }
+
+ /*
+ * Ok, anything else now means a fatal error.
+ */
+ if (info->cpPassPhraseCur == NULL) {
+ ssl_log(info->pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key
+not found.");
+
+ if (dialog_type == SSL_PPTYPE_BUILTIN) {
+ fprintf(stdout, "Apache:mod_ssl:Error: Private key not
+found.\n");
+ fprintf(stdout, "**Stopped\n");
+ }
+ }
+ else {
+ ssl_log(info->pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Pass phrase
+incorrect.");
+
+ if (dialog_type == SSL_PPTYPE_BUILTIN) {
+ fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase
+incorrect.\n");
+ fprintf(stdout, "**Stopped\n");
+ }
+ }
+ ssl_die();
+ return; /* make the compiler happy */
+ }
+
+ static void init_ssl_pphrase_cb_end(ssl_pphrase_cb_info_t *info, char *an)
+ {
+ /*
+ * Log the type of reading
+ */
+ if (info->nPassPhraseDialogCur == 0) {
+ ssl_log(info->pServ, SSL_LOG_TRACE,
+ "Init: (%s) unencrypted %s private key - pass phrase not
+required",
+ info->cpVHostID, an);
+ }
+ else {
+ if (info->cpPassPhraseCur != NULL) {
+ ssl_log(info->pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase
+requested",
+ info->cpVHostID, an);
+ }
+ else {
+ ssl_log(info->pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase
+reused",
+ info->cpVHostID, an);
+ }
+ }
+
+ /*
+ * Ok, when we have one more pass phrase store it
+ */
+ if (info->cpPassPhraseCur != NULL) {
+ char **cpp;
+ cpp = (char **)ssl_ds_array_push(info->aPassPhrase);
+ *cpp = info->cpPassPhraseCur;
+ info->nPassPhrase++;
+ }
+ }
+
void ssl_pphrase_Handle(server_rec *s, pool *p)
{
SSLModConfigRec *mc = myModConfig();
***************
*** 89,114 ****
X509 *pX509Cert;
FILE *fp;
BOOL bReadable;
- ssl_ds_array *aPassPhrase;
- int nPassPhrase;
- int nPassPhraseCur;
- char *cpPassPhraseCur;
- int nPassPhraseRetry;
- int nPassPhraseDialog;
- int nPassPhraseDialogCur;
- BOOL bPassPhraseDialogOnce;
char **cpp;
int i, j;
ssl_algo_t algoCert, algoKey, at;
char *an;
char *cp;
!
! /*
! * Start with a fresh pass phrase array
! */
! aPassPhrase = ssl_ds_array_make(p, sizeof(char *));
! nPassPhrase = 0;
! nPassPhraseDialog = 0;
/*
* Walk through all configured servers
--- 228,241 ----
X509 *pX509Cert;
FILE *fp;
BOOL bReadable;
char **cpp;
int i, j;
ssl_algo_t algoCert, algoKey, at;
char *an;
char *cp;
! ssl_pphrase_cb_info_t cbi;
!
! init_ssl_pphrase_cb_info(&cbi, mc, p);
/*
* Walk through all configured servers
***************
*** 116,125 ****
for (pServ = s; pServ != NULL; pServ = pServ->next) {
sc = mySrvConfig(pServ);
if (!sc->bEnabled)
continue;
- cpVHostID = ssl_util_vhostid(p, pServ);
ssl_log(pServ, SSL_LOG_INFO,
"Init: Loading certificate & private key of SSL-aware server %s",
cpVHostID);
--- 243,336 ----
for (pServ = s; pServ != NULL; pServ = pServ->next) {
sc = mySrvConfig(pServ);
+ cpVHostID = ssl_util_vhostid(p, pServ);
+
+ /*
+ * New SSL-Proxy stuff by AdNovum
+ */
+
+ if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
+ STACK_OF(X509_INFO) *sk;
+
+ sk = sk_X509_INFO_new_null();
+ if (sc->szProxyClientCertificateFile)
+ SSL_CA_load_certs_file(p, sk, sc->szProxyClientCertificateFile);
+ if (sc->szProxyClientCertificatePath)
+ SSL_CA_load_certs_path(p, sk, sc->szProxyClientCertificatePath);
+ ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL
+proxy",
+ cpVHostID, sk_X509_INFO_num(sk));
+
+ mc->aProxyASN1Certs = ap_make_array(mc->pPool,
+sk_X509_INFO_num(sk),
+ sizeof(ssl_asn1_cert_and_key_t));
+
+ for (j = 0; j < sk_X509_INFO_num(sk); j++) {
+ X509_INFO *xi =
+sk_X509_INFO_value(sk,j);
+ long len =
+(long)xi->enc_len;
+ char **pp;
+ ssl_asn1_cert_and_key_t *ck;
+ int ok;
+
+ ck = (ssl_asn1_cert_and_key_t
+*)ap_push_array(mc->aProxyASN1Certs);
+
+ ck->x509.nData = i2d_X509(xi->x509, NULL);
+ ck->x509.cpData = ap_palloc(mc->pPool, ck->x509.nData);
+ ucp = ck->x509.cpData; i2d_X509(xi->x509, &ucp); /* 2nd arg increments
+*/
+
+ if (xi->enc_data) {
+ unsigned char *edp = (unsigned
+char*)xi->enc_data;
+ X509_NAME *xsname =
+X509_get_subject_name(xi->x509);
+ char *cn = "<unknown>";
+ int k;
+
+ at = ssl_util_algotypeof(NULL, xi->x_pkey->dec_pkey);
+ an = ssl_util_algotypestr(at);
+
+ /* search 'Common Name' */
+ for (k = 0; k < sk_X509_NAME_ENTRY_num(xsname->entries); k++) {
+ X509_NAME_ENTRY *xsne =
+sk_X509_NAME_ENTRY_value(xsname->entries, k);
+ if (OBJ_obj2nid(xsne->object) == NID_commonName) {
+ cn = ap_psprintf(p, "Proxy:%s:%*s", an,
+ xsne->value->length, (char
+*)xsne->value->data);
+ break;
+ }
+ }
+
+ init_ssl_pphrase_cb_begin(&cbi, pServ, cn);
+
+ for (;;) {
+ len = (long)xi->enc_len;
+ ok = PEM_do_header(&xi->enc_cipher,
+edp, &len, ssl_pphrase_Handle_CB);
+ if (ok) break;
+ init_ssl_pphrase_cb_check(&cbi,
+sc->nPassPhraseDialogType);
+ }
+
+ if (!ok) {
+ ssl_log(pServ, SSL_LOG_ERROR,
+ "Init: Server %s failed decoding header of private key
+for "
+ "certificate %s", cpVHostID, cn);
+ ssl_die();
+ }
+
+ init_ssl_pphrase_cb_end(&cbi, an);
+
+ ck->pKey.nData = len;
+ ck->pKey.cpData = ap_palloc(mc->pPool, ck->pKey.nData);
+ ck->pKeyType = xi->x_pkey->dec_pkey->type;
+ (void)memcpy(ck->pKey.cpData, edp, len);
+ }
+ else {
+ ck->pKeyType = xi->x_pkey->dec_pkey->type;
+ ck->pKey.nData = i2d_PrivateKey(xi->x_pkey->dec_pkey,
+NULL);
+ ck->pKey.cpData = ap_palloc(mc->pPool, ck->pKey.nData);
+ ucp = ck->pKey.cpData; i2d_PrivateKey(xi->x_pkey->dec_pkey,
+&ucp);
+ }
+ }
+ sk_X509_INFO_free(sk);
+ }
+
if (!sc->bEnabled)
continue;
ssl_log(pServ, SSL_LOG_INFO,
"Init: Loading certificate & private key of SSL-aware server %s",
cpVHostID);
***************
*** 202,226 ****
if (sc->szPrivateKeyFile[j] != NULL)
ap_cpystrn(szPath, sc->szPrivateKeyFile[j++], sizeof(szPath));
! /*
! * Try to read the private key file with the help of
! * the callback function which serves the pass
! * phrases to OpenSSL
! */
! myCtxVarSet(mc, 1, pServ);
! myCtxVarSet(mc, 2, p);
! myCtxVarSet(mc, 3, aPassPhrase);
! myCtxVarSet(mc, 4, &nPassPhraseCur);
! myCtxVarSet(mc, 5, &cpPassPhraseCur);
! myCtxVarSet(mc, 6, cpVHostID);
! myCtxVarSet(mc, 7, &nPassPhraseDialog);
! myCtxVarSet(mc, 8, &nPassPhraseDialogCur);
! myCtxVarSet(mc, 9, &bPassPhraseDialogOnce);
!
! nPassPhraseCur = 0;
! nPassPhraseRetry = 0;
! nPassPhraseDialogCur = 0;
! bPassPhraseDialogOnce = TRUE;
pPrivateKey = NULL;
--- 413,419 ----
if (sc->szPrivateKeyFile[j] != NULL)
ap_cpystrn(szPath, sc->szPrivateKeyFile[j++], sizeof(szPath));
! init_ssl_pphrase_cb_begin(&cbi, pServ, cpVHostID);
pPrivateKey = NULL;
***************
*** 235,241 ****
"Init: Can't open server private key file %s", szPath);
ssl_die();
}
- cpPassPhraseCur = NULL;
bReadable = ((pPrivateKey = SSL_read_PrivateKey(fp, NULL,
ssl_pphrase_Handle_CB)) != NULL ? TRUE : FALSE);
ap_pfclose(p, fp);
--- 428,433 ----
***************
*** 247,299 ****
if (bReadable)
break;
! /*
! * when we have more remembered pass phrases
! * try to reuse these first.
! */
! if (nPassPhraseCur < nPassPhrase) {
! nPassPhraseCur++;
! continue;
! }
!
! /*
! * else it's not readable and we have no more
! * remembered pass phrases. Then this has to mean
! * that the callback function popped up the dialog
! * but a wrong pass phrase was entered. We give the
! * user (but not the dialog program) a few more
! * chances...
! */
! if ( sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN
! && cpPassPhraseCur != NULL
! && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
! fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase incorrect "
! "(%d more retr%s permitted).\n",
! (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry),
! (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" :
"ies");
! nPassPhraseRetry++;
! if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF)
! sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)*5);
! continue;
! }
!
! /*
! * Ok, anything else now means a fatal error.
! */
! if (cpPassPhraseCur == NULL)
! ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key
not found.");
! if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
! fprintf(stdout, "Apache:mod_ssl:Error: Private key not
found.\n");
! fprintf(stdout, "**Stopped\n");
! }
! else {
! ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Pass phrase
incorrect.");
! if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
! fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase
incorrect.\n");
! fprintf(stdout, "**Stopped\n");
! }
! }
! ssl_die();
}
if (pPrivateKey == NULL) {
--- 439,445 ----
if (bReadable)
break;
! init_ssl_pphrase_cb_check(&cbi,
sc->nPassPhraseDialogType);
}
if (pPrivateKey == NULL) {
***************
*** 315,346 ****
}
algoKey |= at;
! /*
! * Log the type of reading
! */
! if (nPassPhraseDialogCur == 0)
! ssl_log(pServ, SSL_LOG_TRACE,
! "Init: (%s) unencrypted %s private key - pass phrase not
required",
! cpVHostID, an);
! else {
! if (cpPassPhraseCur != NULL)
! ssl_log(pServ, SSL_LOG_TRACE,
! "Init: (%s) encrypted %s private key - pass phrase
requested",
! cpVHostID, an);
! else
! ssl_log(pServ, SSL_LOG_TRACE,
! "Init: (%s) encrypted %s private key - pass phrase
reused",
! cpVHostID, an);
! }
!
! /*
! * Ok, when we have one more pass phrase store it
! */
! if (cpPassPhraseCur != NULL) {
! cpp = (char **)ssl_ds_array_push(aPassPhrase);
! *cpp = cpPassPhraseCur;
! nPassPhrase++;
! }
/*
* Insert private key into the global module configuration
--- 461,467 ----
}
algoKey |= at;
! init_ssl_pphrase_cb_end(&cbi, an);
/*
* Insert private key into the global module configuration
***************
*** 364,370 ****
/*
* Let the user know when we're successful.
*/
! if (nPassPhraseDialog > 0) {
sc = mySrvConfig(s);
if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
fprintf(stdout, "\n");
--- 485,491 ----
/*
* Let the user know when we're successful.
*/
! if (cbi.nPassPhraseDialog > 0) {
sc = mySrvConfig(s);
if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
fprintf(stdout, "\n");
***************
*** 376,389 ****
* Wipe out the used memory from the
* pass phrase array and then deallocate it
*/
! if (!ssl_ds_array_isempty(aPassPhrase)) {
! ssl_ds_array_wipeout(aPassPhrase);
! ssl_ds_array_kill(aPassPhrase);
ssl_log(s, SSL_LOG_INFO, "Init: Wiped out the queried pass phrases from
memory");
}
return;
}
int ssl_pphrase_Handle_CB(char *buf, int bufsize, int ask_twice)
{
--- 497,511 ----
* Wipe out the used memory from the
* pass phrase array and then deallocate it
*/
! if (!ssl_ds_array_isempty(cbi.aPassPhrase)) {
! ssl_ds_array_wipeout(cbi.aPassPhrase);
! ssl_ds_array_kill(cbi.aPassPhrase);
ssl_log(s, SSL_LOG_INFO, "Init: Wiped out the queried pass phrases from
memory");
}
return;
}
+
int ssl_pphrase_Handle_CB(char *buf, int bufsize, int ask_twice)
{