MEDIUM: ssl: convert CBS (BoringSSL api) usage to neutral code

switchctx early callback is only supported for BoringSSL. To prepare
the support of openssl 1.1.1 early callback, convert CBS api to neutral
code to work with any ssl libs.
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 3d97239..25b846b 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1965,50 +1965,57 @@
 
 static int ssl_sock_switchctx_cbk(const struct ssl_early_callback_ctx *ctx)
 {
+	SSL *ssl = ctx->ssl;
 	struct connection *conn;
 	struct bind_conf *s;
 	const uint8_t *extension_data;
 	size_t extension_len;
-	CBS extension, cipher_suites, server_name_list, host_name, sig_algs;
-	const SSL_CIPHER *cipher;
-	uint16_t cipher_suite;
-	uint8_t name_type, hash, sign;
 	int has_rsa = 0, has_ecdsa = 0, has_ecdsa_sig = 0;
 
 	char *wildp = NULL;
 	const uint8_t *servername;
+	size_t servername_len;
 	struct ebmb_node *node, *n, *node_ecdsa = NULL, *node_rsa = NULL, *node_anonymous = NULL;
 	int i;
 
-	conn = SSL_get_app_data(ctx->ssl);
+	conn = SSL_get_app_data(ssl);
 	s = objt_listener(conn->target)->bind_conf;
 
 	if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name,
 						 &extension_data, &extension_len)) {
-		CBS_init(&extension, extension_data, extension_len);
-
-		if (!CBS_get_u16_length_prefixed(&extension, &server_name_list)
-		    || !CBS_get_u8(&server_name_list, &name_type)
-		    /* Although the server_name extension was intended to be extensible to
-		     * new name types and multiple names, OpenSSL 1.0.x had a bug which meant
-		     * different name types will cause an error. Further, RFC 4366 originally
-		     * defined syntax inextensibly. RFC 6066 corrected this mistake, but
-		     * adding new name types is no longer feasible.
-		     *
-		     * Act as if the extensibility does not exist to simplify parsing. */
-		    || !CBS_get_u16_length_prefixed(&server_name_list, &host_name)
-		    || CBS_len(&server_name_list) != 0
-		    || CBS_len(&extension) != 0
-		    || name_type != TLSEXT_NAMETYPE_host_name
-		    || CBS_len(&host_name) == 0
-		    || CBS_len(&host_name) > TLSEXT_MAXLEN_host_name
-		    || CBS_contains_zero_byte(&host_name)) {
+		/*
+		 * The server_name extension was given too much extensibility when it
+		 * was written, so parsing the normal case is a bit complex.
+		 */
+		size_t len;
+		if (extension_len <= 2)
 			goto abort;
-		}
+		/* Extract the length of the supplied list of names. */
+		len = (*extension_data++) << 8;
+		len |= *extension_data++;
+		if (len + 2 != extension_len)
+			goto abort;
+		/*
+		 * The list in practice only has a single element, so we only consider
+		 * the first one.
+		 */
+		if (len == 0 || *extension_data++ != TLSEXT_NAMETYPE_host_name)
+			goto abort;
+		extension_len = len - 1;
+		/* Now we can finally pull out the byte array with the actual hostname. */
+		if (extension_len <= 2)
+			goto abort;
+		len = (*extension_data++) << 8;
+		len |= *extension_data++;
+		if (len == 0 || len + 2 > extension_len || len > TLSEXT_MAXLEN_host_name
+		    || memchr(extension_data, 0, len) != NULL)
+			goto abort;
+		servername = extension_data;
+		servername_len = len;
 	} else {
 		/* without SNI extension, is the default_ctx (need SSL_TLSEXT_ERR_NOACK) */
 		if (!s->strict_sni) {
-			ssl_sock_switchctx_set(ctx->ssl, s->default_ctx);
+			ssl_sock_switchctx_set(ssl, s->default_ctx);
 			return 1;
 		}
 		goto abort;
@@ -2016,21 +2023,19 @@
 
 	/* extract/check clientHello informations */
 	if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_signature_algorithms, &extension_data, &extension_len)) {
-		CBS_init(&extension, extension_data, extension_len);
-
-		if (!CBS_get_u16_length_prefixed(&extension, &sig_algs)
-		    || CBS_len(&sig_algs) == 0
-		    || CBS_len(&extension) != 0) {
+		uint8_t sign;
+		size_t len;
+		if (extension_len < 2)
 			goto abort;
-		}
-		if (CBS_len(&sig_algs) % 2 != 0) {
+		len = (*extension_data++) << 8;
+		len |= *extension_data++;
+		if (len + 2 != extension_len)
 			goto abort;
-		}
-		while (CBS_len(&sig_algs) != 0) {
-			if (!CBS_get_u8(&sig_algs, &hash)
-			    || !CBS_get_u8(&sig_algs, &sign)) {
-				goto abort;
-			}
+		if (len % 2 != 0)
+			goto abort;
+		for (; len > 0; len -= 2) {
+			extension_data++; /* hash */
+			sign = *extension_data++;
 			switch (sign) {
 			case TLSEXT_signature_rsa:
 				has_rsa = 1;
@@ -2049,12 +2054,15 @@
 		has_rsa = 1;
 	}
 	if (has_ecdsa_sig) {  /* in very rare case: has ecdsa sign but not a ECDSA cipher */
-		CBS_init(&cipher_suites, ctx->cipher_suites, ctx->cipher_suites_len);
-
-		while (CBS_len(&cipher_suites) != 0) {
-			if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
-				goto abort;
-			}
+		const SSL_CIPHER *cipher;
+		size_t len;
+		const uint8_t *cipher_suites;
+		len = ctx->cipher_suites_len;
+		cipher_suites = ctx->cipher_suites;
+		if (len % 2 != 0)
+			goto abort;
+		for (; len != 0; len -= 2, cipher_suites += 2) {
+			uint16_t cipher_suite = (cipher_suites[0] << 8) | cipher_suites[1];
 			cipher = SSL_get_cipher_by_value(cipher_suite);
 			if (cipher && SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa) {
 				has_ecdsa = 1;
@@ -2063,8 +2071,7 @@
 		}
 	}
 
-	servername = CBS_data(&host_name);
-	for (i = 0; i < trash.size && i < CBS_len(&host_name); i++) {
+	for (i = 0; i < trash.size && i < servername_len; i++) {
 		trash.str[i] = tolower(servername[i]);
 		if (!wildp && (trash.str[i] == '.'))
 			wildp = &trash.str[i];
@@ -2132,20 +2139,20 @@
 	if (node) {
 		/* switch ctx */
 		struct ssl_bind_conf *conf = container_of(node, struct sni_ctx, name)->conf;
-		ssl_sock_switchctx_set(ctx->ssl, container_of(node, struct sni_ctx, name)->ctx);
-		methodVersions[conf->ssl_methods.min].ssl_set_version(ctx->ssl, SET_MIN);
-		methodVersions[conf->ssl_methods.max].ssl_set_version(ctx->ssl, SET_MAX);
+		ssl_sock_switchctx_set(ssl, container_of(node, struct sni_ctx, name)->ctx);
+		methodVersions[conf->ssl_methods.min].ssl_set_version(ssl, SET_MIN);
+		methodVersions[conf->ssl_methods.max].ssl_set_version(ssl, SET_MAX);
 		return 1;
 	}
 	if (!s->strict_sni) {
 		/* no certificate match, is the default_ctx */
-		ssl_sock_switchctx_set(ctx->ssl, s->default_ctx);
+		ssl_sock_switchctx_set(ssl, s->default_ctx);
 		return 1;
 	}
  abort:
 	/* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
 	conn->err_code = CO_ER_SSL_HANDSHAKE;
-	return -1;
+	return ssl_select_cert_error;
 }
 
 #else /* OPENSSL_IS_BORINGSSL */