xref: /dpdk/app/test/test_cryptodev_security_tls_record.c (revision b43bdaa4412d0dd295f9ae2a36772e42a8221b51)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2023 Marvell.
3  */
4 
5 #include <rte_crypto.h>
6 #include <rte_dtls.h>
7 #include <rte_tls.h>
8 
9 #include "test.h"
10 #include "test_cryptodev_security_tls_record.h"
11 #include "test_cryptodev_security_tls_record_test_vectors.h"
12 #include "test_security_proto.h"
13 
14 int
15 test_tls_record_status_check(struct rte_crypto_op *op)
16 {
17 	int ret = TEST_SUCCESS;
18 
19 	if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS)
20 		ret = TEST_FAILED;
21 
22 	return ret;
23 }
24 
25 int
26 test_tls_record_sec_caps_verify(struct rte_security_tls_record_xform *tls_record_xform,
27 				const struct rte_security_capability *sec_cap, bool silent)
28 {
29 	/* Verify security capabilities */
30 
31 	RTE_SET_USED(tls_record_xform);
32 	RTE_SET_USED(sec_cap);
33 	RTE_SET_USED(silent);
34 
35 	return 0;
36 }
37 
38 void
39 test_tls_record_td_read_from_write(const struct tls_record_test_data *td_out,
40 				   struct tls_record_test_data *td_in)
41 {
42 	memcpy(td_in, td_out, sizeof(*td_in));
43 
44 	/* Populate output text of td_in with input text of td_out */
45 	memcpy(td_in->output_text.data, td_out->input_text.data, td_out->input_text.len);
46 	td_in->output_text.len = td_out->input_text.len;
47 
48 	/* Populate input text of td_in with output text of td_out */
49 	memcpy(td_in->input_text.data, td_out->output_text.data, td_out->output_text.len);
50 	td_in->input_text.len = td_out->output_text.len;
51 
52 	td_in->tls_record_xform.type = RTE_SECURITY_TLS_SESS_TYPE_READ;
53 
54 	if (td_in->aead) {
55 		td_in->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
56 	} else {
57 		td_in->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
58 		td_in->xform.chain.cipher.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
59 	}
60 }
61 
62 void
63 test_tls_record_td_prepare(const struct crypto_param *param1, const struct crypto_param *param2,
64 			   const struct tls_record_test_flags *flags,
65 			   struct tls_record_test_data *td_array,
66 			   int nb_td, unsigned int data_len)
67 {
68 	int i, min_padding, hdr_len, tls_pkt_size, mac_len = 0, exp_nonce_len = 0, roundup_len = 0;
69 	struct tls_record_test_data *td = NULL;
70 
71 	memset(td_array, 0, nb_td * sizeof(*td));
72 
73 	for (i = 0; i < nb_td; i++) {
74 		td = &td_array[i];
75 
76 		/* Prepare fields based on param */
77 
78 		if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
79 			/* Copy template for packet & key fields */
80 			if (flags->tls_version == RTE_SECURITY_VERSION_DTLS_1_2)
81 				memcpy(td, &dtls_test_data_aes_128_gcm, sizeof(*td));
82 			else
83 				memcpy(td, &tls_test_data_aes_128_gcm_v1, sizeof(*td));
84 
85 			td->aead = true;
86 			td->xform.aead.aead.algo = param1->alg.aead;
87 			td->xform.aead.aead.key.length = param1->key_length;
88 			td->xform.aead.aead.digest_length = param1->digest_length;
89 		} else {
90 			/* Copy template for packet & key fields */
91 			if (flags->tls_version == RTE_SECURITY_VERSION_DTLS_1_2)
92 				memcpy(td, &dtls_test_data_aes_128_cbc_sha1_hmac, sizeof(*td));
93 			else
94 				memcpy(td, &tls_test_data_aes_128_cbc_sha1_hmac, sizeof(*td));
95 
96 			td->aead = false;
97 			td->xform.chain.cipher.cipher.algo = param1->alg.cipher;
98 			td->xform.chain.cipher.cipher.key.length = param1->key_length;
99 			td->xform.chain.cipher.cipher.iv.length = param1->iv_length;
100 			td->xform.chain.auth.auth.algo = param2->alg.auth;
101 			td->xform.chain.auth.auth.key.length = param2->key_length;
102 			td->xform.chain.auth.auth.digest_length = param2->digest_length;
103 		}
104 	}
105 
106 	if (flags->data_walkthrough) {
107 		test_sec_proto_pattern_set(td->input_text.data, data_len);
108 		td->input_text.len = data_len;
109 	}
110 
111 	tls_pkt_size = td->input_text.len;
112 
113 	if (!td->aead) {
114 		mac_len = td->xform.chain.auth.auth.digest_length;
115 		switch (td->xform.chain.cipher.cipher.algo) {
116 		case RTE_CRYPTO_CIPHER_3DES_CBC:
117 			roundup_len = 8;
118 			exp_nonce_len = 8;
119 			break;
120 		case RTE_CRYPTO_CIPHER_AES_CBC:
121 			roundup_len = 16;
122 			exp_nonce_len = 16;
123 			break;
124 		default:
125 			roundup_len = 0;
126 			exp_nonce_len = 0;
127 			break;
128 		}
129 	} else {
130 		mac_len = td->xform.aead.aead.digest_length;
131 		roundup_len = 0;
132 		exp_nonce_len = 8;
133 	}
134 
135 	switch (td->tls_record_xform.ver) {
136 	case RTE_SECURITY_VERSION_TLS_1_2:
137 	case RTE_SECURITY_VERSION_TLS_1_3:
138 		hdr_len = sizeof(struct rte_tls_hdr);
139 		if (td->aead)
140 			min_padding = 0;
141 		else
142 			min_padding = 1;
143 		break;
144 	case RTE_SECURITY_VERSION_DTLS_1_2:
145 		hdr_len = sizeof(struct rte_dtls_hdr);
146 		if (td->aead)
147 			min_padding = 0;
148 		else
149 			min_padding = 1;
150 		break;
151 	default:
152 		hdr_len = 0;
153 		min_padding = 0;
154 		break;
155 	}
156 
157 	tls_pkt_size += mac_len;
158 
159 	/* Padding */
160 	tls_pkt_size += min_padding;
161 
162 	if (roundup_len)
163 		tls_pkt_size = RTE_ALIGN_MUL_CEIL(tls_pkt_size, roundup_len);
164 
165 	/* Explicit nonce */
166 	tls_pkt_size += exp_nonce_len;
167 
168 	/* Add TLS header */
169 	tls_pkt_size += hdr_len;
170 
171 	td->output_text.len = tls_pkt_size;
172 
173 	RTE_SET_USED(flags);
174 }
175 
176 void
177 test_tls_record_td_update(struct tls_record_test_data td_inb[],
178 			  const struct tls_record_test_data td_outb[], int nb_td,
179 			  const struct tls_record_test_flags *flags)
180 {
181 	int i;
182 
183 	for (i = 0; i < nb_td; i++) {
184 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
185 		       td_outb[i].input_text.len);
186 		td_inb[i].output_text.len = td_outb->input_text.len;
187 
188 		/* Clear outbound specific flags */
189 		td_inb[i].tls_record_xform.options.iv_gen_disable = 0;
190 	}
191 
192 	RTE_SET_USED(flags);
193 }
194 
195 static int
196 test_tls_record_td_verify(uint8_t *output_text, uint32_t len, const struct tls_record_test_data *td,
197 			 bool silent)
198 {
199 	if (len != td->output_text.len) {
200 		printf("Output length (%d) not matching with expected (%d)\n",
201 			len, td->output_text.len);
202 		return TEST_FAILED;
203 	}
204 
205 	if (memcmp(output_text, td->output_text.data, len)) {
206 		if (silent)
207 			return TEST_FAILED;
208 
209 		printf("[%s : %d] %s\n", __func__, __LINE__, "Output text not as expected\n");
210 
211 		rte_hexdump(stdout, "expected", td->output_text.data, len);
212 		rte_hexdump(stdout, "actual", output_text, len);
213 		return TEST_FAILED;
214 	}
215 
216 	return TEST_SUCCESS;
217 }
218 
219 static int
220 test_tls_record_res_d_prepare(const uint8_t *output_text, uint32_t len,
221 			      const struct tls_record_test_data *td,
222 			      struct tls_record_test_data *res_d)
223 {
224 	memcpy(res_d, td, sizeof(*res_d));
225 
226 	memcpy(&res_d->input_text.data, output_text, len);
227 	res_d->input_text.len = len;
228 
229 	res_d->tls_record_xform.type = RTE_SECURITY_TLS_SESS_TYPE_READ;
230 	if (res_d->aead) {
231 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
232 	} else {
233 		res_d->xform.chain.cipher.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
234 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
235 	}
236 
237 	return TEST_SUCCESS;
238 }
239 
240 static int
241 tls_record_hdr_verify(const struct tls_record_test_data *td, const uint8_t *output_text)
242 {
243 	uint16_t length, hdr_len;
244 	uint8_t content_type;
245 
246 	if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_TLS_1_2) {
247 		const struct rte_tls_hdr *hdr = (const struct rte_tls_hdr *)output_text;
248 		if (rte_be_to_cpu_16(hdr->version) != RTE_TLS_VERSION_1_2) {
249 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
250 			       RTE_TLS_VERSION_1_2, rte_be_to_cpu_16(hdr->version));
251 			return TEST_FAILED;
252 		}
253 		content_type = hdr->type;
254 		length = rte_be_to_cpu_16(hdr->length);
255 		hdr_len = sizeof(struct rte_tls_hdr);
256 	} else if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_TLS_1_3) {
257 		const struct rte_tls_hdr *hdr = (const struct rte_tls_hdr *)output_text;
258 		if (rte_be_to_cpu_16(hdr->version) != RTE_TLS_VERSION_1_3) {
259 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
260 			       RTE_TLS_VERSION_1_3, rte_be_to_cpu_16(hdr->version));
261 			return TEST_FAILED;
262 		}
263 		content_type = hdr->type;
264 		length = rte_be_to_cpu_16(hdr->length);
265 		hdr_len = sizeof(struct rte_tls_hdr);
266 	} else if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_DTLS_1_2) {
267 		const struct rte_dtls_hdr *hdr = (const struct rte_dtls_hdr *)output_text;
268 		if (rte_be_to_cpu_16(hdr->version) != RTE_DTLS_VERSION_1_2) {
269 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
270 			       RTE_DTLS_VERSION_1_2, rte_be_to_cpu_16(hdr->version));
271 			return TEST_FAILED;
272 		}
273 		content_type = hdr->type;
274 		length = rte_be_to_cpu_16(hdr->length);
275 		hdr_len = sizeof(struct rte_dtls_hdr);
276 	} else {
277 		return TEST_FAILED;
278 	}
279 
280 	if (content_type != td->app_type) {
281 		printf("Incorrect content type in packet [expected - %d, received - %d]\n",
282 		       td->app_type, content_type);
283 		return TEST_FAILED;
284 	}
285 
286 	if (length != td->output_text.len - hdr_len) {
287 		printf("Incorrect packet length [expected - %d, received - %d]\n",
288 		       td->output_text.len - hdr_len, length);
289 		return TEST_FAILED;
290 	}
291 
292 	return TEST_SUCCESS;
293 }
294 
295 int
296 test_tls_record_post_process(const struct rte_mbuf *m, const struct tls_record_test_data *td,
297 			     struct tls_record_test_data *res_d, bool silent)
298 {
299 	uint8_t output_text[TEST_SEC_CIPHERTEXT_MAX_LEN];
300 	uint32_t len = rte_pktmbuf_pkt_len(m), data_len;
301 	const struct rte_mbuf *seg;
302 	const uint8_t *output;
303 	int ret;
304 
305 	memset(output_text, 0, TEST_SEC_CIPHERTEXT_MAX_LEN);
306 
307 	/*
308 	 * Actual data in packet might be less in error cases, hence take minimum of pkt_len and sum
309 	 * of data_len. This is done to run through negative test cases.
310 	 */
311 	data_len = 0;
312 	seg = m;
313 	while (seg) {
314 		data_len += seg->data_len;
315 		seg = seg->next;
316 	}
317 
318 	len = RTE_MIN(len, data_len);
319 	TEST_ASSERT(len <= TEST_SEC_CIPHERTEXT_MAX_LEN, "Invalid packet length: %u", len);
320 
321 	/* Copy mbuf payload to continuous buffer */
322 	output = rte_pktmbuf_read(m, 0, len, output_text);
323 	if (output != output_text) {
324 		/* Single segment mbuf, copy manually */
325 		memcpy(output_text, output, len);
326 	}
327 
328 	if (td->tls_record_xform.type == RTE_SECURITY_TLS_SESS_TYPE_WRITE) {
329 		ret = tls_record_hdr_verify(td, output_text);
330 		if (ret != TEST_SUCCESS)
331 			return ret;
332 	}
333 
334 	/*
335 	 * In case of known vector tests & all record read (decrypt) tests, res_d provided would be
336 	 * NULL and output data need to be validated against expected. For record read (decrypt),
337 	 * output_text would be plain payload and for record write (encrypt), output_text would TLS
338 	 * record. Validate by comparing against known vectors.
339 	 *
340 	 * In case of combined mode tests, the output_text from TLS write (encrypt) operation (ie,
341 	 * TLS record) would need to be decrypted using a TLS read operation to obtain the plain
342 	 * text. Copy output_text to result data, 'res_d', so that inbound processing can be done.
343 	 */
344 
345 	if (res_d == NULL)
346 		return test_tls_record_td_verify(output_text, len, td, silent);
347 	else
348 		return test_tls_record_res_d_prepare(output_text, len, td, res_d);
349 }
350