xref: /third_party/ltp/lib/tst_af_alg.c (revision f08c3bdf)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2019 Google LLC
4 * Copyright (c) Linux Test Project, 2019-2021
5 */
6
7#include <errno.h>
8#include <stdlib.h>
9
10#define TST_NO_DEFAULT_MAIN
11#include "tst_test.h"
12#include "tst_af_alg.h"
13#include "lapi/socket.h"
14
15int tst_alg_create(void)
16{
17	const long ret = socket(AF_ALG, SOCK_SEQPACKET, 0);
18
19	if (ret >= 0)
20		return ret;
21	if (errno == EAFNOSUPPORT)
22		tst_brk(TCONF, "kernel doesn't support AF_ALG");
23	tst_brk(TBROK | TERRNO, "unexpected error creating AF_ALG socket");
24	return -1;
25}
26
27void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr)
28{
29	const long ret = bind(algfd, (const struct sockaddr *)addr,
30			      sizeof(*addr));
31
32	if (ret == 0)
33		return;
34
35	if (errno == ELIBBAD && tst_fips_enabled()) {
36		tst_brk(TCONF,
37			"FIPS enabled => %s algorithm '%s' disabled",
38			addr->salg_type, addr->salg_name);
39	}
40
41	if (errno == ENOENT) {
42		tst_brk(TCONF, "kernel doesn't support %s algorithm '%s'",
43			addr->salg_type, addr->salg_name);
44	}
45
46	tst_brk(TBROK | TERRNO,
47		"unexpected error binding AF_ALG socket to %s algorithm '%s'",
48		addr->salg_type, addr->salg_name);
49}
50
51static void init_sockaddr_alg(struct sockaddr_alg *addr,
52			      const char *algtype, const char *algname)
53{
54	memset(addr, 0, sizeof(*addr));
55
56	addr->salg_family = AF_ALG;
57
58	strncpy((char *)addr->salg_type, algtype, sizeof(addr->salg_type));
59	if (addr->salg_type[sizeof(addr->salg_type) - 1] != '\0')
60		tst_brk(TBROK, "algorithm type too long: '%s'", algtype);
61
62	strncpy((char *)addr->salg_name, algname, sizeof(addr->salg_name));
63	if (addr->salg_name[sizeof(addr->salg_name) - 1] != '\0')
64		tst_brk(TBROK, "algorithm name too long: '%s'", algname);
65}
66
67void tst_alg_bind(int algfd, const char *algtype, const char *algname)
68{
69	struct sockaddr_alg addr;
70
71	init_sockaddr_alg(&addr, algtype, algname);
72
73	tst_alg_bind_addr(algfd, &addr);
74}
75
76int tst_try_alg(const char *algtype, const char *algname)
77{
78	long ret;
79	int retval = 0;
80	int algfd;
81	struct sockaddr_alg addr;
82
83	algfd = tst_alg_create();
84
85	init_sockaddr_alg(&addr, algtype, algname);
86
87	ret = bind(algfd, (const struct sockaddr *)&addr, sizeof(addr));
88
89	if (ret != 0)
90		retval = errno;
91
92	close(algfd);
93	return retval;
94}
95
96bool tst_have_alg(const char *algtype, const char *algname)
97{
98	int ret;
99
100	ret = tst_try_alg(algtype, algname);
101
102	switch (ret) {
103	case 0:
104		return true;
105	case ENOENT:
106		tst_res(TCONF, "kernel doesn't have %s algorithm '%s'",
107			algtype, algname);
108		return false;
109	case ELIBBAD:
110		if (tst_fips_enabled()) {
111			tst_res(TCONF,
112				"FIPS enabled => %s algorithm '%s' disabled",
113				algtype, algname);
114			return false;
115		}
116	/* fallthrough */
117	default:
118		errno = ret;
119		tst_brk(TBROK | TERRNO,
120			"unexpected error binding AF_ALG socket to %s algorithm '%s'",
121			algtype, algname);
122		return false;
123	}
124}
125
126void tst_require_alg(const char *algtype, const char *algname)
127{
128	int algfd = tst_alg_create();
129
130	tst_alg_bind(algfd, algtype, algname);
131
132	close(algfd);
133}
134
135void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen)
136{
137	long ret;
138	uint8_t *keybuf = NULL;
139	unsigned int i;
140
141	if (key == NULL) {
142		/* generate a random key */
143		keybuf = SAFE_MALLOC(keylen);
144		for (i = 0; i < keylen; i++)
145			keybuf[i] = rand();
146		key = keybuf;
147	}
148	ret = setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen);
149	if (ret != 0) {
150		tst_brk(TBROK | TERRNO,
151			"unexpected error setting key (len=%u)", keylen);
152	}
153	free(keybuf);
154}
155
156int tst_alg_accept(int algfd)
157{
158	const long ret = accept(algfd, NULL, NULL);
159
160	if (ret < 0) {
161		tst_brk(TBROK | TERRNO,
162			"unexpected error accept()ing AF_ALG request socket");
163	}
164	return ret;
165}
166
167int tst_alg_setup(const char *algtype, const char *algname,
168		  const uint8_t *key, unsigned int keylen)
169{
170	int algfd = tst_alg_create();
171
172	tst_alg_bind(algfd, algtype, algname);
173
174	if (keylen != 0)
175		tst_alg_setkey(algfd, key, keylen);
176
177	return algfd;
178}
179
180int tst_alg_setup_reqfd(const char *algtype, const char *algname,
181			const uint8_t *key, unsigned int keylen)
182{
183	int algfd = tst_alg_setup(algtype, algname, key, keylen);
184	int reqfd = tst_alg_accept(algfd);
185
186	close(algfd);
187	return reqfd;
188}
189
190void tst_alg_sendmsg(int reqfd, const void *data, size_t datalen,
191		     const struct tst_alg_sendmsg_params *params)
192{
193	struct iovec iov = {
194		.iov_base = (void *)data,
195		.iov_len = datalen,
196	};
197	struct msghdr msg = {
198		.msg_iov = &iov,
199		.msg_iovlen = 1,
200		.msg_flags = params->msg_flags,
201	};
202	size_t controllen;
203	uint8_t *control;
204	struct cmsghdr *cmsg;
205	struct af_alg_iv *alg_iv;
206
207	if (params->encrypt && params->decrypt)
208		tst_brk(TBROK, "Both encrypt and decrypt are specified");
209
210	controllen = 0;
211	if (params->encrypt || params->decrypt)
212		controllen += CMSG_SPACE(sizeof(uint32_t));
213	if (params->ivlen)
214		controllen += CMSG_SPACE(sizeof(struct af_alg_iv) +
215					 params->ivlen);
216	if (params->assoclen)
217		controllen += CMSG_SPACE(sizeof(uint32_t));
218
219	control = SAFE_MALLOC(controllen);
220	memset(control, 0, controllen);
221	msg.msg_control = control;
222	msg.msg_controllen = controllen;
223	cmsg = CMSG_FIRSTHDR(&msg);
224
225	if (params->encrypt || params->decrypt) {
226		cmsg->cmsg_level = SOL_ALG;
227		cmsg->cmsg_type = ALG_SET_OP;
228		cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
229		*(uint32_t *)CMSG_DATA(cmsg) =
230			params->encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
231		cmsg = CMSG_NXTHDR(&msg, cmsg);
232	}
233	if (params->ivlen) {
234		cmsg->cmsg_level = SOL_ALG;
235		cmsg->cmsg_type = ALG_SET_IV;
236		cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) +
237					  params->ivlen);
238		alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg);
239		alg_iv->ivlen = params->ivlen;
240		memcpy(alg_iv->iv, params->iv, params->ivlen);
241		cmsg = CMSG_NXTHDR(&msg, cmsg);
242	}
243	if (params->assoclen) {
244		cmsg->cmsg_level = SOL_ALG;
245		cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN;
246		cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
247		*(uint32_t *)CMSG_DATA(cmsg) = params->assoclen;
248		cmsg = CMSG_NXTHDR(&msg, cmsg);
249	}
250
251	SAFE_SENDMSG(datalen, reqfd, &msg, 0);
252}
253