You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2015/06/30 17:26:19 UTC
svn commit: r1688474 [14/21] - in /httpd/httpd/trunk/modules/http2: ./ m4/
mod-h2.xcodeproj/ mod-h2.xcodeproj/project.xcworkspace/
mod-h2.xcodeproj/project.xcworkspace/xcshareddata/
mod-h2.xcodeproj/xcuserdata/ mod-h2.xcodeproj/xcuserdata/sei.xcuserdat...
Added: httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_log.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_log.c?rev=1688474&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_log.c (added)
+++ httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_log.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,238 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* _ _
+ * _ __ ___ ___ __| | ___ ___| | mod_ssl
+ * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| | \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ * |_____|
+ * ssl_engine_log.c
+ * Logging Facility
+ */
+ /* ``The difference between a computer
+ industry job and open-source software
+ hacking is about 30 hours a week.''
+ -- Ralf S. Engelschall */
+#include "ssl_private.h"
+
+/* _________________________________________________________________
+**
+** Logfile Support
+** _________________________________________________________________
+*/
+
+static const struct {
+ const char *cpPattern;
+ const char *cpAnnotation;
+} ssl_log_annotate[] = {
+ { "*envelope*bad*decrypt*", "wrong pass phrase!?" },
+ { "*CLIENT_HELLO*unknown*protocol*", "speaking not SSL to HTTPS port!?" },
+ { "*CLIENT_HELLO*http*request*", "speaking HTTP to HTTPS port!?" },
+ { "*SSL3_READ_BYTES:sslv3*alert*bad*certificate*", "Subject CN in certificate not server name or identical to CA!?" },
+ { "*self signed certificate in certificate chain*", "Client certificate signed by CA not known to server?" },
+ { "*peer did not return a certificate*", "No CAs known to server for verification?" },
+ { "*no shared cipher*", "Too restrictive SSLCipherSuite or using DSA server certificate?" },
+ { "*no start line*", "Bad file contents or format - or even just a forgotten SSLCertificateKeyFile?" },
+ { "*bad password read*", "You entered an incorrect pass phrase!?" },
+ { "*bad mac decode*", "Browser still remembered details of a re-created server certificate?" },
+ { NULL, NULL }
+};
+
+static const char *ssl_log_annotation(const char *error)
+{
+ int i = 0;
+
+ while (ssl_log_annotate[i].cpPattern != NULL
+ && ap_strcmp_match(error, ssl_log_annotate[i].cpPattern) != 0)
+ i++;
+
+ return ssl_log_annotate[i].cpAnnotation;
+}
+
+apr_status_t ssl_die(server_rec *s)
+{
+ if (s != NULL && s->is_virtual && s->error_fname != NULL)
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02311)
+ "Fatal error initialising mod_ssl, exiting. "
+ "See %s for more information",
+ ap_server_root_relative(s->process->pool,
+ s->error_fname));
+ else
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02312)
+ "Fatal error initialising mod_ssl, exiting.");
+
+ return APR_EGENERAL;
+}
+
+/*
+ * Prints the SSL library error information.
+ */
+void ssl_log_ssl_error(const char *file, int line, int level, server_rec *s)
+{
+ unsigned long e;
+ const char *data;
+ int flags;
+
+ while ((e = ERR_peek_error_line_data(NULL, NULL, &data, &flags))) {
+ const char *annotation;
+ char err[256];
+
+ if (!(flags & ERR_TXT_STRING)) {
+ data = NULL;
+ }
+
+ ERR_error_string_n(e, err, sizeof err);
+ annotation = ssl_log_annotation(err);
+
+ ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, s,
+ "SSL Library Error: %s%s%s%s%s%s",
+ /* %s */
+ err,
+ /* %s%s%s */
+ data ? " (" : "", data ? data : "", data ? ")" : "",
+ /* %s%s */
+ annotation ? " -- " : "",
+ annotation ? annotation : "");
+
+ /* Pop the error off the stack: */
+ ERR_get_error();
+ }
+}
+
+static void ssl_log_cert_error(const char *file, int line, int level,
+ apr_status_t rv, const server_rec *s,
+ const conn_rec *c, const request_rec *r,
+ apr_pool_t *p, X509 *cert, const char *format,
+ va_list ap)
+{
+ char buf[HUGE_STRING_LEN];
+ int msglen, n;
+ char *name;
+
+ apr_vsnprintf(buf, sizeof buf, format, ap);
+
+ msglen = strlen(buf);
+
+ if (cert) {
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ if (bio) {
+ /*
+ * Limit the maximum length of the subject and issuer DN strings
+ * in the log message. 300 characters should always be sufficient
+ * for holding both the timestamp, module name, pid etc. stuff
+ * at the beginning of the line and the trailing information about
+ * serial, notbefore and notafter.
+ */
+ int maxdnlen = (HUGE_STRING_LEN - msglen - 300) / 2;
+
+ BIO_puts(bio, " [subject: ");
+ name = SSL_X509_NAME_to_string(p, X509_get_subject_name(cert),
+ maxdnlen);
+ if (!strIsEmpty(name)) {
+ BIO_puts(bio, name);
+ } else {
+ BIO_puts(bio, "-empty-");
+ }
+
+ BIO_puts(bio, " / issuer: ");
+ name = SSL_X509_NAME_to_string(p, X509_get_issuer_name(cert),
+ maxdnlen);
+ if (!strIsEmpty(name)) {
+ BIO_puts(bio, name);
+ } else {
+ BIO_puts(bio, "-empty-");
+ }
+
+ BIO_puts(bio, " / serial: ");
+ if (i2a_ASN1_INTEGER(bio, X509_get_serialNumber(cert)) == -1)
+ BIO_puts(bio, "(ERROR)");
+
+ BIO_puts(bio, " / notbefore: ");
+ ASN1_TIME_print(bio, X509_get_notBefore(cert));
+
+ BIO_puts(bio, " / notafter: ");
+ ASN1_TIME_print(bio, X509_get_notAfter(cert));
+
+ BIO_puts(bio, "]");
+
+ n = BIO_read(bio, buf + msglen, sizeof buf - msglen - 1);
+ if (n > 0)
+ buf[msglen + n] = '\0';
+
+ BIO_free(bio);
+ }
+ }
+ else {
+ apr_snprintf(buf + msglen, sizeof buf - msglen,
+ " [certificate: -not available-]");
+ }
+
+ if (r) {
+ ap_log_rerror(file, line, APLOG_MODULE_INDEX, level, rv, r, "%s", buf);
+ }
+ else if (c) {
+ ap_log_cerror(file, line, APLOG_MODULE_INDEX, level, rv, c, "%s", buf);
+ }
+ else if (s) {
+ ap_log_error(file, line, APLOG_MODULE_INDEX, level, rv, s, "%s", buf);
+ }
+
+}
+
+/*
+ * Wrappers for ap_log_error/ap_log_cerror/ap_log_rerror which log additional
+ * details of the X509 cert. For ssl_log_xerror, a pool needs to be passed in
+ * as well (for temporary allocation of the cert's subject/issuer name strings,
+ * in the other cases we use the connection and request pool, respectively).
+ */
+void ssl_log_xerror(const char *file, int line, int level, apr_status_t rv,
+ apr_pool_t *ptemp, server_rec *s, X509 *cert,
+ const char *fmt, ...)
+{
+ if (APLOG_IS_LEVEL(s,level)) {
+ va_list ap;
+ va_start(ap, fmt);
+ ssl_log_cert_error(file, line, level, rv, s, NULL, NULL, ptemp,
+ cert, fmt, ap);
+ va_end(ap);
+ }
+}
+
+void ssl_log_cxerror(const char *file, int line, int level, apr_status_t rv,
+ conn_rec *c, X509 *cert, const char *fmt, ...)
+{
+ if (APLOG_IS_LEVEL(mySrvFromConn(c),level)) {
+ va_list ap;
+ va_start(ap, fmt);
+ ssl_log_cert_error(file, line, level, rv, NULL, c, NULL, c->pool,
+ cert, fmt, ap);
+ va_end(ap);
+ }
+}
+
+void ssl_log_rxerror(const char *file, int line, int level, apr_status_t rv,
+ request_rec *r, X509 *cert, const char *fmt, ...)
+{
+ if (APLOG_R_IS_LEVEL(r,level)) {
+ va_list ap;
+ va_start(ap, fmt);
+ ssl_log_cert_error(file, line, level, rv, NULL, NULL, r, r->pool,
+ cert, fmt, ap);
+ va_end(ap);
+ }
+}
Added: httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_mutex.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_mutex.c?rev=1688474&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_mutex.c (added)
+++ httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_mutex.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,111 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* _ _
+ * _ __ ___ ___ __| | ___ ___| | mod_ssl
+ * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| | \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ * |_____|
+ * ssl_engine_mutex.c
+ * Semaphore for Mutual Exclusion
+ */
+ /* ``Real programmers confuse
+ Christmas and Halloween
+ because DEC 25 = OCT 31.''
+ -- Unknown */
+
+#include "ssl_private.h"
+
+int ssl_mutex_init(server_rec *s, apr_pool_t *p)
+{
+ SSLModConfigRec *mc = myModConfig(s);
+ apr_status_t rv;
+
+ /* A mutex is only needed if a session cache is configured, and
+ * the provider used is not internally multi-process/thread
+ * safe. */
+ if (!mc->sesscache
+ || (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) == 0) {
+ return TRUE;
+ }
+
+ if (mc->pMutex) {
+ return TRUE;
+ }
+
+ if ((rv = ap_global_mutex_create(&mc->pMutex, NULL, SSL_CACHE_MUTEX_TYPE,
+ NULL, s, s->process->pool, 0))
+ != APR_SUCCESS) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int ssl_mutex_reinit(server_rec *s, apr_pool_t *p)
+{
+ SSLModConfigRec *mc = myModConfig(s);
+ apr_status_t rv;
+ const char *lockfile;
+
+ if (mc->pMutex == NULL || !mc->sesscache
+ || (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) == 0) {
+ return TRUE;
+ }
+
+ lockfile = apr_global_mutex_lockfile(mc->pMutex);
+ if ((rv = apr_global_mutex_child_init(&mc->pMutex,
+ lockfile,
+ p)) != APR_SUCCESS) {
+ if (lockfile)
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02024)
+ "Cannot reinit %s mutex with file `%s'",
+ SSL_CACHE_MUTEX_TYPE, lockfile);
+ else
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(02025)
+ "Cannot reinit %s mutex", SSL_CACHE_MUTEX_TYPE);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int ssl_mutex_on(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig(s);
+ apr_status_t rv;
+
+ if ((rv = apr_global_mutex_lock(mc->pMutex)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(02026)
+ "Failed to acquire SSL session cache lock");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int ssl_mutex_off(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig(s);
+ apr_status_t rv;
+
+ if ((rv = apr_global_mutex_unlock(mc->pMutex)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(02027)
+ "Failed to release SSL session cache lock");
+ return FALSE;
+ }
+ return TRUE;
+}
+
Added: httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_ocsp.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_ocsp.c?rev=1688474&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_ocsp.c (added)
+++ httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_ocsp.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,300 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ssl_private.h"
+
+#ifndef OPENSSL_NO_OCSP
+#include "apr_base64.h"
+
+/* Return the responder URI specified in the given certificate, or
+ * NULL if none specified. */
+static const char *extract_responder_uri(X509 *cert, apr_pool_t *pool)
+{
+ STACK_OF(ACCESS_DESCRIPTION) *values;
+ char *result = NULL;
+ int j;
+
+ values = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL);
+ if (!values) {
+ return NULL;
+ }
+
+ for (j = 0; j < sk_ACCESS_DESCRIPTION_num(values) && !result; j++) {
+ ACCESS_DESCRIPTION *value = sk_ACCESS_DESCRIPTION_value(values, j);
+
+ /* Name found in extension, and is a URI: */
+ if (OBJ_obj2nid(value->method) == NID_ad_OCSP
+ && value->location->type == GEN_URI) {
+ result = apr_pstrdup(pool,
+ (char *)value->location->d.uniformResourceIdentifier->data);
+ }
+ }
+
+ AUTHORITY_INFO_ACCESS_free(values);
+
+ return result;
+}
+
+/* Return the responder URI object which should be used in the given
+ * configuration for the given certificate, or NULL if none can be
+ * determined. */
+static apr_uri_t *determine_responder_uri(SSLSrvConfigRec *sc, X509 *cert,
+ conn_rec *c, apr_pool_t *p)
+{
+ apr_uri_t *u = apr_palloc(p, sizeof *u);
+ const char *s;
+ apr_status_t rv;
+
+ /* Use default responder URL if forced by configuration, else use
+ * certificate-specified responder, falling back to default if
+ * necessary and possible. */
+ if (sc->server->ocsp_force_default) {
+ s = sc->server->ocsp_responder;
+ }
+ else {
+ s = extract_responder_uri(cert, p);
+
+ if (s == NULL && sc->server->ocsp_responder) {
+ s = sc->server->ocsp_responder;
+ }
+ }
+
+ if (s == NULL) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01918)
+ "no OCSP responder specified in certificate and "
+ "no default configured");
+ return NULL;
+ }
+
+ rv = apr_uri_parse(p, s, u);
+ if (rv || !u->hostname) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(01919)
+ "failed to parse OCSP responder URI '%s'", s);
+ return NULL;
+ }
+
+ if (strcasecmp(u->scheme, "http") != 0) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(01920)
+ "cannot handle OCSP responder URI '%s'", s);
+ return NULL;
+ }
+
+ if (!u->port) {
+ u->port = apr_uri_port_of_scheme(u->scheme);
+ }
+
+ return u;
+}
+
+/* Create an OCSP request for the given certificate; returning the
+ * certificate ID in *certid and *issuer on success. Returns the
+ * request object on success, or NULL on error. */
+static OCSP_REQUEST *create_request(X509_STORE_CTX *ctx, X509 *cert,
+ OCSP_CERTID **certid,
+ server_rec *s, apr_pool_t *p,
+ SSLSrvConfigRec *sc)
+{
+ OCSP_REQUEST *req = OCSP_REQUEST_new();
+
+ *certid = OCSP_cert_to_id(NULL, cert, ctx->current_issuer);
+ if (!*certid || !OCSP_request_add0_id(req, *certid)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01921)
+ "could not retrieve certificate id");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ return NULL;
+ }
+
+ if (sc->server->ocsp_use_request_nonce != FALSE) {
+ OCSP_request_add1_nonce(req, 0, -1);
+ }
+
+ return req;
+}
+
+/* Verify the OCSP status of given certificate. Returns
+ * V_OCSP_CERTSTATUS_* result code. */
+static int verify_ocsp_status(X509 *cert, X509_STORE_CTX *ctx, conn_rec *c,
+ SSLSrvConfigRec *sc, server_rec *s,
+ apr_pool_t *pool)
+{
+ int rc = V_OCSP_CERTSTATUS_GOOD;
+ OCSP_RESPONSE *response = NULL;
+ OCSP_BASICRESP *basicResponse = NULL;
+ OCSP_REQUEST *request = NULL;
+ OCSP_CERTID *certID = NULL;
+ apr_uri_t *ruri;
+
+ ruri = determine_responder_uri(sc, cert, c, pool);
+ if (!ruri) {
+ return V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+
+ request = create_request(ctx, cert, &certID, s, pool, sc);
+ if (request) {
+ apr_interval_time_t to = sc->server->ocsp_responder_timeout == UNSET ?
+ apr_time_from_sec(DEFAULT_OCSP_TIMEOUT) :
+ sc->server->ocsp_responder_timeout;
+ response = modssl_dispatch_ocsp_request(ruri, to, request, c, pool);
+ }
+
+ if (!request || !response) {
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+
+ if (rc == V_OCSP_CERTSTATUS_GOOD) {
+ int r = OCSP_response_status(response);
+
+ if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01922)
+ "OCSP response not successful: %d", rc);
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+ }
+
+ if (rc == V_OCSP_CERTSTATUS_GOOD) {
+ basicResponse = OCSP_response_get1_basic(response);
+ if (!basicResponse) {
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01923)
+ "could not retrieve OCSP basic response");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+ }
+
+ if (rc == V_OCSP_CERTSTATUS_GOOD &&
+ sc->server->ocsp_use_request_nonce != FALSE &&
+ OCSP_check_nonce(request, basicResponse) != 1) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01924)
+ "Bad OCSP responder answer (bad nonce)");
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+
+ if (rc == V_OCSP_CERTSTATUS_GOOD) {
+ /* TODO: allow flags configuration. */
+ if (OCSP_basic_verify(basicResponse, NULL, ctx->ctx, 0) != 1) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01925)
+ "failed to verify the OCSP response");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+ }
+
+ if (rc == V_OCSP_CERTSTATUS_GOOD) {
+ int reason = -1, status;
+ ASN1_GENERALIZEDTIME *thisup = NULL, *nextup = NULL;
+
+ rc = OCSP_resp_find_status(basicResponse, certID, &status,
+ &reason, NULL, &thisup, &nextup);
+ if (rc != 1) {
+ ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02272)
+ "failed to retrieve OCSP response status");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+ else {
+ rc = status;
+ }
+
+ /* Check whether the response is inside the defined validity
+ * period; otherwise fail. */
+ if (rc != V_OCSP_CERTSTATUS_UNKNOWN) {
+ long resptime_skew = sc->server->ocsp_resptime_skew == UNSET ?
+ DEFAULT_OCSP_MAX_SKEW : sc->server->ocsp_resptime_skew;
+ /* oscp_resp_maxage can be passed verbatim - UNSET (-1) means
+ * that responses can be of any age as long as nextup is in the
+ * future. */
+ int vrc = OCSP_check_validity(thisup, nextup, resptime_skew,
+ sc->server->ocsp_resp_maxage);
+ if (vrc != 1) {
+ ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02273)
+ "OCSP response outside validity period");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ rc = V_OCSP_CERTSTATUS_UNKNOWN;
+ }
+ }
+
+ {
+ int level =
+ (status == V_OCSP_CERTSTATUS_GOOD) ? APLOG_INFO : APLOG_ERR;
+ const char *result =
+ status == V_OCSP_CERTSTATUS_GOOD ? "good" :
+ (status == V_OCSP_CERTSTATUS_REVOKED ? "revoked" : "unknown");
+
+ ssl_log_cxerror(SSLLOG_MARK, level, 0, c, cert,
+ "OCSP validation completed, "
+ "certificate status: %s (%d, %d)",
+ result, status, reason);
+ }
+ }
+
+ if (request) OCSP_REQUEST_free(request);
+ if (response) OCSP_RESPONSE_free(response);
+ if (basicResponse) OCSP_BASICRESP_free(basicResponse);
+ /* certID is freed when the request is freed */
+
+ return rc;
+}
+
+int modssl_verify_ocsp(X509_STORE_CTX *ctx, SSLSrvConfigRec *sc,
+ server_rec *s, conn_rec *c, apr_pool_t *pool)
+{
+ X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
+ apr_pool_t *vpool;
+ int rv;
+
+ if (!cert) {
+ /* starting with OpenSSL 1.0, X509_STORE_CTX_get_current_cert()
+ * may yield NULL. Return early, but leave the ctx error as is. */
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+ "No cert available to check with OCSP");
+ return 1;
+ }
+ else if (cert->valid && X509_check_issued(cert,cert) == X509_V_OK) {
+ /* don't do OCSP checking for valid self-issued certs */
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+ "Skipping OCSP check for valid self-issued cert");
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ return 1;
+ }
+
+ /* Create a temporary pool to constrain memory use (the passed-in
+ * pool may be e.g. a connection pool). */
+ apr_pool_create(&vpool, pool);
+
+ rv = verify_ocsp_status(cert, ctx, c, sc, s, vpool);
+
+ apr_pool_destroy(vpool);
+
+ /* Propagate the verification status back to the passed-in
+ * context. */
+ switch (rv) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ break;
+
+ case V_OCSP_CERTSTATUS_REVOKED:
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+ break;
+
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ /* correct error code for application errors? */
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
+ break;
+ }
+
+ return rv == V_OCSP_CERTSTATUS_GOOD;
+}
+#endif /* HAVE_OCSP */
Added: httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_pphrase.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_pphrase.c?rev=1688474&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_pphrase.c (added)
+++ httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_pphrase.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,623 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* _ _
+ * _ __ ___ ___ __| | ___ ___| | mod_ssl
+ * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| | \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ * |_____|
+ * ssl_engine_pphrase.c
+ * Pass Phrase Dialog
+ */
+ /* ``Treat your password like your
+ toothbrush. Don't let anybody
+ else use it, and get a new one
+ every six months.''
+ -- Clifford Stoll */
+#include "ssl_private.h"
+
+typedef struct {
+ server_rec *s;
+ apr_pool_t *p;
+ apr_array_header_t *aPassPhrase;
+ int nPassPhraseCur;
+ char *cpPassPhraseCur;
+ int nPassPhraseDialog;
+ int nPassPhraseDialogCur;
+ BOOL bPassPhraseDialogOnce;
+ const char *key_id;
+ const char *pkey_file;
+} pphrase_cb_arg_t;
+
+#ifdef HAVE_ECC
+static const char *key_types[] = {"RSA", "DSA", "ECC"};
+#else
+static const char *key_types[] = {"RSA", "DSA"};
+#endif
+
+/*
+ * Return true if the named file exists and is readable
+ */
+
+static apr_status_t exists_and_readable(const char *fname, apr_pool_t *pool,
+ apr_time_t *mtime)
+{
+ apr_status_t stat;
+ apr_finfo_t sbuf;
+ apr_file_t *fd;
+
+ if ((stat = apr_stat(&sbuf, fname, APR_FINFO_MIN, pool)) != APR_SUCCESS)
+ return stat;
+
+ if (sbuf.filetype != APR_REG)
+ return APR_EGENERAL;
+
+ if ((stat = apr_file_open(&fd, fname, APR_READ, 0, pool)) != APR_SUCCESS)
+ return stat;
+
+ if (mtime) {
+ *mtime = sbuf.mtime;
+ }
+
+ apr_file_close(fd);
+ return APR_SUCCESS;
+}
+
+/*
+ * reuse vhost keys for asn1 tables where keys are allocated out
+ * of s->process->pool to prevent "leaking" each time we format
+ * a vhost key. since the key is stored in a table with lifetime
+ * of s->process->pool, the key needs to have the same lifetime.
+ *
+ * XXX: probably seems silly to use a hash table with keys and values
+ * being the same, but it is easier than doing a linear search
+ * and will make it easier to remove keys if needed in the future.
+ * also have the problem with apr_array_header_t that if we
+ * underestimate the number of vhost keys when we apr_array_make(),
+ * the array will get resized when we push past the initial number
+ * of elts. this resizing in the s->process->pool means "leaking"
+ * since apr_array_push() will apr_alloc arr->nalloc * 2 elts,
+ * leaving the original arr->elts to waste.
+ */
+static const char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p,
+ const char *id, int i)
+{
+ /* 'p' pool used here is cleared on restarts (or sooner) */
+ char *key = apr_psprintf(p, "%s:%d", id, i);
+ void *keyptr = apr_hash_get(mc->tVHostKeys, key,
+ APR_HASH_KEY_STRING);
+
+ if (!keyptr) {
+ /* make a copy out of s->process->pool */
+ keyptr = apr_pstrdup(mc->pPool, key);
+ apr_hash_set(mc->tVHostKeys, keyptr,
+ APR_HASH_KEY_STRING, keyptr);
+ }
+
+ return (char *)keyptr;
+}
+
+/* _________________________________________________________________
+**
+** Pass Phrase and Private Key Handling
+** _________________________________________________________________
+*/
+
+#define BUILTIN_DIALOG_BACKOFF 2
+#define BUILTIN_DIALOG_RETRIES 5
+
+static apr_file_t *writetty = NULL;
+static apr_file_t *readtty = NULL;
+
+int ssl_pphrase_Handle_CB(char *, int, int, void *);
+
+static char *pphrase_array_get(apr_array_header_t *arr, int idx)
+{
+ if ((idx < 0) || (idx >= arr->nelts)) {
+ return NULL;
+ }
+
+ return ((char **)arr->elts)[idx];
+}
+
+apr_status_t ssl_load_encrypted_pkey(server_rec *s, apr_pool_t *p, int idx,
+ const char *pkey_file,
+ apr_array_header_t **pphrases)
+{
+ SSLModConfigRec *mc = myModConfig(s);
+ SSLSrvConfigRec *sc = mySrvConfig(s);
+ const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx);
+ EVP_PKEY *pPrivateKey = NULL;
+ ssl_asn1_t *asn1;
+ unsigned char *ucp;
+ long int length;
+ BOOL bReadable;
+ int nPassPhrase = (*pphrases)->nelts;
+ int nPassPhraseRetry = 0;
+ apr_time_t pkey_mtime = 0;
+ apr_status_t rv;
+ pphrase_cb_arg_t ppcb_arg;
+
+ if (!pkey_file) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02573)
+ "Init: No private key specified for %s", key_id);
+ return ssl_die(s);
+ }
+ else if ((rv = exists_and_readable(pkey_file, p, &pkey_mtime))
+ != APR_SUCCESS ) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02574)
+ "Init: Can't open server private key file %s", pkey_file);
+ return ssl_die(s);
+ }
+
+ ppcb_arg.s = s;
+ ppcb_arg.p = p;
+ ppcb_arg.aPassPhrase = *pphrases;
+ ppcb_arg.nPassPhraseCur = 0;
+ ppcb_arg.cpPassPhraseCur = NULL;
+ ppcb_arg.nPassPhraseDialog = 0;
+ ppcb_arg.nPassPhraseDialogCur = 0;
+ ppcb_arg.bPassPhraseDialogOnce = TRUE;
+ ppcb_arg.key_id = key_id;
+ ppcb_arg.pkey_file = pkey_file;
+
+ /*
+ * if the private key is encrypted and SSLPassPhraseDialog
+ * is configured to "builtin" it isn't possible to prompt for
+ * a password after httpd has detached from the tty.
+ * in this case if we already have a private key and the
+ * file name/mtime hasn't changed, then reuse the existing key.
+ * we also reuse existing private keys that were encrypted for
+ * exec: and pipe: dialogs to minimize chances to snoop the
+ * password. that and pipe: dialogs might prompt the user
+ * for password, which on win32 for example could happen 4
+ * times at startup. twice for each child and twice within
+ * each since apache "restarts itself" on startup.
+ * of course this will not work for the builtin dialog if
+ * the server was started without LoadModule ssl_module
+ * configured, then restarted with it configured.
+ * but we fall through with a chance of success if the key
+ * is not encrypted or can be handled via exec or pipe dialog.
+ * and in the case of fallthrough, pkey_mtime and isatty()
+ * are used to give a better idea as to what failed.
+ */
+ if (pkey_mtime) {
+ ssl_asn1_t *asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
+ if (asn1 && (asn1->source_mtime == pkey_mtime)) {
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02575)
+ "Reusing existing private key from %s on restart",
+ ppcb_arg.pkey_file);
+ return APR_SUCCESS;
+ }
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02576)
+ "Attempting to load encrypted (?) private key %s", key_id);
+
+ for (;;) {
+ /*
+ * Try to read the private key file with the help of
+ * the callback function which serves the pass
+ * phrases to OpenSSL
+ */
+
+ ppcb_arg.cpPassPhraseCur = NULL;
+
+ /* Ensure that the error stack is empty; some SSL
+ * functions will fail spuriously if the error stack
+ * is not empty. */
+ ERR_clear_error();
+
+ bReadable = ((pPrivateKey = SSL_read_PrivateKey(ppcb_arg.pkey_file,
+ NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ?
+ TRUE : FALSE);
+
+ /*
+ * when the private key file now was readable,
+ * it's fine and we go out of the loop
+ */
+ if (bReadable)
+ break;
+
+ /*
+ * when we have more remembered pass phrases
+ * try to reuse these first.
+ */
+ if (ppcb_arg.nPassPhraseCur < nPassPhrase) {
+ ppcb_arg.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...
+ */
+#ifndef WIN32
+ if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE)
+#else
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE
+#endif
+ && ppcb_arg.cpPassPhraseCur != NULL
+ && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
+ apr_file_printf(writetty, "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)
+ apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)
+ * 5 * APR_USEC_PER_SEC);
+ continue;
+ }
+#ifdef WIN32
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02577)
+ "Init: SSLPassPhraseDialog builtin is not "
+ "supported on Win32 (key file "
+ "%s)", ppcb_arg.pkey_file);
+ return ssl_die(s);
+ }
+#endif /* WIN32 */
+
+ /*
+ * Ok, anything else now means a fatal error.
+ */
+ if (ppcb_arg.cpPassPhraseCur == NULL) {
+ if (ppcb_arg.nPassPhraseDialogCur && pkey_mtime &&
+ !isatty(fileno(stdout))) /* XXX: apr_isatty() */
+ {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+ s, APLOGNO(02578)
+ "Init: Unable to read pass phrase "
+ "[Hint: key introduced or changed "
+ "before restart?]");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+ s, APLOGNO(02579) "Init: Private key not found");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+ }
+ if (writetty) {
+ apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n");
+ apr_file_printf(writetty, "**Stopped\n");
+ }
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02580)
+ "Init: Pass phrase incorrect for key %s",
+ key_id);
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+
+ if (writetty) {
+ apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
+ apr_file_printf(writetty, "**Stopped\n");
+ }
+ }
+ return ssl_die(s);
+ }
+
+ if (pPrivateKey == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02581)
+ "Init: Unable to read server private key from file %s",
+ ppcb_arg.pkey_file);
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+ return ssl_die(s);
+ }
+
+ /*
+ * Log the type of reading
+ */
+ if (ppcb_arg.nPassPhraseDialogCur == 0) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02582)
+ "unencrypted %s private key - pass phrase not "
+ "required", key_id);
+ }
+ else {
+ if (ppcb_arg.cpPassPhraseCur != NULL) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ s, APLOGNO(02583)
+ "encrypted %s private key - pass phrase "
+ "requested", key_id);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ s, APLOGNO(02584)
+ "encrypted %s private key - pass phrase"
+ " reused", key_id);
+ }
+ }
+
+ /*
+ * Ok, when we have one more pass phrase store it
+ */
+ if (ppcb_arg.cpPassPhraseCur != NULL) {
+ *(const char **)apr_array_push(ppcb_arg.aPassPhrase) =
+ ppcb_arg.cpPassPhraseCur;
+ nPassPhrase++;
+ }
+
+ /*
+ * Insert private key into the global module configuration
+ * (we convert it to a stand-alone DER byte sequence
+ * because the SSL library uses static variables inside a
+ * RSA structure which do not survive DSO reloads!)
+ */
+ length = i2d_PrivateKey(pPrivateKey, NULL);
+ ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
+ (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
+
+ if (ppcb_arg.nPassPhraseDialogCur != 0) {
+ /* remember mtime of encrypted keys */
+ asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
+ asn1->source_mtime = pkey_mtime;
+ }
+
+ /*
+ * Free the private key structure
+ */
+ EVP_PKEY_free(pPrivateKey);
+
+ /*
+ * Let the user know when we're successful.
+ */
+ if ((ppcb_arg.nPassPhraseDialog > 0) &&
+ (ppcb_arg.cpPassPhraseCur != NULL)) {
+ if (writetty) {
+ apr_file_printf(writetty, "\n"
+ "OK: Pass Phrase Dialog successful.\n");
+ }
+ }
+
+ /* Close the pipes if they were opened
+ */
+ if (readtty) {
+ apr_file_close(readtty);
+ apr_file_close(writetty);
+ readtty = writetty = NULL;
+ }
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t ssl_pipe_child_create(apr_pool_t *p, const char *progname)
+{
+ /* Child process code for 'ErrorLog "|..."';
+ * may want a common framework for this, since I expect it will
+ * be common for other foo-loggers to want this sort of thing...
+ */
+ apr_status_t rc;
+ apr_procattr_t *procattr;
+ apr_proc_t *procnew;
+
+ if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) &&
+ ((rc = apr_procattr_io_set(procattr,
+ APR_FULL_BLOCK,
+ APR_FULL_BLOCK,
+ APR_NO_PIPE)) == APR_SUCCESS)) {
+ char **args;
+ const char *pname;
+
+ apr_tokenize_to_argv(progname, &args, p);
+ pname = apr_pstrdup(p, args[0]);
+ procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
+ rc = apr_proc_create(procnew, pname, (const char * const *)args,
+ NULL, procattr, p);
+ if (rc == APR_SUCCESS) {
+ /* XXX: not sure if we aught to...
+ * apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
+ */
+ writetty = procnew->in;
+ readtty = procnew->out;
+ }
+ }
+
+ return rc;
+}
+
+static int pipe_get_passwd_cb(char *buf, int length, char *prompt, int verify)
+{
+ apr_status_t rc;
+ char *p;
+
+ apr_file_puts(prompt, writetty);
+
+ buf[0]='\0';
+ rc = apr_file_gets(buf, length, readtty);
+ apr_file_puts(APR_EOL_STR, writetty);
+
+ if (rc != APR_SUCCESS || apr_file_eof(readtty)) {
+ memset(buf, 0, length);
+ return 1; /* failure */
+ }
+ if ((p = strchr(buf, '\n')) != NULL) {
+ *p = '\0';
+ }
+#ifdef WIN32
+ /* XXX: apr_sometest */
+ if ((p = strchr(buf, '\r')) != NULL) {
+ *p = '\0';
+ }
+#endif
+ return 0;
+}
+
+int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
+{
+ pphrase_cb_arg_t *ppcb_arg = (pphrase_cb_arg_t *)srv;
+ SSLSrvConfigRec *sc = mySrvConfig(ppcb_arg->s);
+ char *cpp;
+ int len = -1;
+
+ ppcb_arg->nPassPhraseDialog++;
+ ppcb_arg->nPassPhraseDialogCur++;
+
+ /*
+ * When remembered pass phrases are available use them...
+ */
+ if ((cpp = pphrase_array_get(ppcb_arg->aPassPhrase,
+ ppcb_arg->nPassPhraseCur)) != NULL) {
+ apr_cpystrn(buf, cpp, bufsize);
+ len = strlen(buf);
+ return len;
+ }
+
+ /*
+ * Builtin or Pipe dialog
+ */
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ char *prompt;
+ int i;
+
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ if (!readtty) {
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s,
+ APLOGNO(01965)
+ "Init: Creating pass phrase dialog pipe child "
+ "'%s'", sc->server->pphrase_dialog_path);
+ if (ssl_pipe_child_create(ppcb_arg->p,
+ sc->server->pphrase_dialog_path)
+ != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb_arg->s,
+ APLOGNO(01966)
+ "Init: Failed to create pass phrase pipe '%s'",
+ sc->server->pphrase_dialog_path);
+ PEMerr(PEM_F_PEM_DEF_CALLBACK,
+ PEM_R_PROBLEMS_GETTING_PASSWORD);
+ memset(buf, 0, (unsigned int)bufsize);
+ return (-1);
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01967)
+ "Init: Requesting pass phrase via piped dialog");
+ }
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
+#ifdef WIN32
+ PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
+ memset(buf, 0, (unsigned int)bufsize);
+ return (-1);
+#else
+ /*
+ * stderr has already been redirected to the error_log.
+ * rather than attempting to temporarily rehook it to the terminal,
+ * we print the prompt to stdout before EVP_read_pw_string turns
+ * off tty echo
+ */
+ apr_file_open_stdout(&writetty, ppcb_arg->p);
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01968)
+ "Init: Requesting pass phrase via builtin terminal "
+ "dialog");
+#endif
+ }
+
+ /*
+ * The first time display a header to inform the user about what
+ * program he actually speaks to, which module is responsible for
+ * this terminal dialog and why to the hell he has to enter
+ * something...
+ */
+ if (ppcb_arg->nPassPhraseDialog == 1) {
+ apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n",
+ AP_SERVER_BASEVERSION);
+ apr_file_printf(writetty, "Some of your private key files are encrypted for security reasons.\n");
+ apr_file_printf(writetty, "In order to read them you have to provide the pass phrases.\n");
+ }
+ if (ppcb_arg->bPassPhraseDialogOnce) {
+ ppcb_arg->bPassPhraseDialogOnce = FALSE;
+ apr_file_printf(writetty, "\n");
+ apr_file_printf(writetty, "Private key %s (%s)\n",
+ ppcb_arg->key_id, ppcb_arg->pkey_file);
+ }
+
+ /*
+ * Emulate the OpenSSL internal pass phrase dialog
+ * (see crypto/pem/pem_lib.c:def_callback() for details)
+ */
+ prompt = "Enter pass phrase:";
+
+ for (;;) {
+ apr_file_puts(prompt, writetty);
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
+ i = pipe_get_passwd_cb(buf, bufsize, "", FALSE);
+ }
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
+ i = EVP_read_pw_string(buf, bufsize, "", FALSE);
+ }
+ if (i != 0) {
+ PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD);
+ memset(buf, 0, (unsigned int)bufsize);
+ return (-1);
+ }
+ len = strlen(buf);
+ if (len < 1)
+ apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase empty (needs to be at least 1 character).\n");
+ else
+ break;
+ }
+ }
+
+ /*
+ * Filter program
+ */
+ else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) {
+ const char *cmd = sc->server->pphrase_dialog_path;
+ const char **argv = apr_palloc(ppcb_arg->p, sizeof(char *) * 4);
+ const char *idx = ap_strrchr_c(ppcb_arg->key_id, ':') + 1;
+ char *result;
+ int i;
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01969)
+ "Init: Requesting pass phrase from dialog filter "
+ "program (%s)", cmd);
+
+ argv[0] = cmd;
+ argv[1] = apr_pstrndup(ppcb_arg->p, ppcb_arg->key_id,
+ idx-1 - ppcb_arg->key_id);
+ if ((i = atoi(idx)) < CERTKEYS_IDX_MAX+1) {
+ /*
+ * For compatibility with existing 2.4.x configurations, use
+ * "RSA", "DSA" and "ECC" strings for the first two/three keys
+ */
+ argv[2] = key_types[i];
+ } else {
+ /* Four and above: use the integer index */
+ argv[2] = apr_pstrdup(ppcb_arg->p, idx);
+ }
+ argv[3] = NULL;
+
+ result = ssl_util_readfilter(ppcb_arg->s, ppcb_arg->p, cmd, argv);
+ apr_cpystrn(buf, result, bufsize);
+ len = strlen(buf);
+ }
+
+ /*
+ * Ok, we now have the pass phrase, so give it back
+ */
+ ppcb_arg->cpPassPhraseCur = apr_pstrdup(ppcb_arg->p, buf);
+
+ /*
+ * And return its length to OpenSSL...
+ */
+ return (len);
+}
Added: httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_rand.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_rand.c?rev=1688474&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_rand.c (added)
+++ httpd/httpd/trunk/modules/http2/sandbox/httpd/mod_ssl-alpn/ssl_engine_rand.c Tue Jun 30 15:26:16 2015
@@ -0,0 +1,175 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* _ _
+ * _ __ ___ ___ __| | ___ ___| | mod_ssl
+ * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| | \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ * |_____|
+ * ssl_engine_rand.c
+ * Random Number Generator Seeding
+ */
+ /* ``The generation of random
+ numbers is too important
+ to be left to chance.'' */
+
+#include "ssl_private.h"
+
+/* _________________________________________________________________
+**
+** Support for better seeding of SSL library's RNG
+** _________________________________________________________________
+*/
+
+static int ssl_rand_choosenum(int, int);
+static int ssl_rand_feedfp(apr_pool_t *, apr_file_t *, int);
+
+int ssl_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix)
+{
+ SSLModConfigRec *mc;
+ apr_array_header_t *apRandSeed;
+ ssl_randseed_t *pRandSeeds;
+ ssl_randseed_t *pRandSeed;
+ unsigned char stackdata[256];
+ int nDone;
+ apr_file_t *fp;
+ int i, n, l;
+
+ mc = myModConfig(s);
+ nDone = 0;
+ apRandSeed = mc->aRandSeed;
+ pRandSeeds = (ssl_randseed_t *)apRandSeed->elts;
+ for (i = 0; i < apRandSeed->nelts; i++) {
+ pRandSeed = &pRandSeeds[i];
+ if (pRandSeed->nCtx == nCtx) {
+ if (pRandSeed->nSrc == SSL_RSSRC_FILE) {
+ /*
+ * seed in contents of an external file
+ */
+ if (apr_file_open(&fp, pRandSeed->cpPath,
+ APR_READ, APR_OS_DEFAULT, p) != APR_SUCCESS)
+ continue;
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+ apr_file_close(fp);
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) {
+ const char *cmd = pRandSeed->cpPath;
+ const char **argv = apr_palloc(p, sizeof(char *) * 3);
+ /*
+ * seed in contents generated by an external program
+ */
+ argv[0] = cmd;
+ argv[1] = apr_itoa(p, pRandSeed->nBytes);
+ argv[2] = NULL;
+
+ if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
+ continue;
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+ ssl_util_ppclose(s, p, fp);
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_EGD) {
+ /*
+ * seed in contents provided by the external
+ * Entropy Gathering Daemon (EGD)
+ */
+ if ((n = RAND_egd(pRandSeed->cpPath)) == -1)
+ continue;
+ nDone += n;
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_BUILTIN) {
+ struct {
+ time_t t;
+ pid_t pid;
+ } my_seed;
+
+ /*
+ * seed in the current time (usually just 4 bytes)
+ */
+ my_seed.t = time(NULL);
+
+ /*
+ * seed in the current process id (usually just 4 bytes)
+ */
+ my_seed.pid = mc->pid;
+
+ l = sizeof(my_seed);
+ RAND_seed((unsigned char *)&my_seed, l);
+ nDone += l;
+
+ /*
+ * seed in some current state of the run-time stack (128 bytes)
+ */
+ n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
+ RAND_seed(stackdata+n, 128);
+ nDone += 128;
+
+ }
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s,
+ "%sSeeding PRNG with %d bytes of entropy", prefix, nDone);
+
+ if (RAND_status() == 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01990)
+ "%sPRNG still contains insufficient entropy!", prefix);
+
+ return nDone;
+}
+
+#define BUFSIZE 8192
+
+static int ssl_rand_feedfp(apr_pool_t *p, apr_file_t *fp, int nReq)
+{
+ apr_size_t nDone;
+ unsigned char caBuf[BUFSIZE];
+ apr_size_t nBuf;
+ apr_size_t nRead;
+ apr_size_t nTodo;
+
+ nDone = 0;
+ nRead = BUFSIZE;
+ nTodo = nReq;
+ while (1) {
+ if (nReq > 0)
+ nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE);
+ nBuf = nRead;
+ if (apr_file_read(fp, caBuf, &nBuf) != APR_SUCCESS)
+ break;
+ RAND_seed(caBuf, nBuf);
+ nDone += nBuf;
+ if (nReq > 0) {
+ nTodo -= nBuf;
+ if (nTodo <= 0)
+ break;
+ }
+ }
+ return nDone;
+}
+
+static int ssl_rand_choosenum(int l, int h)
+{
+ int i;
+ char buf[50];
+
+ apr_snprintf(buf, sizeof(buf), "%.0f",
+ (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
+ i = atoi(buf)+1;
+ if (i < l) i = l;
+ if (i > h) i = h;
+ return i;
+}
+