BUG/MINOR: ssl: always check for ssl connection before getting its XPRT context

In several SSL functions, the XPRT context is retrieved before any check on the
connection. In the function ssl_sock_is_ssl(), a test suggests the connection
may be null. So, it is safer to test the ssl connection before retrieving its
XPRT context. It removes any ambiguities and prevents possible null pointer
dereferences.

This patch fixes the issue #265. It must be backported to 2.0.

(cherry picked from commit 82004145d495bc3f159af06acad333fa6da4b58d)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 6242846..97a1b78 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -6093,7 +6093,7 @@
 /* used for ppv2 pkey alog (can be used for logging) */
 int ssl_sock_get_pkey_algo(struct connection *conn, struct buffer *out)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 	struct pkey_info *pkinfo;
 	int bits = 0;
 	int sig = TLSEXT_signature_anonymous;
@@ -6101,7 +6101,7 @@
 
 	if (!ssl_sock_is_ssl(conn))
 		return 0;
-
+	ctx = conn->xprt_ctx;
 	pkinfo = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ctx->ssl), ssl_pkey_info_index);
 	if (pkinfo) {
 		sig = pkinfo->sig;
@@ -6152,13 +6152,14 @@
 /* used for ppv2 cert signature (can be used for logging) */
 const char *ssl_sock_get_cert_sig(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	__OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
 	X509 *crt;
 
 	if (!ssl_sock_is_ssl(conn))
 		return NULL;
+	ctx = conn->xprt_ctx;
 	crt = SSL_get_certificate(ctx->ssl);
 	if (!crt)
 		return NULL;
@@ -6170,10 +6171,11 @@
 const char *ssl_sock_get_sni(struct connection *conn)
 {
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return NULL;
+	ctx = conn->xprt_ctx;
 	return SSL_get_servername(ctx->ssl, TLSEXT_NAMETYPE_host_name);
 #else
 	return NULL;
@@ -6183,22 +6185,22 @@
 /* used for logging/ppv2, may be changed for a sample fetch later */
 const char *ssl_sock_get_cipher_name(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return NULL;
-
+	ctx = conn->xprt_ctx;
 	return SSL_get_cipher_name(ctx->ssl);
 }
 
 /* used for logging/ppv2, may be changed for a sample fetch later */
 const char *ssl_sock_get_proto_version(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return NULL;
-
+	ctx = conn->xprt_ctx;
 	return SSL_get_version(ctx->ssl);
 }
 
@@ -6404,11 +6406,11 @@
 void ssl_sock_set_alpn(struct connection *conn, const unsigned char *alpn, int len)
 {
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return;
-
+	ctx = conn->xprt_ctx;
 	SSL_set_alpn_protos(ctx->ssl, alpn, len);
 #endif
 }
@@ -6419,12 +6421,13 @@
 void ssl_sock_set_servername(struct connection *conn, const char *hostname)
 {
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	char *prev_name;
 
 	if (!ssl_sock_is_ssl(conn))
 		return;
+	ctx = conn->xprt_ctx;
 
 	/* if the SNI changes, we must destroy the reusable context so that a
 	 * new connection will present a new SNI. As an optimization we could
@@ -6449,7 +6452,7 @@
 int ssl_sock_get_remote_common_name(struct connection *conn,
 				    struct buffer *dest)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 	X509 *crt = NULL;
 	X509_NAME *name;
 	const char find_cn[] = "CN";
@@ -6461,6 +6464,7 @@
 
 	if (!ssl_sock_is_ssl(conn))
 		goto out;
+	ctx = conn->xprt_ctx;
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
 	crt = SSL_get_peer_certificate(ctx->ssl);
@@ -6482,11 +6486,12 @@
 /* returns 1 if client passed a certificate for this session, 0 if not */
 int ssl_sock_get_cert_used_sess(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 	X509 *crt = NULL;
 
 	if (!ssl_sock_is_ssl(conn))
 		return 0;
+	ctx = conn->xprt_ctx;
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
 	crt = SSL_get_peer_certificate(ctx->ssl);
@@ -6500,22 +6505,22 @@
 /* returns 1 if client passed a certificate for this connection, 0 if not */
 int ssl_sock_get_cert_used_conn(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return 0;
-
+	ctx = conn->xprt_ctx;
 	return SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
 }
 
 /* returns result from SSL verify */
 unsigned int ssl_sock_get_verify_result(struct connection *conn)
 {
-	struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+	struct ssl_sock_ctx *ctx;
 
 	if (!ssl_sock_is_ssl(conn))
 		return (unsigned int)X509_V_ERR_APPLICATION_VERIFICATION;
-
+	ctx = conn->xprt_ctx;
 	return (unsigned int)SSL_get_verify_result(ctx->ssl);
 }