Blob Blame History Raw
--- neon-0.30.2/src/ne_openssl.c.openssl11
+++ neon-0.30.2/src/ne_openssl.c
@@ -574,6 +574,9 @@
         /* enable workarounds for buggy SSL server implementations */
         SSL_CTX_set_options(ctx->ctx, SSL_OP_ALL);
         SSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_PEER, verify_callback);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+        SSL_CTX_set_post_handshake_auth(ctx->ctx, 1);
+#endif
     } else if (mode == NE_SSL_CTX_SERVER) {
         ctx->ctx = SSL_CTX_new(SSLv23_server_method());
         SSL_CTX_set_session_cache_mode(ctx->ctx, SSL_SESS_CACHE_CLIENT);
@@ -1130,7 +1133,10 @@
     return 0;
 }
 
-#ifdef NE_HAVE_TS_SSL
+#if defined(NE_HAVE_TS_SSL) && OPENSSL_VERSION_NUMBER < 0x10101000L
+/* For OpenSSL 1.1.1 locking callbacks are no longer need at all. */
+#define WITH_OPENSSL_LOCKING (1)
+
 /* Implementation of locking callbacks to make OpenSSL thread-safe.
  * If the OpenSSL API was better designed, this wouldn't be necessary.
  * In OpenSSL releases without CRYPTO_set_idptr_callback, it's not
@@ -1184,8 +1190,6 @@
     }
 }
 
-#endif
-
 /* ID_CALLBACK_IS_{NEON,OTHER} evaluate as true if the currently
  * registered OpenSSL ID callback is the neon function (_NEON), or has
  * been overwritten by some other app (_OTHER). */
@@ -1196,6 +1200,8 @@
 #define ID_CALLBACK_IS_OTHER (CRYPTO_get_id_callback() != NULL)
 #define ID_CALLBACK_IS_NEON (CRYPTO_get_id_callback() == thread_id_neon)
 #endif
+        
+#endif /* NE_HAVE_TS_SSL && OPENSSL_VERSION_NUMBER < 1.1.1 */
 
 int ne__ssl_init(void)
 {
@@ -1205,7 +1211,7 @@
     SSL_library_init();
     OpenSSL_add_all_algorithms();
 
-#ifdef NE_HAVE_TS_SSL
+#ifdef WITH_OPENSSL_LOCKING
     /* If some other library has already come along and set up the
      * thread-safety callbacks, then it must be presumed that the
      * other library will have a longer lifetime in the process than
@@ -1252,7 +1258,7 @@
     /* Cannot call ERR_free_strings() etc here in case any other code
      * in the process using OpenSSL. */
 
-#ifdef NE_HAVE_TS_SSL
+#ifdef WITH_OPENSSL_LOCKING
     /* Only unregister the callbacks if some *other* library has not
      * come along in the mean-time and trampled over the callbacks
      * installed by neon. */
--- neon-0.30.2/src/ne_pkcs11.c.openssl11
+++ neon-0.30.2/src/ne_pkcs11.c
@@ -113,13 +113,13 @@
         return 0;
     }
 
-    if (padding != RSA_PKCS1_PADDING) {
+    if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) {
         NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, unknown padding mode '%d'.\n", padding);
         RSAerr(PK11_RSA_ERR,ERR_R_RSA_LIB);
         return 0;
     }        
 
-    mech.mechanism = CKM_RSA_PKCS;
+    mech.mechanism = padding == RSA_PKCS1_PADDING ? CKM_RSA_PKCS : CKM_RSA_X_509;
     mech.parameter = NULL;
     mech.parameter_len = 0;
 
--- neon-0.30.2/src/ne_request.c.openssl11
+++ neon-0.30.2/src/ne_request.c
@@ -940,6 +940,12 @@
     }
 }
 
+#ifdef NE_HAVE_SSL
+#define SSL_CC_REQUESTED(_r) (_r->session->ssl_cc_requested)
+#else
+#define SSL_CC_REQUESTED(_r) (0)
+#endif
+
 /* Read and parse response status-line into 'status'.  'retry' is non-zero
  * if an NE_RETRY should be returned if an EOF is received. */
 static int read_status_line(ne_request *req, ne_status *status, int retry)
