--- 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),