Hi,

A while back, Lukas Tribus mentioned that HAproxy used quite a few
OpenSSL internals that were not going to be usable in the 1.1.x branch,
and that we would better take a look at it. As I am currently having
unexpected free time, here is a first attempt at fixing it.

This patch tries to make HAproxy compatible with the OpenSSL 1.1.x
branch, which is still in development, by using accessors instead of
directly using OpenSSL internals when possible, and replacing the use of
deprecated functions by the new ones.

There is still some issues left with this patch:

- in src/shctx.c, the context size increases because I didn't find a way
to alter the session_id_length and sid_ctx_length fields in the same way
it was done before ;
- in ssl_sock_handshake(), we have now slightly less accurate SSL
handshake error messages, because I couldn't find how to retrieve the
information contained in (SSL *)conn->xprt_ctx)->packet_length in a
clean way ;
- in ssl_sock_load_ocsp_response(), we still access the certId field
from a OCSP_SINGLERESP struct, which is becoming opaque in 1.1. I
couldn't find an accessor for this field so I proposed to add one in a
pull request to OpenSSL [1].

Of course these only occur when built against the OpenSSL 1.1.x.

Any comment would be welcome!


Regards,

[1]: https://github.com/openssl/openssl/pull/334

--
Remi Gacogne


From 5b5a5a89b542c9a24c79babf6c1066b18553ecb8 Mon Sep 17 00:00:00 2001
From: Remi Gacogne <[email protected]>
Date: Thu, 23 Jul 2015 16:39:43 +0200
Subject: [PATCH] MEDIUM: ssl: add compatibility with openssl 1.1.x

This patch tries to make HAproxy compatible with the OpenSSL 1.1.x branch, which is still in development, by using accessors instead of directly using OpenSSL internals when possible, and replacing the use of deprecated functions by the new ones.
---
 src/shctx.c    |  37 ++++++++++++++---
 src/ssl_sock.c | 122 +++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 129 insertions(+), 30 deletions(-)

diff --git a/src/shctx.c b/src/shctx.c
index a22730a..b0ff108 100644
--- a/src/shctx.c
+++ b/src/shctx.c
@@ -390,8 +390,18 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
 	unsigned char encsess[sizeof(struct shsess_packet)+SHSESS_MAX_DATA_LEN];
 	struct shsess_packet *packet = (struct shsess_packet *)encsess;
 	unsigned char *p;
-	int data_len, sid_length, sid_ctx_length;
+	const unsigned char *sid;
+	int data_len;
+	unsigned int sid_length;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+	unsigned int sid_ctx_length;
+#endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	sid = SSL_SESSION_get_id(sess,
+				 &sid_length);
+#else
+	sid = sess->session_id;
 
 	/* Session id is already stored in to key and session id is known
 	 * so we dont store it to keep size.
@@ -400,6 +410,7 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
 	sess->session_id_length = 0;
 	sid_ctx_length = sess->sid_ctx_length;
 	sess->sid_ctx_length = 0;
+#endif
 
 	/* check if buffer is large enough for the ASN1 encoded session */
 	data_len = i2d_SSL_SESSION(sess, NULL);
@@ -410,7 +421,7 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
 	p = packet->data;
 	i2d_SSL_SESSION(sess, &p);
 
-	memcpy(packet->hdr.id, sess->session_id, sid_length);
+	memcpy(packet->hdr.id, sid, sid_length);
 	if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
 		memset(&packet->hdr.id[sid_length], 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
 
@@ -422,9 +433,11 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
 	shared_context_unlock();
 
 err:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	/* reset original length values */
 	sess->session_id_length = sid_length;
 	sess->sid_ctx_length = sid_ctx_length;
+#endif
 
 	return 0; /* do not increment session reference count */
 }
@@ -501,6 +514,8 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_cop
 	/* decode ASN1 session */
 	p = data;
 	sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	/* Reset session id and session id contenxt */
 	if (sess) {
 		memcpy(sess->session_id, key, key_len);
@@ -508,6 +523,7 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_cop
 		memcpy(sess->sid_ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
 		sess->sid_ctx_length = ssl->sid_ctx_length;
 	}
+#endif
 
 	return sess;
 }