@@ -949,8 +955,11 @@
 
     ret = ne_sock_readline(req->session->socket, buffer, sizeof req->respbuf);
     if (ret <= 0) {
-	int aret = aborted(req, _("Could not read status line"), ret);
-	return RETRY_RET(retry, ret, aret);
+        const char *errstr = SSL_CC_REQUESTED(req)
+            ? _("Could not read status line (TLS client certificate was requested)")
+            : _("Could not read status line");
+        int aret = aborted(req, errstr, ret);
+        return RETRY_RET(retry, ret, aret);
     }
     
     NE_DEBUG(NE_DBG_HTTP, "[status-line] < %s", buffer);
--- neon-0.30.2/src/ne_socket.c.openssl11
+++ neon-0.30.2/src/ne_socket.c
@@ -179,6 +179,9 @@
 /* Socket read timeout */
 #define SOCKET_READ_TIMEOUT 120
 
+/* Internal read retry value */
+#define NE_SOCK_RETRY (-6)
+    
 /* Critical I/O functions on a socket: useful abstraction for easily
  * handling SSL I/O alongside raw socket I/O. */
 struct iofns {
@@ -599,13 +602,50 @@
 
 static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw, writev_raw };
 
+static int error_ossl(ne_socket *sock, int sret);
+
 #ifdef HAVE_OPENSSL
 /* OpenSSL I/O function implementations. */
 static int readable_ossl(ne_socket *sock, int secs)
 {
+#if OPENSSL_VERSION_NUMBER < 0x10101000L
+    /* Sufficient for TLSv1.2 and earlier. */
     if (SSL_pending(sock->ssl))
 	return 0;
     return readable_raw(sock, secs);
+#else
+    /* TLSv1.3 sends a lot more handshake data so the presence of data
+     * on the socket - i.e. poll() returning 1, is an insufficient
+     * test for app-data readability. */
+    char pending;
+    int ret;
+    size_t bytes;
+
+    /* Loop while no app data is pending, each time attempting a one
+     * byte peek, and retrying the poll if that fails due to absence
+     * of app data. */
+    while (!SSL_pending(sock->ssl)) {
+	ret = readable_raw(sock, secs);
+	if (ret == NE_SOCK_TIMEOUT) {
+	    return ret;
+	}
+        
+	ret = SSL_peek_ex(sock->ssl, &pending, 1, &bytes);
+	if (ret) {
+            /* App data definitely available. */
+	    break;
+	}
+	else {
+            /* If this gave SSL_ERROR_WANT_READ, loop and probably
+             * block again, else some other error happened. */
+            ret = error_ossl(sock, ret);
+            if (ret != NE_SOCK_RETRY)
+                return ret;
+	}
+    }
+
+    return 0;
+#endif /* OPENSSL_VERSION_NUMBER < 1.1.1 */
 }
 
 /* SSL error handling, according to SSL_get_error(3). */
@@ -618,6 +658,10 @@
 	set_error(sock, _("Connection closed"));
         return NE_SOCK_CLOSED;
     }
+    else if (errnum == SSL_ERROR_WANT_READ) {
+        set_error(sock, _("Retry operation"));
+        return NE_SOCK_RETRY;
+    }
     
     /* for all other errors, look at the OpenSSL error stack */
     err = ERR_get_error();
@@ -656,13 +700,15 @@
 {
     int ret;
 
-    ret = readable_ossl(sock, sock->rdtimeout);
-    if (ret) return ret;
-    
-    ret = SSL_read(sock->ssl, buffer, CAST2INT(len));
-    if (ret <= 0)
-	ret = error_ossl(sock, ret);
-
+    do {
+        ret = readable_ossl(sock, sock->rdtimeout);
+        if (ret) return ret;
+        
+        ret = SSL_read(sock->ssl, buffer, CAST2INT(len));
+        if (ret <= 0)
+            ret = error_ossl(sock, ret);
+    } while (ret == NE_SOCK_RETRY);
+        
     return ret;
 }
 
@@ -1761,7 +1807,11 @@
     }
     
     SSL_set_app_data(ssl, userdata);
+#if OPENSSL_VERSION_NUMBER < 0x10101000L
     SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+#else
+    SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
+#endif    
     SSL_set_fd(ssl, sock->fd);
     sock->ops = &iofns_ssl;
 
