Commit dd824d4e authored by Krzysztof Karas's avatar Krzysztof Karas Committed by Konrad Sztyber
Browse files

sock: add TLS cipher suite field



Add a field to structure spdk_sock_impl_opts that will be set
with selected cipher suite for connecting side or cipher suite
list for listening side. Then set cipher suite with
SSL_CTX_set_ciphersuites().

Cipher TLS_AES_256_GCM_SHA384 requires us to use newer
version of OpenSSL callbacks, which are incompatibilie
with TLS 1.2 and below:
 - instead of setting them with SSL_set_psk_client_callback()
we'll need to use SSL_set_psk_use_session_callback for
client callbacks. As a part of this patch introduce
required client side changes.
 - remove support for TLS 1.2 and below, as required
cipher suites are incompatibile with earlier TLS versions.

Change-Id: Id4e274ad2cc265f79d8dd02e65692678981926f2
Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16672


Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent eaf70c87
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -245,6 +245,7 @@ hello_sock_connect(struct hello_context_t *ctx)
	impl_opts.enable_ktls = ctx->ktls;
	impl_opts.tls_version = ctx->tls_version;
	impl_opts.psk_identity = ctx->psk_identity;
	impl_opts.tls_cipher_suites = "TLS_AES_128_GCM_SHA256";

	opts.opts_size = sizeof(opts);
	spdk_sock_get_default_opts(&opts);
