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;
+}
+