@@ -1923,12 +1973,13 @@
 {
     int ret;
 
-    /* Per API description - for an SSL connection, simply send the
-     * close_notify but do not wait for the peer's response. */
+    /* Complete a bidirectional shutdown for SSL/TLS. */
 #if defined(HAVE_OPENSSL)
     if (sock->ssl) {
-        SSL_shutdown(sock->ssl);
-	SSL_free(sock->ssl);
+        if (SSL_shutdown(sock->ssl) == 0) {
+            SSL_shutdown(sock->ssl);
+        }
+        SSL_free(sock->ssl);
     }
 #elif defined(HAVE_GNUTLS)
     if (sock->ssl) {
--- neon-0.30.2/test/ssl.c.openssl11
+++ neon-0.30.2/test/ssl.c
@@ -201,6 +201,50 @@
 
 #define DEFSESS  (ne_session_create("https", "localhost", 7777))
 
+static int make_ssl_session_port(ne_session **sess,
+                                 const char *hostname, int port,
+                                 server_fn fn, void *userdata)
+{
+    return fakeproxied_session_server(sess, "https", hostname, port,
+                                      fn, userdata);
+}
+
+static int make_ssl_session(ne_session **sess, const char *hostname,
+                            server_fn fn, void *userdata)
+{
+    return make_ssl_session_port(sess,
+                                 hostname ? hostname : "localhost", 7777,
+                                 fn, userdata);
+}
+
+static int load_and_trust_cert(ne_session *sess, const char *ca_cert)
+{
+    ne_ssl_certificate *ca = ne_ssl_cert_read(ca_cert);
+    ONV(ca == NULL, ("could not load CA cert `%s'", ca_cert));
+    ne_ssl_trust_cert(sess, ca);
+    ne_ssl_cert_free(ca);
+    return OK;
+}
+
+static int make_ssl_request(struct ssl_server_args *args,
+                            const char *ca_cert, const char *hostname,
+                            ne_ssl_verify_fn verify_fn, void *verify_ud)
+{
+    ne_session *sess;
+    int ret;
+
+    CALL(make_ssl_session(&sess, hostname, ssl_server, args));
+
+    if (ca_cert) CALL(load_and_trust_cert(sess, ca_cert));
+    
+    if (verify_fn) ne_ssl_set_verify(sess, verify_fn, verify_ud);
+
+    ret = any_2xx_request(sess, "/foo");
+    CALL(await_server());
+    ne_session_destroy(sess);
+    return ret;
+}
+
 /* Run a request in the given session. */
 static int any_ssl_request(ne_session *sess, server_fn fn, void *server_ud,
 			   char *ca_cert,
@@ -209,10 +253,7 @@
     int ret;
     
     if (ca_cert) {
-        ne_ssl_certificate *ca = ne_ssl_cert_read(ca_cert);
-        ONV(ca == NULL, ("could not load CA cert `%s'", ca_cert));
-        ne_ssl_trust_cert(sess, ca);
-        ne_ssl_cert_free(ca);
+        CALL(load_and_trust_cert(sess, ca_cert));
     }
 
     CALL(spawn_server(7777, fn, server_ud));
@@ -403,12 +444,10 @@
  * unconditionaly. */
 static int accept_signed_cert_for_hostname(char *cert, const char *hostname)
 {
-    ne_session *sess = ne_session_create("https", hostname, 7777);
     struct ssl_server_args args = {cert, 0};
+
     /* no verify callback needed. */
-    CALL(any_ssl_request(sess, ssl_server, &args, CA_CERT, NULL, NULL));
-    ne_session_destroy(sess);
-    return OK;
+    return make_ssl_request(&args, CA_CERT, hostname, NULL, NULL);
 }
 
 
@@ -444,51 +483,34 @@
 }
 #endif
 
-/* Serves using HTTP/1.0 get-till-EOF semantics. */
-static int serve_eof(ne_socket *sock, void *ud)
+/* Test read-til-EOF behaviour with SSL. */
+static int simple_eof(void)
 {
-    struct ssl_server_args args = {0};
+    struct ssl_server_args args = {SERVER_CERT, 0};
 
-    args.cert = ud;
     args.response = "HTTP/1.0 200 OK\r\n"
         "Connection: close\r\n"
         "\r\n"
         "This is a response body, like it or not.";
 
-    return ssl_server(sock, &args);
-}
-
-/* Test read-til-EOF behaviour with SSL. */
-static int simple_eof(void)
-{
-    ne_session *sess = DEFSESS;
-
-    CALL(any_ssl_request(sess, serve_eof, SERVER_CERT, CA_CERT, NULL, NULL));
-    ne_session_destroy(sess);
-    return OK;
+    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);
 }
 
 static int intermediary(void)
 {
-    ne_session *sess = DEFSESS;
     struct ssl_server_args args = {CA2_SERVER_CERT, 0};
-    CALL(any_ssl_request(sess, ssl_server, &args, CA_CERT, NULL, NULL));
-    ne_session_destroy(sess);
-    return OK;
+
+    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);
 }
 
 static int empty_truncated_eof(void)
 {
-    ne_session *sess = DEFSESS;
     struct ssl_server_args args = {0};
 
     args.cert = SERVER_CERT;
     args.response = "HTTP/1.0 200 OK\r\n" "\r\n";
     
-    CALL(any_ssl_request(sess, ssl_server, &args, CA_CERT, NULL, NULL));
-
-    ne_session_destroy(sess);
-    return OK;
+    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);
 }
 
 /* Server function which just sends a string then EOF. */