@@ -517,13 +533,22 @@ void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
 {
 	struct shared_session *shsess;
 	unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
-	unsigned char *key = sess->session_id;
+	const unsigned char *key;
+	unsigned int key_length = 0;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	key = SSL_SESSION_get_id(sess,
+				 &key_length);
+#else
+	key = sess->session_id;
+	key_length = sess->session_id_length;
+#endif
 	(void)ctx;
 
 	/* tree key is zeros padded sessionid */
-	if (sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
-		memcpy(tmpkey, sess->session_id, sess->session_id_length);
-		memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sess->session_id_length);
+	if (key_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
+		memcpy(tmpkey, key, key_length);
+		memset(tmpkey+key_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_length);
 		key = tmpkey;
 	}
 
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 7f1a070..92395db 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -38,12 +38,14 @@
 #include <netdb.h>
 #include <netinet/tcp.h>
 
+#include <openssl/bn.h>
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/x509.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#include <openssl/rsa.h>
 #if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
 #include <openssl/ocsp.h>
 #endif
@@ -271,6 +273,7 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
 	OCSP_RESPONSE *resp;
 	OCSP_BASICRESP *bs = NULL;
 	OCSP_SINGLERESP *sr;
+	OCSP_CERTID *resp_cid = NULL;
 	unsigned char *p = (unsigned char *)ocsp_response->str;
 	int rc , count_sr;
 	ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd = NULL;
@@ -307,6 +310,12 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
 		goto out;
 	}
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	resp_cid = OCSP_SINGLERESP_get0_id(sr);
+#else
+	resp_cid = sr->certId;
+#endif
+
 	rc = OCSP_single_get0_status(sr, &reason, &revtime, &thisupd, &nextupd);
 	if (rc != V_OCSP_CERTSTATUS_GOOD) {
 		memprintf(err, "OCSP single response: certificate status not good");
@@ -325,7 +334,7 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
 	}
 
 	if (cid) {
-		if (OCSP_id_cmp(sr->certId, cid)) {
+		if (OCSP_id_cmp(resp_cid, cid)) {
 			memprintf(err, "OCSP single response: Certificate ID does not match certificate and issuer");
 			goto out;
 		}
@@ -335,7 +344,7 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
 		unsigned char key[OCSP_MAX_CERTID_ASN1_LENGTH];
 		unsigned char *p;
 
-		rc = i2d_OCSP_CERTID(sr->certId, NULL);
+		rc = i2d_OCSP_CERTID(resp_cid, NULL);
 		if (!rc) {
 			memprintf(err, "OCSP single response: Unable to encode Certificate ID");
 			goto out;
@@ -348,7 +357,7 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
 
 		p = key;
 		memset(key, 0, OCSP_MAX_CERTID_ASN1_LENGTH);
-		i2d_OCSP_CERTID(sr->certId, &p);
+		i2d_OCSP_CERTID(resp_cid, &p);
 		ocsp = (struct certificate_ocsp *)ebmb_lookup(&cert_ocsp_tree, key, OCSP_MAX_CERTID_ASN1_LENGTH);
 		if (!ocsp) {
 			memprintf(err, "OCSP single response: Certificate ID does not match any certificate or issuer");
@@ -447,7 +456,11 @@ static int ssl_tlsext_ticket_key_cb(SSL *s, unsigned char key_name[16], unsigned
 	if (enc) {
 		memcpy(key_name, keys[head].name, 16);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+		if(!RAND_bytes(iv, EVP_MAX_IV_LENGTH))
+#else
 		if(!RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH))
+#endif
 			return -1;
 
 		if(!EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, keys[head].aes_key, iv))
@@ -649,7 +662,7 @@ static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
 		if (BIO_read_filename(in, issuer_path) <= 0)
 			goto out;
 
-		xi = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata);
+		xi = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
 		if (!xi)
 			goto out;
 
@@ -964,7 +977,11 @@ void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf
 		 * above as SSL_ERROR_SSL while an other handshake failure with
 		 * a heartbeat message will be reported as SSL_ERROR_SYSCALL.
 		 */
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+		SSL_set_max_send_fragment(ssl, 0);
+#else
 		ssl->max_send_fragment = 0;
+#endif
 		SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_SSL_HANDSHAKE_FAILURE);
 		return;
 	}
@@ -1014,15 +1031,30 @@ ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert,
 	SSL_CTX      *ssl_ctx = NULL;
 	X509         *newcrt  = NULL;
 	EVP_PKEY     *pkey    = NULL;
-	RSA          *rsa;
+	RSA          *rsa     = NULL;
 	X509_NAME    *name;
 	const EVP_MD *digest;
 	X509V3_CTX    ctx;
 	unsigned int  i;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	BIGNUM	     *bn = NULL;
+
+	if (!(bn = BN_new()))
+		goto mkcert_error;
+
+	if (!(rsa = RSA_new()))
+		goto mkcert_error;
+
+	if (!(BN_set_word(bn, 3)))
+		goto mkcert_error;
 
 	/* Generate the public key */
+	if (!(RSA_generate_key_ex(rsa, 2048, bn, NULL)))
+		goto mkcert_error;
+#else
 	if (!(rsa = RSA_generate_key(2048, 3, NULL, NULL)))
 		goto mkcert_error;
+#endif
 	if (!(pkey = EVP_PKEY_new()))
 		goto mkcert_error;
 	if (EVP_PKEY_assign_RSA(pkey, rsa) != 1)
@@ -1092,7 +1124,11 @@ ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert,
 		goto mkcert_error;
 
 	/* Create and set the new SSL_CTX */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	if (!(ssl_ctx = SSL_CTX_new(TLS_server_method())))
+#else
 	if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
+#endif
 		goto mkcert_error;
 	if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
 		goto mkcert_error;
@@ -1101,11 +1137,17 @@ ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert,
 	if (!SSL_CTX_check_private_key(ssl_ctx))
 		goto mkcert_error;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	if (bn)     BN_free(bn);
+#endif
 	if (newcrt) X509_free(newcrt);
 	if (pkey)   EVP_PKEY_free(pkey);
 	return ssl_ctx;
 
  mkcert_error:
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	if (bn)      BN_free(bn);
+#endif
 	if (ssl_ctx) SSL_CTX_free(ssl_ctx);
 	if (newcrt)  X509_free(newcrt);
 	if (pkey)    EVP_PKEY_free(pkey);
@@ -1562,7 +1604,7 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
 	if (BIO_read_filename(in, file) <= 0)
 		goto end;
 
-	x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata);
+	x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
 	if (x == NULL)
 		goto end;
 
