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
signature.asc
Description: OpenPGP digital signature