+10 −0
Original line number Diff line number Diff line
@@ -173,6 +173,16 @@ struct spdk_sock_impl_opts {
	 * Context to be passed to get_key() callback.
	 */
	void *get_key_ctx;

	/**
	 * Cipher suite. Used by ssl socket module.
	 * For connecting side, it must contain a single cipher:
	 * example: "TLS_AES_256_GCM_SHA384"
	 *
	 * For listening side, it may be a colon separated list of ciphers:
	 * example: "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
	 */
	const char *tls_cipher_suites;
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -1946,6 +1946,7 @@ nvme_tcp_qpair_connect_sock(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpai
		impl_opts.psk_identity = tcp_ctrlr->psk_identity;
		impl_opts.psk_key = tcp_ctrlr->psk;
		impl_opts.psk_key_size = tcp_ctrlr->psk_size;
		impl_opts.tls_cipher_suites = "TLS_AES_128_GCM_SHA256";
	}
	opts.opts_size = sizeof(opts);
	spdk_sock_get_default_opts(&opts);
+73 −30
Original line number Diff line number Diff line
@@ -83,7 +83,8 @@ static struct spdk_sock_impl_opts g_spdk_posix_sock_impl_opts = {
	.psk_key_size = 0,
	.psk_identity = NULL,
	.get_key = NULL,
	.get_key_ctx = NULL
	.get_key_ctx = NULL,
	.tls_cipher_suites = NULL
};

static struct spdk_sock_map g_map = {
@@ -128,6 +129,7 @@ posix_sock_copy_impl_opts(struct spdk_sock_impl_opts *dest, const struct spdk_so
	SET_FIELD(psk_identity);
	SET_FIELD(get_key);
	SET_FIELD(get_key_ctx);
	SET_FIELD(tls_cipher_suites);

#undef SET_FIELD
#undef FIELD_OK
@@ -563,41 +565,80 @@ posix_sock_tls_psk_server_cb(SSL *ssl,
	}
}

static unsigned int
posix_sock_tls_psk_client_cb(SSL *ssl, const char *hint,
			     char *identity,
			     unsigned int max_identity_len,
			     unsigned char *psk,
			     unsigned int max_psk_len)
static int
posix_sock_psk_use_session_client_cb(SSL *ssl, const EVP_MD *md, const unsigned char **identity,
				     size_t *identity_len, SSL_SESSION **sess)
{
	long key_len;
	struct spdk_sock_impl_opts *impl_opts;
	struct spdk_sock_impl_opts *impl_opts = SSL_get_app_data(ssl);
	int rc, i;
	STACK_OF(SSL_CIPHER) *ciphers;
	const SSL_CIPHER *cipher;
	const char *cipher_name;
	long keylen;
	bool found = false;

	impl_opts = SSL_get_app_data(ssl);
	if (impl_opts->psk_key == NULL) {
		SPDK_ERRLOG("PSK is not set\n");
		return 0;
	}
	if (impl_opts->psk_key_size > SSL_MAX_MASTER_KEY_LENGTH) {
		SPDK_ERRLOG("PSK too long\n");
		return 0;
	}
	keylen = impl_opts->psk_key_size;

	if (hint) {
		SPDK_DEBUGLOG(sock_posix,  "Received PSK identity hint '%s'\n", hint);
	if (impl_opts->tls_cipher_suites == NULL) {
		SPDK_ERRLOG("Cipher suite not set\n");
		return 0;
	}
	*sess = SSL_SESSION_new();
	if (*sess == NULL) {
		SPDK_ERRLOG("Unable to allocate new SSL session\n");
		return 0;
	}

	if (impl_opts->psk_key == NULL) {
		SPDK_ERRLOG("PSK is not set\n");
	ciphers = SSL_get_ciphers(ssl);
	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
		cipher = sk_SSL_CIPHER_value(ciphers, i);
		cipher_name = SSL_CIPHER_get_name(cipher);

		if (strcmp(impl_opts->tls_cipher_suites, cipher_name) == 0) {
			rc = SSL_SESSION_set_cipher(*sess, cipher);
			if (rc != 1) {
				SPDK_ERRLOG("Unable to set cipher: %s\n", cipher_name);
				goto err;
			}
			found = true;
			break;
		}
	}
	if (found == false) {
		SPDK_ERRLOG("No suitable cipher found\n");
		goto err;
	}

	SPDK_DEBUGLOG(sock_posix, "Cipher selected: %s\n", cipher_name);

	rc = SSL_SESSION_set_protocol_version(*sess, TLS1_3_VERSION);
	if (rc != 1) {
		SPDK_ERRLOG("Unable to set TLS version: %d\n", TLS1_3_VERSION);
		goto err;
	}
	key_len = impl_opts->psk_key_size;
	if ((strlen(impl_opts->psk_identity) + 1 > max_identity_len)
	    || (key_len > max_psk_len)) {
		SPDK_ERRLOG("PSK ID or Key buffer is not sufficient\n");

	rc = SSL_SESSION_set1_master_key(*sess, impl_opts->psk_key, keylen);
	if (rc != 1) {
		SPDK_ERRLOG("Unable to set PSK for session\n");
		goto err;
	}
	spdk_strcpy_pad(identity, impl_opts->psk_identity, strlen(impl_opts->psk_identity), 0);
	SPDK_DEBUGLOG(sock_posix, "Sending PSK identity '%s'\n", identity);

	memcpy(psk, impl_opts->psk_key, key_len);
	SPDK_DEBUGLOG(sock_posix, "Provided out-of-band (OOB) PSK for TLS1.3 client\n");
	*identity_len = strlen(impl_opts->psk_identity);
	*identity = impl_opts->psk_identity;

	return key_len;
	return 1;

err:
	SSL_SESSION_free(*sess);
	*sess = NULL;
	return 0;
}

@@ -627,12 +668,6 @@ posix_sock_create_ssl_context(const SSL_METHOD *method, struct spdk_sock_opts *o
	case 0:
		/* auto-negotioation */
		break;
	case SPDK_TLS_VERSION_1_1:
		tls_version = TLS1_1_VERSION;
		break;
	case SPDK_TLS_VERSION_1_2:
		tls_version = TLS1_2_VERSION;
		break;
	case SPDK_TLS_VERSION_1_3:
		tls_version = TLS1_3_VERSION;
		break;
@@ -667,6 +702,14 @@ posix_sock_create_ssl_context(const SSL_METHOD *method, struct spdk_sock_opts *o
		}
	}

	/* SSL_CTX_set_ciphersuites() return 1 if the requested
	 * cipher suite list was configured, and 0 otherwise. */
	if (impl_opts->tls_cipher_suites != NULL &&
	    SSL_CTX_set_ciphersuites(ctx, impl_opts->tls_cipher_suites) != 1) {
		SPDK_ERRLOG("Unable to set TLS cipher suites for SSL'\n");
		goto err;
	}

	return ctx;

err:
@@ -688,7 +731,7 @@ ssl_sock_connect_loop(SSL_CTX *ctx, int fd, struct spdk_sock_impl_opts *impl_opt
	}
	SSL_set_fd(ssl, fd);
	SSL_set_app_data(ssl, impl_opts);
	SSL_set_psk_client_callback(ssl, posix_sock_tls_psk_client_cb);
	SSL_set_psk_use_session_callback(ssl, posix_sock_psk_use_session_client_cb);
	SPDK_DEBUGLOG(sock_posix, "SSL object creation finished: %p\n", ssl);
	SPDK_DEBUGLOG(sock_posix, "%s = SSL_state_string_long(%p)\n", SSL_state_string_long(ssl), ssl);
	while ((rc = SSL_connect(ssl)) != 1) {
+0 −17
Original line number Diff line number Diff line
@@ -141,13 +141,6 @@ if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client using TLS 1.2
message="**MESSAGE:This is a test message from the hello_sock client with ssl using TLS 1.2**"
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 12 -m 0x2)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client using incorrect TLS 7
message="**MESSAGE:This is a test message from the hello_sock client with ssl using incorrect TLS 7**"
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 7 -m 0x2 && exit 1
@@ -178,16 +171,6 @@ if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using openssl client using TLS 1.2
message="**MESSAGE:This is a test message from the openssl client using TLS 1.2**"
response=$( (
	echo -ne $message
	sleep 2
) | $OPENSSL_APP s_client -debug -state -tlsextdebug -tls1_2 -psk_identity psk.spdk.io -psk "1234567890ABCDEF" -connect $TARGET_IP:$ISCSI_PORT)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client with unmatching PSK KEY, expect a failure
message="**MESSAGE:This is a test message from the hello_sock client with unmatching psk_key**"
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -E 4321DEADBEEF1234 -m 0x2 && exit 1
Loading