@@ -1590,7 +1632,7 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
 		i = -1;
 		while ((i = X509_NAME_get_index_by_NID(xname, NID_commonName, i)) != -1) {
 			X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i);
-			if (ASN1_STRING_to_UTF8((unsigned char **)&str, entry->value) >= 0) {
+			if (ASN1_STRING_to_UTF8((unsigned char **)&str, X509_NAME_ENTRY_get_data(entry)) >= 0) {
 				order = ssl_sock_add_cert_sni(ctx, s, str, order);
 				OPENSSL_free(str);
 			}
@@ -1601,12 +1643,16 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
 	if (!SSL_CTX_use_certificate(ctx, x))
 		goto end;
 
+#ifdef SSL_CTX_clear_extra_chain_certs
+	SSL_CTX_clear_extra_chain_certs(ctx);
+#else
 	if (ctx->extra_certs != NULL) {
 		sk_X509_pop_free(ctx->extra_certs, X509_free);
 		ctx->extra_certs = NULL;
 	}
+#endif
 
-	while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata))) {
+	while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
 		if (!SSL_CTX_add_extra_chain_cert(ctx, ca)) {
 			X509_free(ca);
 			goto end;
@@ -1635,7 +1681,12 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf
 	int ret;
 	SSL_CTX *ctx;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	ctx = SSL_CTX_new(TLS_server_method());
+#else
 	ctx = SSL_CTX_new(SSLv23_server_method());
+#endif
+
 	if (!ctx) {
 		memprintf(err, "%sunable to allocate SSL context for cert '%s'.\n",
 		          err && *err ? *err : "", path);
@@ -2226,7 +2277,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
 	i = -1;
 	while (!ok && (i = X509_NAME_get_index_by_NID(cert_subject, NID_commonName, i)) != -1) {
 		X509_NAME_ENTRY *entry = X509_NAME_get_entry(cert_subject, i);
-		if (ASN1_STRING_to_UTF8((unsigned char **)&str, entry->value) >= 0) {
+		if (ASN1_STRING_to_UTF8((unsigned char **)&str, X509_NAME_ENTRY_get_data(entry)) >= 0) {
 			ok = ssl_sock_srv_hostcheck(str, servername);
 			OPENSSL_free(str);
 		}
@@ -2266,7 +2317,12 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy)
 	if (srv->check.use_ssl)
 		srv->check.xprt = &ssl_sock;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	srv->ssl_ctx.ctx = SSL_CTX_new(TLS_client_method());
+#else
 	srv->ssl_ctx.ctx = SSL_CTX_new(SSLv23_client_method());
+#endif
+
 	if (!srv->ssl_ctx.ctx) {
 		Alert("config : %s '%s', server '%s': unable to allocate ssl context.\n",
 		      proxy_type_str(curproxy), curproxy->id,
@@ -2721,6 +2777,12 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
 				if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
 					conn->flags &= ~CO_FL_WAIT_L4_CONN;
 				if (!conn->err_code) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+					if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
+						conn->err_code = CO_ER_SSL_HANDSHAKE_HB;
+					else
+						conn->err_code = CO_ER_SSL_HANDSHAKE;
+#else
 					if (!((SSL *)conn->xprt_ctx)->packet_length) {
 						if (!errno) {
 							if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
@@ -2741,6 +2803,7 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
 						else
 							conn->err_code = CO_ER_SSL_HANDSHAKE;
 					}
+#endif
 				}
 				goto out_error;
 			}
@@ -2788,6 +2851,12 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
 			if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
 				conn->flags &= ~CO_FL_WAIT_L4_CONN;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+			if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
+				conn->err_code = CO_ER_SSL_HANDSHAKE_HB;
+			else
+				conn->err_code = CO_ER_SSL_HANDSHAKE;
+#else
 			if (!((SSL *)conn->xprt_ctx)->packet_length) {
 				if (!errno) {
 					if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
@@ -2808,6 +2877,7 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
 				else
 					conn->err_code = CO_ER_SSL_HANDSHAKE;
 			}
+#endif
 			goto out_error;
 		}
 		else {
@@ -3205,16 +3275,16 @@ ssl_sock_get_dn_entry(X509_NAME *a, const struct chunk *entry, int pos, struct c
 	char tmp[128];
 
 	out->len = 0;
-	for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
+	for (i = 0; i < X509_NAME_entry_count(a); i++) {
 		if (pos < 0)
-			j = (sk_X509_NAME_ENTRY_num(a->entries)-1) - i;
+			j = (X509_NAME_entry_count(a)-1) - i;
 		else
 			j = i;
 
-		ne = sk_X509_NAME_ENTRY_value(a->entries, j);
-		n = OBJ_obj2nid(ne->object);
+		ne = X509_NAME_get_entry(a, j);
+		n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne));
 		if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
-			i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
+			i2t_ASN1_OBJECT(tmp, sizeof(tmp), X509_NAME_ENTRY_get_object(ne));
 			s = tmp;
 		}
 
@@ -3229,11 +3299,11 @@ ssl_sock_get_dn_entry(X509_NAME *a, const struct chunk *entry, int pos, struct c
 		if (cur != pos)
 			continue;
 
-		if (ne->value->length > out->size)
+		if (X509_NAME_ENTRY_get_data(ne)->length > out->size)
 			return -1;
 
-		memcpy(out->str, ne->value->data, ne->value->length);
-		out->len = ne->value->length;
+		memcpy(out->str, X509_NAME_ENTRY_get_data(ne)->data, X509_NAME_ENTRY_get_data(ne)->length);
+		out->len = X509_NAME_ENTRY_get_data(ne)->length;
 		return 1;
 	}
 
@@ -3256,16 +3326,16 @@ ssl_sock_get_dn_oneline(X509_NAME *a, struct chunk *out)
 
 	out->len = 0;
 	p = out->str;
-	for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
-		ne = sk_X509_NAME_ENTRY_value(a->entries, i);
-		n = OBJ_obj2nid(ne->object);
+	for (i = 0; i < X509_NAME_entry_count(a); i++) {
+		ne = X509_NAME_get_entry(a, i);
+		n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne));
 		if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
-			i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
+			i2t_ASN1_OBJECT(tmp, sizeof(tmp), X509_NAME_ENTRY_get_object(ne));
 			s = tmp;
 		}
 		ln = strlen(s);
 
-		l += 1 + ln + 1 + ne->value->length;
+		l += 1 + ln + 1 + X509_NAME_ENTRY_get_data(ne)->length;
 		if (l > out->size)
 			return -1;
 		out->len = l;
@@ -3274,8 +3344,8 @@ ssl_sock_get_dn_oneline(X509_NAME *a, struct chunk *out)
 		memcpy(p, s, ln);
 		p += ln;
 		*(p++)='=';
-		memcpy(p, ne->value->data, ne->value->length);
-		p += ne->value->length;
+		memcpy(p, X509_NAME_ENTRY_get_data(ne)->data, X509_NAME_ENTRY_get_data(ne)->length);
+		p += X509_NAME_ENTRY_get_data(ne)->length;
 	}
 
 	if (!out->len)
@@ -5370,7 +5440,11 @@ static void __ssl_sock_deinit(void)
 	}
 #endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+	ERR_remove_thread_state(NULL);
+#else
         ERR_remove_state(0);
+#endif
         ERR_free_strings();
 
         EVP_cleanup();
-- 
2.4.6

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to