@@ -502,10 +524,10 @@
 /* test for the SSL negotiation failing. */
 static int fail_not_ssl(void)
 {
-    ne_session *sess = DEFSESS;
+    ne_session *sess;
     int ret;
     
-    CALL(spawn_server(7777, just_serve_string, "Hello, world.\n"));
+    CALL(make_ssl_session(&sess, NULL, just_serve_string, "Hello, world.\n"));
     ret = any_request(sess, "/bar");
     CALL(await_server());
 
@@ -515,44 +537,18 @@
     return OK;
 }
 
-/* Server callback which handles a CONNECT request. */
-static int tunnel_server(ne_socket *sock, void *ud)
-{
-    struct ssl_server_args *args = ud;
-
-    CALL(discard_request(sock));
-
-    SEND_STRING(sock, "HTTP/1.1 200 OK\r\nServer: serve_tunnel\r\n\r\n");
-    
-    return ssl_server(sock, args);
-}
-
 static int wildcard_match(void)
 {
-    ne_session *sess;
     struct ssl_server_args args = {"wildcard.cert", 0};
-    
-    sess = ne_session_create("https", "anything.example.com", 443);
-    ne_session_proxy(sess, "localhost", 7777);
 
-    CALL(any_ssl_request(sess, tunnel_server, &args, CA_CERT, NULL, NULL));
-    ne_session_destroy(sess);
-    
-    return OK;
+    return make_ssl_request(&args, CA_CERT, "bar.example.com", NULL, NULL);
 }
 
 static int wildcard_match_altname(void)
 {
-    ne_session *sess;
     struct ssl_server_args args = {"altname9.cert", 0};
-    
-    sess = ne_session_create("https", "anything.example.com", 443);
-    ne_session_proxy(sess, "localhost", 7777);
 
-    CALL(any_ssl_request(sess, tunnel_server, &args, CA_CERT, NULL, NULL));
-    ne_session_destroy(sess);
-    
-    return OK;
+    return make_ssl_request(&args, CA_CERT, "foo.example.com", NULL, NULL);
 }
 
 /* Check that hostname comparisons are not cases-sensitive. */
