MEDIUM: ssl: Add support for OpenSSL 1.1.0

In the last release a lot of the structures have become opaque for an
end user. This means the code using these needs to be changed to use the
proper functions to interact with these structures instead of trying to
manipulate them directly.

This does not fix any deprecations yet that are part of 1.1.0, it only
ensures that it can be compiled against that version and is still
compatible with older ones.

[wt: openssl-0.9.8 doesn't build with it, there are conflicts on certain
     function prototypes which we declare as inline here and which are
     defined differently there. But openssl-0.9.8 is not supported anymore
     so probably it's OK to go without it for now and we'll see later if
     some users still need it. Emeric has reviewed this change and didn't
     spot anything obvious which requires special care. Let's try it for
     real now]
This commit is contained in:
Dirkjan Bussink 2016-08-29 13:26:37 +02:00 committed by Willy Tarreau
parent e5d3169e1c
commit 1866d6d8f1
4 changed files with 323 additions and 68 deletions

View File

@ -579,6 +579,9 @@ ifneq ($(USE_OPENSSL),)
BUILD_OPTIONS += $(call ignore_implicit,USE_OPENSSL)
OPTIONS_CFLAGS += -DUSE_OPENSSL $(if $(SSL_INC),-I$(SSL_INC))
OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
ifneq ($(USE_DL),)
OPTIONS_LDFLAGS += -ldl
endif
OPTIONS_OBJS += src/ssl_sock.o src/shctx.o
ifneq ($(USE_PRIVATE_CACHE),)
OPTIONS_CFLAGS += -DUSE_PRIVATE_CACHE

View File

@ -0,0 +1,142 @@
#ifndef _PROTO_OPENSSL_COMPAT_H
#define _PROTO_OPENSSL_COMPAT_H
#include <openssl/crypto.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>
#if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#endif
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
#if (OPENSSL_VERSION_NUMBER < 0x1000000fL)
/*
* Functions introduced in OpenSSL 1.0.1
*/
static inline int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx, unsigned int sid_ctx_len)
{
s->sid_ctx_length = sid_ctx_len;
memcpy(s->sid_ctx, sid_ctx, sid_ctx_len);
return 1;
}
static inline int EVP_PKEY_base_id(const EVP_PKEY *pkey)
{
return EVP_PKEY_type(pkey->type);
}
static inline const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *sess, unsigned int *sid_length)
{
*sid_length = sess->session_id_length;
return sess->session_id;
}
static inline X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc)
{
return sk_X509_NAME_ENTRY_value(name->entries, loc);
}
static inline ASN1_OBJECT *X509_NAME_ENTRY_get_object(const X509_NAME_ENTRY *ne)
{
return ne->object;
}
static inline ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne)
{
return ne->value;
}
static inline int ASN1_STRING_length(const ASN1_STRING *x)
{
return x->length;
}
static inline int X509_NAME_entry_count(X509_NAME *name)
{
return sk_X509_NAME_ENTRY_num(name->entries)
}
int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, X509_ALGOR **pa, X509_PUBKEY *pub)
{
*ppkalg = pub->algor->algorithm;
return 1;
}
static inline void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, const void **ppval, const X509_ALGOR *algor)
{
*paobj = algor->algorithm;
}
#ifndef X509_get_X509_PUBKEY
#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key
#endif
#endif
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
/*
* Functions introduced in OpenSSL 1.1.0
*/
static inline const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length)
{
*sid_ctx_length = sess->sid_ctx_length;
return sess->sid_ctx;
}
static inline int SSL_SESSION_set1_id(SSL_SESSION *s, const unsigned char *sid, unsigned int sid_len)
{
s->session_id_length = sid_len;
memcpy(s->session_id, sid, sid_len);
return 1;
}
static inline const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single)
{
return single->certId;
}
static inline pem_password_cb *SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
{
return ctx->default_passwd_callback;
}
static inline void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
{
return ctx->default_passwd_callback_userdata;
}
#ifndef OPENSSL_NO_DH
static inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
/* Implements only the bare necessities for HAProxy */
dh->p = p;
dh->g = g;
return 1;
}
#endif
static inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
{
return x->data;
}
static inline X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x)
{
return x->cert_info->signature;
}
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
#define __OPENSSL_110_CONST__ const
#else
#define __OPENSSL_110_CONST__
#endif
#endif /* _PROTO_OPENSSL_COMPAT_H */

