xref: /dpdk/app/test/test_cryptodev_security_tls_record.c (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
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, int nb_td)
66 {
67 	int i, min_padding, hdr_len, tls_pkt_size, mac_len = 0, exp_nonce_len = 0, roundup_len = 0;
68 	struct tls_record_test_data *td = NULL;
69 
70 	memset(td_array, 0, nb_td * sizeof(*td));
71 
72 	for (i = 0; i < nb_td; i++) {
73 		td = &td_array[i];
74 
75 		/* Prepare fields based on param */
76 
77 		if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
78 			/* Copy template for packet & key fields */
79 			memcpy(td, &tls_test_data_aes_128_gcm_v1, sizeof(*td));
80 
81 			td->aead = true;
82 			td->xform.aead.aead.algo = param1->alg.aead;
83 			td->xform.aead.aead.key.length = param1->key_length;
84 			td->xform.aead.aead.digest_length = param1->digest_length;
85 		} else {
86 			/* Copy template for packet & key fields */
87 			memcpy(td, &tls_test_data_aes_128_cbc_sha1_hmac, sizeof(*td));
88 
89 			td->aead = false;
90 			td->xform.chain.cipher.cipher.algo = param1->alg.cipher;
91 			td->xform.chain.cipher.cipher.key.length = param1->key_length;
92 			td->xform.chain.cipher.cipher.iv.length = param1->iv_length;
93 			td->xform.chain.auth.auth.algo = param2->alg.auth;
94 			td->xform.chain.auth.auth.key.length = param2->key_length;
95 			td->xform.chain.auth.auth.digest_length = param2->digest_length;
96 		}
97 	}
98 
99 	tls_pkt_size = td->input_text.len;
100 
101 	if (!td->aead) {
102 		mac_len = td->xform.chain.auth.auth.digest_length;
103 		switch (td->xform.chain.cipher.cipher.algo) {
104 		case RTE_CRYPTO_CIPHER_3DES_CBC:
105 			roundup_len = 8;
106 			exp_nonce_len = 8;
107 			break;
108 		case RTE_CRYPTO_CIPHER_AES_CBC:
109 			roundup_len = 16;
110 			exp_nonce_len = 16;
111 			break;
112 		default:
113 			roundup_len = 0;
114 			exp_nonce_len = 0;
115 			break;
116 		}
117 	} else {
118 		mac_len = td->xform.aead.aead.digest_length;
119 		exp_nonce_len = 8;
120 	}
121 
122 	switch (td->tls_record_xform.ver) {
123 	case RTE_SECURITY_VERSION_TLS_1_2:
124 	case RTE_SECURITY_VERSION_TLS_1_3:
125 		hdr_len = sizeof(struct rte_tls_hdr);
126 		min_padding = 1;
127 		break;
128 	case RTE_SECURITY_VERSION_DTLS_1_2:
129 		hdr_len = sizeof(struct rte_dtls_hdr);
130 		min_padding = 0;
131 		break;
132 	default:
133 		hdr_len = 0;
134 		min_padding = 0;
135 		break;
136 	}
137 
138 	tls_pkt_size += mac_len;
139 
140 	/* Padding */
141 	tls_pkt_size += min_padding;
142 	tls_pkt_size = RTE_ALIGN_MUL_CEIL(tls_pkt_size, roundup_len);
143 
144 	/* Explicit nonce */
145 	tls_pkt_size += exp_nonce_len;
146 
147 	/* Add TLS header */
148 	tls_pkt_size += hdr_len;
149 
150 	td->output_text.len = tls_pkt_size;
151 
152 	RTE_SET_USED(flags);
153 }
154 
155 void
156 test_tls_record_td_update(struct tls_record_test_data td_inb[],
157 			  const struct tls_record_test_data td_outb[], int nb_td,
158 			  const struct tls_record_test_flags *flags)
159 {
160 	int i;
161 
162 	for (i = 0; i < nb_td; i++) {
163 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
164 		       td_outb[i].input_text.len);
165 		td_inb[i].output_text.len = td_outb->input_text.len;
166 
167 		/* Clear outbound specific flags */
168 		td_inb[i].tls_record_xform.options.iv_gen_disable = 0;
169 	}
170 
171 	RTE_SET_USED(flags);
172 }
173 
174 static int
175 test_tls_record_td_verify(uint8_t *output_text, uint32_t len, const struct tls_record_test_data *td,
176 			 bool silent)
177 {
178 	if (len != td->output_text.len) {
179 		printf("Output length (%d) not matching with expected (%d)\n",
180 			len, td->output_text.len);
181 		return TEST_FAILED;
182 	}
183 
184 	if (memcmp(output_text, td->output_text.data, len)) {
185 		if (silent)
186 			return TEST_FAILED;
187 
188 		printf("[%s : %d] %s\n", __func__, __LINE__, "Output text not as expected\n");
189 
190 		rte_hexdump(stdout, "expected", td->output_text.data, len);
191 		rte_hexdump(stdout, "actual", output_text, len);
192 		return TEST_FAILED;
193 	}
194 
195 	return TEST_SUCCESS;
196 }
197 
198 static int
199 test_tls_record_res_d_prepare(const uint8_t *output_text, uint32_t len,
200 			      const struct tls_record_test_data *td,
201 			      struct tls_record_test_data *res_d)
202 {
203 	memcpy(res_d, td, sizeof(*res_d));
204 
205 	memcpy(&res_d->input_text.data, output_text, len);
206 	res_d->input_text.len = len;
207 
208 	res_d->tls_record_xform.type = RTE_SECURITY_TLS_SESS_TYPE_READ;
209 	if (res_d->aead) {
210 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
211 	} else {
212 		res_d->xform.chain.cipher.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
213 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
214 	}
215 
216 	return TEST_SUCCESS;
217 }
218 static int
219 tls_record_hdr_verify(const struct tls_record_test_data *td, const uint8_t *output_text)
220 {
221 	uint16_t length, hdr_len;
222 	uint8_t content_type;
223 
224 	if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_TLS_1_2) {
225 		const struct rte_tls_hdr *hdr = (const struct rte_tls_hdr *)output_text;
226 		if (rte_be_to_cpu_16(hdr->version) != RTE_TLS_VERSION_1_2) {
227 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
228 			       RTE_TLS_VERSION_1_2, rte_be_to_cpu_16(hdr->version));
229 			return TEST_FAILED;
230 		}
231 		content_type = hdr->type;
232 		length = rte_be_to_cpu_16(hdr->length);
233 		hdr_len = sizeof(struct rte_tls_hdr);
234 	} else if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_TLS_1_3) {
235 		const struct rte_tls_hdr *hdr = (const struct rte_tls_hdr *)output_text;
236 		if (rte_be_to_cpu_16(hdr->version) != RTE_TLS_VERSION_1_3) {
237 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
238 			       RTE_TLS_VERSION_1_3, rte_be_to_cpu_16(hdr->version));
239 			return TEST_FAILED;
240 		}
241 		content_type = hdr->type;
242 		length = rte_be_to_cpu_16(hdr->length);
243 		hdr_len = sizeof(struct rte_tls_hdr);
244 	} else if (td->tls_record_xform.ver == RTE_SECURITY_VERSION_DTLS_1_2) {
245 		const struct rte_dtls_hdr *hdr = (const struct rte_dtls_hdr *)output_text;
246 		if (rte_be_to_cpu_16(hdr->version) != RTE_DTLS_VERSION_1_2) {
247 			printf("Incorrect header version [expected - %4x, received - %4x]\n",
248 			       RTE_DTLS_VERSION_1_2, rte_be_to_cpu_16(hdr->version));
249 			return TEST_FAILED;
250 		}
251 		content_type = hdr->type;
252 		length = rte_be_to_cpu_16(hdr->length);
253 		hdr_len = sizeof(struct rte_dtls_hdr);
254 	} else {
255 		return TEST_FAILED;
256 	}
257 
258 	if (content_type != td->app_type) {
259 		printf("Incorrect content type in packet [expected - %d, received - %d]\n",
260 		       td->app_type, content_type);
261 		return TEST_FAILED;
262 	}
263 
264 	if (length != td->output_text.len - hdr_len) {
265 		printf("Incorrect packet length [expected - %d, received - %d]\n",
266 		       td->output_text.len - hdr_len, length);
267 		return TEST_FAILED;
268 	}
269 
270 	return TEST_SUCCESS;
271 }
272 
273 int
274 test_tls_record_post_process(const struct rte_mbuf *m, const struct tls_record_test_data *td,
275 			     struct tls_record_test_data *res_d, bool silent)
276 {
277 	uint32_t len = rte_pktmbuf_pkt_len(m), data_len;
278 	uint8_t output_text[TLS_RECORD_MAX_LEN];
279 	const struct rte_mbuf *seg;
280 	const uint8_t *output;
281 	int ret;
282 
283 	memset(output_text, 0, TLS_RECORD_MAX_LEN);
284 
285 	/*
286 	 * Actual data in packet might be less in error cases, hence take minimum of pkt_len and sum
287 	 * of data_len. This is done to run through negative test cases.
288 	 */
289 	data_len = 0;
290 	seg = m;
291 	while (seg) {
292 		data_len += seg->data_len;
293 		seg = seg->next;
294 	}
295 
296 	len = RTE_MIN(len, data_len);
297 	TEST_ASSERT(len <= TLS_RECORD_MAX_LEN, "Invalid packet length: %u", len);
298 
299 	/* Copy mbuf payload to continuous buffer */
300 	output = rte_pktmbuf_read(m, 0, len, output_text);
301 	if (output != output_text) {
302 		/* Single segment mbuf, copy manually */
303 		memcpy(output_text, output, len);
304 	}
305 
306 	if (td->tls_record_xform.type == RTE_SECURITY_TLS_SESS_TYPE_WRITE) {
307 		ret = tls_record_hdr_verify(td, output_text);
308 		if (ret != TEST_SUCCESS)
309 			return ret;
310 	}
311 
312 	/*
313 	 * In case of known vector tests & all record read (decrypt) tests, res_d provided would be
314 	 * NULL and output data need to be validated against expected. For record read (decrypt),
315 	 * output_text would be plain payload and for record write (encrypt), output_text would TLS
316 	 * record. Validate by comparing against known vectors.
317 	 *
318 	 * In case of combined mode tests, the output_text from TLS write (encrypt) operation (ie,
319 	 * TLS record) would need to be decrypted using a TLS read operation to obtain the plain
320 	 * text. Copy output_text to result data, 'res_d', so that inbound processing can be done.
321 	 */
322 
323 	if (res_d == NULL)
324 		return test_tls_record_td_verify(output_text, len, td, silent);
325 	else
326 		return test_tls_record_res_d_prepare(output_text, len, td, res_d);
327 }
328