@@ -655,15 +651,12 @@
 /* Check that certificate attributes are passed correctly. */
 static int parse_cert(void)
 {
-    ne_session *sess = DEFSESS;
-    int ret = 0;
     struct ssl_server_args args = {SERVER_CERT, 0};
+    int ret = 0;
 
     /* don't give a CA cert; should force the verify callback to be
      * used. */
-    CALL(any_ssl_request(sess, ssl_server, &args, NULL, 
-			 check_cert, &ret));
-    ne_session_destroy(sess);
+    CALL(make_ssl_request(&args, NULL, NULL, check_cert, &ret));
 
     ONN("cert verification never called", ret == 0);
 
@@ -705,7 +698,6 @@
 /* Check that certificate attributes are passed correctly. */
 static int parse_chain(void)
 {
-    ne_session *sess = DEFSESS;
     int ret = 0;
     struct ssl_server_args args = {"wrongcn.cert", 0};
 
@@ -713,9 +705,7 @@
 
     /* The cert is signed by the CA but has a CN mismatch, so will
      * force the verification callback to be invoked. */
-    CALL(any_ssl_request(sess, ssl_server, &args, CA_CERT, 
-			 check_chain, &ret));
-    ne_session_destroy(sess);
+    CALL(make_ssl_request(&args, CA_CERT, NULL, check_chain, &ret));
 
     ONN("cert verification never called", ret == 0);
 
@@ -735,17 +725,13 @@
 
 static int no_verify(void)
 {
-    ne_session *sess = DEFSESS;
     int count = 0;
     struct ssl_server_args args = {SERVER_CERT, 0};
 
-    CALL(any_ssl_request(sess, ssl_server, &args, CA_CERT, count_vfy,
-			 &count));
+    CALL(make_ssl_request(&args, CA_CERT, NULL, count_vfy, &count));
 
     ONN("verify callback called unnecessarily", count != 0);
 
-    ne_session_destroy(sess);
-
     return OK;
 }
 
@@ -834,8 +820,8 @@
 			  get_failures, &gotf);
 
     ONV(gotf == 0,
-	("no error in verification callback; error string: %s",
-	 ne_get_error(sess)));
+	("no error in verification callback; request rv %d error string: %s",
+	 ret, ne_get_error(sess)));
 
     ONV(gotf & ~NE_SSL_FAILMASK,
 	("verification flags %x outside mask %x", gotf, NE_SSL_FAILMASK));
@@ -853,6 +839,7 @@
         
     ne_session_destroy(sess);
     if (addr) ne_addr_destroy(addr);
+    if (list) ne_free(list);
 
     return OK;
 }
@@ -1019,31 +1006,28 @@
                             "issuer ca not yet valid", NE_SSL_BADCHAIN);
 }
 
+#if 0
 /* Test that the SSL session is cached across connections. */
 static int session_cache(void)
 {
     struct ssl_server_args args = {0};
-    ne_session *sess = ne_session_create("https", "localhost", 7777);
-    
+    ne_session *sess;
+
     args.cert = SERVER_CERT;
     args.cache = 1;
 
-    ne_ssl_trust_cert(sess, def_ca_cert);
+    CALL(multi_session_server(&sess, "https", "localhost",
+                              2, ssl_server, &args));
 
-    /* have spawned server listen for several connections. */
-    CALL(spawn_server_repeat(7777, ssl_server, &args, 4));
+    ne_ssl_trust_cert(sess, def_ca_cert);
 
     ONREQ(any_request(sess, "/req1"));
     ONREQ(any_request(sess, "/req2"));
     ne_session_destroy(sess);
-    /* server should still be waiting for connections: if not,
-     * something went wrong. */
-    ONN("error from child", dead_server());
-    /* now get rid of it. */
-    reap_server();
 
-    return OK;
+    return await_server();
 }
+#endif
 
 /* Callback for client_cert_provider; takes a c. cert as userdata and
  * registers it. */
@@ -1201,6 +1185,8 @@
 }
 
 #define NOCERT_MESSAGE "client certificate was requested"
+/* random SSL read may fail like this with TLSv1.3 */
+#define NOCERT_ALT "certificate required"
 
 /* Tests for useful error message if a handshake fails where a client
  * cert was requested. */
@@ -1222,7 +1208,8 @@
     ONV(ret != NE_ERROR,
         ("unexpected result %d: %s", ret, ne_get_error(sess)));
 
-    ONV(strstr(ne_get_error(sess), NOCERT_MESSAGE) == NULL,
+    ONV(strstr(ne_get_error(sess), NOCERT_MESSAGE) == NULL
+        && strstr(ne_get_error(sess), NOCERT_ALT) == NULL,
         ("error message was '%s', missing '%s'", 
          ne_get_error(sess), NOCERT_MESSAGE));
     
@@ -1945,9 +1932,11 @@
     T(nulcn_identity),
     T(fail_nul_cn),
     T(fail_nul_san),
-    
+
+#if 0
     T(session_cache),
-	
+#endif
+
     T(fail_tunnel),
     T(proxy_tunnel),
     T(auth_proxy_tunnel),