1/*	$OpenBSD: x509_algor.c,v 1.7 2024/02/29 20:03:47 tb Exp $ */
2/*
3 * Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <err.h>
19#include <stdio.h>
20
21#include <openssl/asn1.h>
22#include <openssl/evp.h>
23#include <openssl/objects.h>
24#include <openssl/x509.h>
25
26int X509_ALGOR_set_evp_md(X509_ALGOR *alg, const EVP_MD *md);
27
28static int
29x509_algor_new_test(void)
30{
31	X509_ALGOR *alg = NULL;
32	const ASN1_OBJECT *aobj;
33	int failed = 1;
34
35	if ((alg = X509_ALGOR_new()) == NULL)
36		errx(1, "%s: X509_ALGOR_new", __func__);
37
38	if ((aobj = OBJ_nid2obj(NID_undef)) == NULL)
39		errx(1, "%s: OBJ_nid2obj", __func__);
40
41	if (alg->algorithm != aobj) {
42		fprintf(stderr, "FAIL: %s: want NID_undef OID\n", __func__);
43		goto failure;
44	}
45	if (alg->parameter != NULL) {
46		fprintf(stderr, "FAIL: %s: want NULL parameters\n", __func__);
47		goto failure;
48	}
49
50	failed = 0;
51
52 failure:
53	X509_ALGOR_free(alg);
54
55	return failed;
56}
57
58static int
59x509_algor_set0_test(void)
60{
61	X509_ALGOR *alg = NULL;
62	ASN1_TYPE *old_parameter;
63	ASN1_OBJECT *oid;
64	ASN1_INTEGER *aint = NULL, *aint_ref;
65	int ret;
66	int failed = 1;
67
68	if ((ret = X509_ALGOR_set0(NULL, NULL, 0, NULL)) != 0) {
69		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(NULL, NULL, 0, NULL)"
70		    ", want: %d, got %d\n", __func__, 0, ret);
71		goto failure;
72	}
73
74	if ((alg = X509_ALGOR_new()) == NULL)
75		errx(1, "%s: X509_ALGOR_new", __func__);
76
77	/* This sets algorithm to NULL and allocates new parameters. */
78	if ((ret = X509_ALGOR_set0(alg, NULL, 0, NULL)) != 1) {
79		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, NULL)"
80		    ", want: %d, got %d\n", __func__, 1, ret);
81		goto failure;
82	}
83	if (alg->algorithm != NULL) {
84		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
85		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
86		goto failure;
87	}
88	if ((old_parameter = alg->parameter) == NULL) {
89		fprintf(stderr, "FAIL: %s: want non-NULL parameter after "
90		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
91		goto failure;
92	}
93	if (alg->parameter->type != V_ASN1_UNDEF) {
94		fprintf(stderr, "FAIL: %s: want %d parameter type after "
95		    "X509_ALGOR_set0(alg, NULL, 0, NULL), got %d\n",
96		    __func__, V_ASN1_UNDEF, alg->parameter->type);
97		goto failure;
98	}
99	if (alg->parameter->value.ptr != NULL) {
100		fprintf(stderr, "FAIL: %s: want NULL parameter value after "
101		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
102		goto failure;
103	}
104
105	/* This should leave algorithm at NULL and parameters untouched. */
106	if ((ret = X509_ALGOR_set0(alg, NULL, 0, NULL)) != 1) {
107		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, NULL)"
108		    ", want: %d, got %d\n", __func__, 1, ret);
109		goto failure;
110	}
111	if (alg->algorithm != NULL) {
112		fprintf(stderr, "FAIL: %s: want NULL algorithm after second"
113		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
114		goto failure;
115	}
116	if (alg->parameter != old_parameter) {
117		fprintf(stderr, "FAIL: %s: parameter changed after second"
118		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
119		goto failure;
120	}
121
122	/* This ignores pval (old_parameter). */
123	if ((ret = X509_ALGOR_set0(alg, NULL, 0, old_parameter)) != 1) {
124		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, ptr)"
125		    ", want: %d, got %d\n", __func__, 1, ret);
126		goto failure;
127	}
128	if (alg->algorithm != NULL) {
129		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
130		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
131		goto failure;
132	}
133	if (alg->parameter == NULL) {
134		fprintf(stderr, "FAIL: %s: want non-NULL parameter after "
135		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
136		goto failure;
137	}
138	if (alg->parameter->type != V_ASN1_UNDEF) {
139		fprintf(stderr, "FAIL: %s: want %d parameter type after "
140		    "X509_ALGOR_set0(alg, NULL, 0, ptr), got %d\n",
141		    __func__, V_ASN1_UNDEF, alg->parameter->type);
142		goto failure;
143	}
144	if (alg->parameter->value.ptr != NULL) {
145		fprintf(stderr, "FAIL: %s: want NULL parameter value after "
146		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
147		goto failure;
148	}
149
150	old_parameter = NULL;
151
152	/* This frees parameters and ignores pval. */
153	if ((ret = X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)) != 1) {
154		fprintf(stderr, "FAIL: %s: "
155		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)"
156		    ", want: %d, got %d\n", __func__, 1, ret);
157		goto failure;
158	}
159	if (alg->algorithm != NULL) {
160		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
161		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)\n", __func__);
162		goto failure;
163	}
164	if (alg->parameter != NULL) {
165		fprintf(stderr, "FAIL: %s: want NULL parameter after "
166		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)\n", __func__);
167		goto failure;
168	}
169
170	/* This frees parameters and ignores "foo". */
171	if ((ret = X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, "foo")) != 1) {
172		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, \"foo\")"
173		    ", want: %d, got %d\n", __func__, 1, ret);
174		goto failure;
175	}
176	if (alg->algorithm != NULL) {
177		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
178		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, \"foo\")\n", __func__);
179		goto failure;
180	}
181	if (alg->parameter != NULL) {
182		fprintf(stderr, "FAIL: %s: want NULL parameter after "
183		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, \"foo\")\n", __func__);
184		goto failure;
185	}
186
187	if ((oid = OBJ_nid2obj(NID_sha512_224)) == NULL) {
188		fprintf(stderr, "FAIL: %s: OBJ_nid2obj(NID_sha512_224)\n", __func__);
189		goto failure;
190	}
191	if ((aint = aint_ref = ASN1_INTEGER_new()) == NULL)
192		errx(1, "%s: ASN1_INTEGER_new()", __func__);
193	if (!ASN1_INTEGER_set_uint64(aint, 57))
194		errx(1, "%s: ASN1_INTEGER_set_uint64()", __func__);
195
196	if ((ret = X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)) != 1) {
197		fprintf(stderr, "Fail: %s: "
198		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
199		    ", want: %d, got %d\n", __func__, 1, ret);
200		goto failure;
201	}
202	aint = NULL;
203	if (alg->algorithm != oid) {
204		fprintf(stderr, "FAIL: %s: unexpected oid on alg after "
205		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
206		    ", want: %d, got %d\n", __func__, 1, ret);
207		goto failure;
208	}
209	if (alg->parameter == NULL) {
210		fprintf(stderr, "FAIL: %s: expected non-NULL parameter after "
211		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
212		    ", want: %d, got %d\n", __func__, 1, ret);
213		goto failure;
214	}
215	if (alg->parameter->type != V_ASN1_INTEGER) {
216		fprintf(stderr, "FAIL: %s: want %d parameter type after "
217		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint), got %d\n",
218		    __func__, V_ASN1_INTEGER, alg->parameter->type);
219		goto failure;
220	}
221	if (alg->parameter->value.asn1_string != aint_ref) {
222		fprintf(stderr, "FAIL: %s: unexpected parameter value after "
223		    "X509_ALGOR_set0(alg, oid, V_ASN1_NULL, aint)\n", __func__);
224		goto failure;
225	}
226
227	failed = 0;
228
229 failure:
230	X509_ALGOR_free(alg);
231	ASN1_INTEGER_free(aint);
232
233	return failed;
234}
235
236static int
237x509_algor_get0_test(void)
238{
239	X509_ALGOR *alg;
240	const ASN1_OBJECT *aobj = NULL;
241	int ptype = 0;
242	const void *pval = NULL;
243	ASN1_OBJECT *oid;
244	ASN1_INTEGER *aint = NULL, *aint_ref = NULL;
245	int ret;
246	int failed = 1;
247
248	if ((alg = X509_ALGOR_new()) == NULL)
249		errx(1, "%s: X509_ALGOR_new", __func__);
250
251	X509_ALGOR_get0(&aobj, NULL, NULL, alg);
252	if (aobj == NULL) {
253		fprintf(stderr, "FAIL: %s: expected non-NULL aobj\n", __func__);
254		goto failure;
255	}
256	X509_ALGOR_get0(NULL, &ptype, NULL, alg);
257	if (ptype != V_ASN1_UNDEF) {
258		fprintf(stderr, "FAIL: %s: want %d, got %d\n",
259		    __func__, V_ASN1_UNDEF, ptype);
260		goto failure;
261	}
262
263	if ((oid = OBJ_nid2obj(NID_ED25519)) == NULL)
264		errx(1, "%s: OBJ_nid2obj(NID_ED25519)", __func__);
265	if ((aint = aint_ref = ASN1_INTEGER_new()) == NULL)
266		errx(1, "%s: ASN1_INTEGER_new()", __func__);
267	if (!ASN1_INTEGER_set_uint64(aint, 99))
268		errx(1, "%s: ASN1_INTEGER_set_uint64()", __func__);
269
270	if ((ret = X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)) != 1) {
271		fprintf(stderr, "Fail: %s: "
272		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
273		    ", want: %d, got %d\n", __func__, 1, ret);
274		goto failure;
275	}
276	aint = NULL;
277
278	X509_ALGOR_get0(&aobj, NULL, NULL, alg);
279	if (aobj != oid) {
280		fprintf(stderr, "FAIL: %s: expected Ed25519 oid\n", __func__);
281		goto failure;
282	}
283	X509_ALGOR_get0(NULL, &ptype, NULL, alg);
284	if (ptype != V_ASN1_INTEGER) {
285		fprintf(stderr, "FAIL: %s: expected %d, got %d\n",
286		    __func__, V_ASN1_INTEGER, ptype);
287		goto failure;
288	}
289	pval = oid;
290	X509_ALGOR_get0(NULL, NULL, &pval, alg);
291	if (pval != NULL) {
292		fprintf(stderr, "FAIL: %s: got non-NULL pval\n", __func__);
293		goto failure;
294	}
295
296	aobj = NULL;
297	ptype = V_ASN1_UNDEF;
298	pval = oid;
299	X509_ALGOR_get0(&aobj, &ptype, &pval, alg);
300	if (aobj != oid) {
301		fprintf(stderr, "FAIL: %s: expected Ed25519 oid 2\n", __func__);
302		goto failure;
303	}
304	if (ptype != V_ASN1_INTEGER) {
305		fprintf(stderr, "FAIL: %s: expected %d, got %d 2\n",
306		    __func__, V_ASN1_INTEGER, ptype);
307		goto failure;
308	}
309	if (pval != aint_ref) {
310		fprintf(stderr, "FAIL: %s: expected ASN.1 integer\n", __func__);
311		goto failure;
312	}
313
314	failed = 0;
315
316 failure:
317	X509_ALGOR_free(alg);
318	ASN1_INTEGER_free(aint);
319
320	return failed;
321}
322
323static int
324x509_algor_set_evp_md_test(void)
325{
326	X509_ALGOR *alg = NULL;
327	const ASN1_OBJECT *aobj;
328	int ptype = 0, nid = 0;
329	int failed = 1;
330
331	if ((alg = X509_ALGOR_new()) == NULL)
332		errx(1, "%s: X509_ALGOR_new", __func__);
333
334	if (!X509_ALGOR_set_evp_md(alg, EVP_sm3())) {
335		fprintf(stderr, "%s: X509_ALGOR_set_evp_md to sm3 failed\n",
336		    __func__);
337		goto failure;
338	}
339	X509_ALGOR_get0(&aobj, &ptype, NULL, alg);
340	if ((nid = OBJ_obj2nid(aobj)) != NID_sm3) {
341		fprintf(stderr, "%s: sm3 want %d, got %d\n", __func__,
342		    NID_sm3, nid);
343		goto failure;
344	}
345	if (ptype != V_ASN1_UNDEF) {
346		fprintf(stderr, "%s: sm3 want %d, got %d\n", __func__,
347		    V_ASN1_UNDEF, ptype);
348		goto failure;
349	}
350
351	/* Preallocate as recommended in the manual. */
352	if (!X509_ALGOR_set0(alg, NULL, 0, NULL))
353		errx(1, "%s: X509_ALGOR_set0", __func__);
354
355	if (!X509_ALGOR_set_evp_md(alg, EVP_md5())) {
356		fprintf(stderr, "%s: X509_ALGOR_set_evp_md to md5 failed\n",
357		    __func__);
358		goto failure;
359	}
360	X509_ALGOR_get0(&aobj, &ptype, NULL, alg);
361	if ((nid = OBJ_obj2nid(aobj)) != NID_md5) {
362		fprintf(stderr, "%s: md5 want %d, got %d\n", __func__,
363		    NID_sm3, nid);
364		goto failure;
365	}
366	if (ptype != V_ASN1_NULL) {
367		fprintf(stderr, "%s: md5 want %d, got %d\n", __func__,
368		    V_ASN1_NULL, ptype);
369		goto failure;
370	}
371
372	failed = 0;
373
374 failure:
375	X509_ALGOR_free(alg);
376
377	return failed;
378}
379
380int
381main(void)
382{
383	int failed = 0;
384
385	failed |= x509_algor_new_test();
386	failed |= x509_algor_set0_test();
387	failed |= x509_algor_get0_test();
388	failed |= x509_algor_set_evp_md_test();
389
390	return failed;
391}
392