View File

@ -27,6 +27,7 @@
#include <ebmbtree.h>
#include <types/global.h>
#include "proto/shctx.h"
#include <proto/openssl-compat.h>
struct shsess_packet_hdr {
unsigned int eol;
@ -390,16 +391,19 @@ 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;
int data_len;
unsigned int sid_length, sid_ctx_length;
const unsigned char *sid_data;
const unsigned char *sid_ctx_data;
/* Session id is already stored in to key and session id is known
* so we dont store it to keep size.
*/
sid_length = sess->session_id_length;
sess->session_id_length = 0;
sid_ctx_length = sess->sid_ctx_length;
sess->sid_ctx_length = 0;
sid_data = SSL_SESSION_get_id(sess, &sid_length);
sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
SSL_SESSION_set1_id(sess, sid_data, 0);
SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
/* check if buffer is large enough for the ASN1 encoded session */
data_len = i2d_SSL_SESSION(sess, NULL);
@ -410,7 +414,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_data, 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);
@ -423,14 +427,14 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
err:
/* reset original length values */
sess->session_id_length = sid_length;
sess->sid_ctx_length = sid_ctx_length;
SSL_SESSION_set1_id(sess, sid_data, sid_length);
SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
return 0; /* do not increment session reference count */
}
/* SSL callback used on lookup an existing session cause none found in internal cache */
SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy)
SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, int key_len, int *do_copy)
{
struct shared_session *shsess;
unsigned char data[SHSESS_MAX_DATA_LEN], *p;
@ -503,10 +507,8 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_cop
sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
/* Reset session id and session id contenxt */
if (sess) {
memcpy(sess->session_id, key, key_len);
sess->session_id_length = key_len;
memcpy(sess->sid_ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
sess->sid_ctx_length = ssl->sid_ctx_length;
SSL_SESSION_set1_id(sess, key, key_len);
SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
}
return sess;
@ -517,20 +519,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;
unsigned int sid_length;
const unsigned char *sid_data;
(void)ctx;
sid_data = SSL_SESSION_get_id(sess, &sid_length);
/* 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);
key = tmpkey;
if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
memcpy(tmpkey, sid_data, sid_length);
memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
sid_data = tmpkey;
}
shared_context_lock();
/* lookup for session */
shsess = shsess_tree_lookup(key);
shsess = shsess_tree_lookup(sid_data);
if (shsess) {
/* free session */
shsess_tree_delete(shsess);

View File

@ -39,6 +39,7 @@
#include <netdb.h>
#include <netinet/tcp.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@ -78,6 +79,7 @@
#include <proto/freq_ctr.h>
#include <proto/frontend.h>
#include <proto/listener.h>
#include <proto/openssl-compat.h>
#include <proto/pattern.h>
#include <proto/proto_tcp.h>
#include <proto/server.h>
@ -326,6 +328,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 *id;
unsigned char *p = (unsigned char *)ocsp_response->str;
int rc , count_sr;
ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd = NULL;
@ -362,6 +365,8 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
goto out;
}
id = (OCSP_CERTID*)OCSP_SINGLERESP_get0_id(sr);
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");
@ -380,7 +385,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(id, cid)) {
memprintf(err, "OCSP single response: Certificate ID does not match certificate and issuer");
goto out;
}
@ -390,7 +395,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(id, NULL);
if (!rc) {
memprintf(err, "OCSP single response: Unable to encode Certificate ID");
goto out;
@ -403,7 +408,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(id, &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");
@ -642,7 +647,7 @@ int ssl_sock_ocsp_stapling_cbk(SSL *ssl, void *arg)
if (!ssl_pkey)
return SSL_TLSEXT_ERR_NOACK;
key_type = EVP_PKEY_type(ssl_pkey->type);
key_type = EVP_PKEY_base_id(ssl_pkey);
if (ocsp_arg->is_single && ocsp_arg->single_kt == key_type)
ocsp = ocsp_arg->s_ocsp;
@ -705,6 +710,9 @@ static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
struct certificate_ocsp *ocsp = NULL, *iocsp;
char *warn = NULL;
unsigned char *p;
pem_password_cb *passwd_cb;
void *passwd_cb_userdata;
void (*callback) (void);
snprintf(ocsp_path, MAXPATHLEN+1, "%s.ocsp", cert_path);
@ -745,7 +753,10 @@ 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);
passwd_cb = SSL_CTX_get_default_passwd_cb(ctx);
passwd_cb_userdata = SSL_CTX_get_default_passwd_cb_userdata(ctx);
xi = PEM_read_bio_X509_AUX(in, NULL, passwd_cb, passwd_cb_userdata);
if (!xi)
goto out;
@ -774,12 +785,19 @@ static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
if (iocsp == ocsp)
ocsp = NULL;
if (!ctx->tlsext_status_cb) {
#ifndef SSL_CTX_get_tlsext_status_cb
# define SSL_CTX_get_tlsext_status_cb(ctx, cb) \
*cb = (void (*) (void))ctx->tlsext_status_cb;
#endif
SSL_CTX_get_tlsext_status_cb(ctx, &callback);
if (!callback) {
struct ocsp_cbk_arg *cb_arg = calloc(1, sizeof(*cb_arg));
cb_arg->is_single = 1;
cb_arg->s_ocsp = iocsp;
cb_arg->single_kt = EVP_PKEY_type(X509_get_pubkey(x)->type);
cb_arg->single_kt = EVP_PKEY_base_id(X509_get_pubkey(x));
SSL_CTX_set_tlsext_status_cb(ctx, ssl_sock_ocsp_stapling_cbk);
SSL_CTX_set_tlsext_status_arg(ctx, cb_arg);
@ -788,9 +806,16 @@ static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
* If the ctx has a status CB, then we have previously set an OCSP staple for this ctx
* Update that cb_arg with the new cert's staple
*/
struct ocsp_cbk_arg *cb_arg = ctx->tlsext_status_arg;
struct ocsp_cbk_arg *cb_arg;
struct certificate_ocsp *tmp_ocsp;
int index;
int key_type;
#ifdef SSL_CTX_get_tlsext_status_arg
SSL_CTX_ctrl(ctx, SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG, 0, &cb_arg);
#else
cb_arg = ctx->tlsext_status_arg;
#endif
/*
* The following few lines will convert cb_arg from a single ocsp to multi ocsp
@ -803,7 +828,8 @@ static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
cb_arg->is_single = 0;
cb_arg->single_kt = 0;
index = ssl_sock_get_ocsp_arg_kt_index(EVP_PKEY_type(X509_get_pubkey(x)->type));
key_type = EVP_PKEY_base_id(X509_get_pubkey(x));
index = ssl_sock_get_ocsp_arg_kt_index(key_type);
if (index >= 0 && !cb_arg->m_ocsp[index])
cb_arg->m_ocsp[index] = iocsp;
@ -1154,6 +1180,7 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
const EVP_MD *digest;
X509V3_CTX ctx;
unsigned int i;
int key_type;
/* Get the private key of the defautl certificate and use it */
if (!(pkey = SSL_get_privatekey(ssl)))
@ -1215,11 +1242,14 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
}
/* Sign the certificate with the CA private key */
if (EVP_PKEY_type(capkey->type) == EVP_PKEY_DSA)
digest = EVP_dss1();
else if (EVP_PKEY_type (capkey->type) == EVP_PKEY_RSA)
key_type = EVP_PKEY_base_id(capkey);
if (key_type == EVP_PKEY_DSA)
digest = EVP_sha1();
else if (key_type == EVP_PKEY_RSA)
digest = EVP_sha256();
else if (EVP_PKEY_type (capkey->type) == EVP_PKEY_EC)
else if (key_type == EVP_PKEY_EC)
digest = EVP_sha256();
else {
#if (OPENSSL_VERSION_NUMBER >= 0x1000000fL)
@ -1451,14 +1481,18 @@ static DH * ssl_get_dh_1024(void)
0x02,
};
BIGNUM *p;
BIGNUM *g;
DH *dh = DH_new();
if (dh) {
dh->p = BN_bin2bn(dh1024_p, sizeof dh1024_p, NULL);
dh->g = BN_bin2bn(dh1024_g, sizeof dh1024_g, NULL);
p = BN_bin2bn(dh1024_p, sizeof dh1024_p, NULL);
g = BN_bin2bn(dh1024_g, sizeof dh1024_g, NULL);
if (!dh->p || !dh->g) {
if (!p || !g) {
DH_free(dh);
dh = NULL;
} else {
DH_set0_pqg(dh, p, NULL, g);
}
}
return dh;
@ -1494,14 +1528,18 @@ static DH *ssl_get_dh_2048(void)
0x02,
};
BIGNUM *p;
BIGNUM *g;
DH *dh = DH_new();
if (dh) {
dh->p = BN_bin2bn(dh2048_p, sizeof dh2048_p, NULL);
dh->g = BN_bin2bn(dh2048_g, sizeof dh2048_g, NULL);
p = BN_bin2bn(dh2048_p, sizeof dh2048_p, NULL);
g = BN_bin2bn(dh2048_g, sizeof dh2048_g, NULL);
if (!dh->p || !dh->g) {
if (!p || !g) {
DH_free(dh);
dh = NULL;
} else {
DH_set0_pqg(dh, p, NULL, g);
}
}
return dh;
@ -1558,14 +1596,18 @@ static DH *ssl_get_dh_4096(void)
0x02,
};
BIGNUM *p;
BIGNUM *g;
DH *dh = DH_new();
if (dh) {
dh->p = BN_bin2bn(dh4096_p, sizeof dh4096_p, NULL);
dh->g = BN_bin2bn(dh4096_g, sizeof dh4096_g, NULL);
p = BN_bin2bn(dh4096_p, sizeof dh4096_p, NULL);
g = BN_bin2bn(dh4096_g, sizeof dh4096_g, NULL);
if (!dh->p || !dh->g) {
if (!p || !g) {
DH_free(dh);
dh = NULL;
} else {
DH_set0_pqg(dh, p, NULL, g);
}
}
return dh;
@ -1577,7 +1619,9 @@ static DH *ssl_get_tmp_dh(SSL *ssl, int export, int keylen)
{
DH *dh = NULL;
EVP_PKEY *pkey = SSL_get_privatekey(ssl);
int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
int type;
type = pkey ? EVP_PKEY_base_id(pkey) : EVP_PKEY_NONE;
/* The keylen supplied by OpenSSL can only be 512 or 1024.
See ssl3_send_server_key_exchange() in ssl/s3_srvr.c
@ -2035,8 +2079,9 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con
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) {
ASN1_STRING *value;
value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
/* Important line is here */
ssl_sock_populate_sni_keytypes_hplr(str, &sni_keytypes_map, n);
@ -2207,6 +2252,9 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
int order = 0;
X509_NAME *xname;
char *str;
pem_password_cb *passwd_cb;
void *passwd_cb_userdata;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
STACK_OF(GENERAL_NAME) *names;
#endif
@ -2218,7 +2266,11 @@ 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);
passwd_cb = SSL_CTX_get_default_passwd_cb(ctx);
passwd_cb_userdata = SSL_CTX_get_default_passwd_cb_userdata(ctx);
x = PEM_read_bio_X509_AUX(in, NULL, passwd_cb, passwd_cb_userdata);
if (x == NULL)
goto end;
@ -2246,7 +2298,10 @@ 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) {
ASN1_STRING *value;
value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
order = ssl_sock_add_cert_sni(ctx, s, str, order);
OPENSSL_free(str);
}
@ -2257,12 +2312,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, passwd_cb, passwd_cb_userdata))) {
if (!SSL_CTX_add_extra_chain_cert(ctx, ca)) {
X509_free(ca);
goto end;
@ -2944,7 +3003,9 @@ 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) {
ASN1_STRING *value;
value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
ok = ssl_sock_srv_hostcheck(str, servername);
OPENSSL_free(str);
}
@ -3455,7 +3516,15 @@ 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 (!((SSL *)conn->xprt_ctx)->packet_length) {
int empty_handshake;
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
OSSL_HANDSHAKE_STATE state = SSL_get_state((SSL *)conn->xprt_ctx);
empty_handshake = state == TLS_ST_BEFORE;
#else
empty_handshake = !((SSL *)conn->xprt_ctx)->packet_length;
#endif
if (empty_handshake) {
if (!errno) {
if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
conn->err_code = CO_ER_SSL_HANDSHAKE_HB;
@ -3518,11 +3587,21 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
return 0;
}
else if (ret == SSL_ERROR_SYSCALL) {
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
OSSL_HANDSHAKE_STATE state;
#endif
int empty_handshake;
/* if errno is null, then connection was successfully established */
if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
conn->flags &= ~CO_FL_WAIT_L4_CONN;
if (!((SSL *)conn->xprt_ctx)->packet_length) {
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
state = SSL_get_state((SSL *)conn->xprt_ctx);
empty_handshake = state == TLS_ST_BEFORE;
#else
empty_handshake = !((SSL *)conn->xprt_ctx)->packet_length;
#endif
if (empty_handshake) {
if (!errno) {
if (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT)
conn->err_code = CO_ER_SSL_HANDSHAKE_HB;
@ -3937,22 +4016,33 @@ static int
ssl_sock_get_dn_entry(X509_NAME *a, const struct chunk *entry, int pos, struct chunk *out)
{
X509_NAME_ENTRY *ne;
ASN1_OBJECT *obj;
ASN1_STRING *data;
const unsigned char *data_ptr;
int data_len;
int i, j, n;
int cur = 0;
const char *s;
char tmp[128];
int name_count;
name_count = X509_NAME_entry_count(a);
out->len = 0;
for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
for (i = 0; i < name_count; i++) {
if (pos < 0)
j = (sk_X509_NAME_ENTRY_num(a->entries)-1) - i;
j = (name_count-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);
obj = X509_NAME_ENTRY_get_object(ne);
data = X509_NAME_ENTRY_get_data(ne);
data_ptr = ASN1_STRING_get0_data(data);
data_len = ASN1_STRING_length(data);
n = OBJ_obj2nid(obj);
if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
s = tmp;
}
@ -3967,11 +4057,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 (data_len > out->size)
return -1;
memcpy(out->str, ne->value->data, ne->value->length);
out->len = ne->value->length;
memcpy(out->str, data_ptr, data_len);
out->len = data_len;
return 1;
}
@ -3986,24 +4076,36 @@ static int
ssl_sock_get_dn_oneline(X509_NAME *a, struct chunk *out)
{
X509_NAME_ENTRY *ne;
ASN1_OBJECT *obj;
ASN1_STRING *data;
const unsigned char *data_ptr;
int data_len;
int i, n, ln;
int l = 0;
const char *s;
char *p;
char tmp[128];
int name_count;
name_count = X509_NAME_entry_count(a);
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 < name_count; i++) {
ne = X509_NAME_get_entry(a, i);
obj = X509_NAME_ENTRY_get_object(ne);
data = X509_NAME_ENTRY_get_data(ne);
data_ptr = ASN1_STRING_get0_data(data);
data_len = ASN1_STRING_length(data);
n = OBJ_obj2nid(obj);
if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
s = tmp;
}
ln = strlen(s);
l += 1 + ln + 1 + ne->value->length;
l += 1 + ln + 1 + data_len;
if (l > out->size)
return -1;
out->len = l;
@ -4012,8 +4114,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, data_ptr, data_len);
p += data_len;
}
if (!out->len)
@ -4540,6 +4642,7 @@ smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *
{
int cert_peer = (kw[4] == 'c') ? 1 : 0;
X509 *crt;
__OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
int nid;
struct connection *conn;
@ -4559,7 +4662,8 @@ smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *
if (!crt)
return 0;
nid = OBJ_obj2nid((ASN1_OBJECT *)(crt->cert_info->signature->algorithm));
X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
nid = OBJ_obj2nid(algorithm);
smp->data.u.str.str = (char *)OBJ_nid2sn(nid);
if (!smp->data.u.str.str) {
@ -4588,6 +4692,7 @@ smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *
{
int cert_peer = (kw[4] == 'c') ? 1 : 0;
X509 *crt;
ASN1_OBJECT *algorithm;
int nid;
struct connection *conn;
@ -4607,7 +4712,8 @@ smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *
if (!crt)
return 0;
nid = OBJ_obj2nid((ASN1_OBJECT *)(crt->cert_info->key->algor->algorithm));
X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
nid = OBJ_obj2nid(algorithm);
smp->data.u.str.str = (char *)OBJ_nid2sn(nid);
if (!smp->data.u.str.str) {