1*00ee6dc4Stb /*	$OpenBSD: x509_algor.c,v 1.7 2024/02/29 20:03:47 tb Exp $ */
2414d371cStb /*
3414d371cStb  * Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
4414d371cStb  *
5414d371cStb  * Permission to use, copy, modify, and distribute this software for any
6414d371cStb  * purpose with or without fee is hereby granted, provided that the above
7414d371cStb  * copyright notice and this permission notice appear in all copies.
8414d371cStb  *
9414d371cStb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10414d371cStb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11414d371cStb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12414d371cStb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13414d371cStb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14414d371cStb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15414d371cStb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16414d371cStb  */
17414d371cStb 
18414d371cStb #include <err.h>
19414d371cStb #include <stdio.h>
20414d371cStb 
2126cc26e1Stb #include <openssl/asn1.h>
2226cc26e1Stb #include <openssl/evp.h>
2326cc26e1Stb #include <openssl/objects.h>
24414d371cStb #include <openssl/x509.h>
25414d371cStb 
26*00ee6dc4Stb int X509_ALGOR_set_evp_md(X509_ALGOR *alg, const EVP_MD *md);
27379777c0Stb 
28414d371cStb static int
x509_algor_new_test(void)29414d371cStb x509_algor_new_test(void)
30414d371cStb {
31414d371cStb 	X509_ALGOR *alg = NULL;
32414d371cStb 	const ASN1_OBJECT *aobj;
33414d371cStb 	int failed = 1;
34414d371cStb 
35414d371cStb 	if ((alg = X509_ALGOR_new()) == NULL)
36414d371cStb 		errx(1, "%s: X509_ALGOR_new", __func__);
37414d371cStb 
38414d371cStb 	if ((aobj = OBJ_nid2obj(NID_undef)) == NULL)
39414d371cStb 		errx(1, "%s: OBJ_nid2obj", __func__);
40414d371cStb 
41414d371cStb 	if (alg->algorithm != aobj) {
42414d371cStb 		fprintf(stderr, "FAIL: %s: want NID_undef OID\n", __func__);
43414d371cStb 		goto failure;
44414d371cStb 	}
45414d371cStb 	if (alg->parameter != NULL) {
46414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL parameters\n", __func__);
47414d371cStb 		goto failure;
48414d371cStb 	}
49414d371cStb 
50414d371cStb 	failed = 0;
51414d371cStb 
52414d371cStb  failure:
53414d371cStb 	X509_ALGOR_free(alg);
54414d371cStb 
55414d371cStb 	return failed;
56414d371cStb }
57414d371cStb 
58414d371cStb static int
x509_algor_set0_test(void)59414d371cStb x509_algor_set0_test(void)
60414d371cStb {
61414d371cStb 	X509_ALGOR *alg = NULL;
62414d371cStb 	ASN1_TYPE *old_parameter;
63414d371cStb 	ASN1_OBJECT *oid;
64414d371cStb 	ASN1_INTEGER *aint = NULL, *aint_ref;
65414d371cStb 	int ret;
66414d371cStb 	int failed = 1;
67414d371cStb 
68414d371cStb 	if ((ret = X509_ALGOR_set0(NULL, NULL, 0, NULL)) != 0) {
69414d371cStb 		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(NULL, NULL, 0, NULL)"
70414d371cStb 		    ", want: %d, got %d\n", __func__, 0, ret);
71414d371cStb 		goto failure;
72414d371cStb 	}
73414d371cStb 
74414d371cStb 	if ((alg = X509_ALGOR_new()) == NULL)
75414d371cStb 		errx(1, "%s: X509_ALGOR_new", __func__);
76414d371cStb 
77414d371cStb 	/* This sets algorithm to NULL and allocates new parameters. */
78414d371cStb 	if ((ret = X509_ALGOR_set0(alg, NULL, 0, NULL)) != 1) {
79414d371cStb 		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, NULL)"
80414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
81414d371cStb 		goto failure;
82414d371cStb 	}
83414d371cStb 	if (alg->algorithm != NULL) {
84414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
85414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
86414d371cStb 		goto failure;
87414d371cStb 	}
88414d371cStb 	if ((old_parameter = alg->parameter) == NULL) {
89414d371cStb 		fprintf(stderr, "FAIL: %s: want non-NULL parameter after "
90414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
91414d371cStb 		goto failure;
92414d371cStb 	}
93414d371cStb 	if (alg->parameter->type != V_ASN1_UNDEF) {
94414d371cStb 		fprintf(stderr, "FAIL: %s: want %d parameter type after "
95414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL), got %d\n",
96414d371cStb 		    __func__, V_ASN1_UNDEF, alg->parameter->type);
97414d371cStb 		goto failure;
98414d371cStb 	}
99414d371cStb 	if (alg->parameter->value.ptr != NULL) {
100414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL parameter value after "
101414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
102414d371cStb 		goto failure;
103414d371cStb 	}
104414d371cStb 
105414d371cStb 	/* This should leave algorithm at NULL and parameters untouched. */
106414d371cStb 	if ((ret = X509_ALGOR_set0(alg, NULL, 0, NULL)) != 1) {
107414d371cStb 		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, NULL)"
108414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
109414d371cStb 		goto failure;
110414d371cStb 	}
111414d371cStb 	if (alg->algorithm != NULL) {
112414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL algorithm after second"
113414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
114414d371cStb 		goto failure;
115414d371cStb 	}
116414d371cStb 	if (alg->parameter != old_parameter) {
117414d371cStb 		fprintf(stderr, "FAIL: %s: parameter changed after second"
118414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, NULL)\n", __func__);
119414d371cStb 		goto failure;
120414d371cStb 	}
121414d371cStb 
122414d371cStb 	/* This ignores pval (old_parameter). */
123414d371cStb 	if ((ret = X509_ALGOR_set0(alg, NULL, 0, old_parameter)) != 1) {
124414d371cStb 		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, ptr)"
125414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
126414d371cStb 		goto failure;
127414d371cStb 	}
128414d371cStb 	if (alg->algorithm != NULL) {
129414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
130414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
131414d371cStb 		goto failure;
132414d371cStb 	}
133414d371cStb 	if (alg->parameter == NULL) {
134414d371cStb 		fprintf(stderr, "FAIL: %s: want non-NULL parameter after "
135414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
136414d371cStb 		goto failure;
137414d371cStb 	}
138414d371cStb 	if (alg->parameter->type != V_ASN1_UNDEF) {
139414d371cStb 		fprintf(stderr, "FAIL: %s: want %d parameter type after "
140414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, ptr), got %d\n",
141414d371cStb 		    __func__, V_ASN1_UNDEF, alg->parameter->type);
142414d371cStb 		goto failure;
143414d371cStb 	}
144414d371cStb 	if (alg->parameter->value.ptr != NULL) {
145414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL parameter value after "
146414d371cStb 		    "X509_ALGOR_set0(alg, NULL, 0, ptr)\n", __func__);
147414d371cStb 		goto failure;
148414d371cStb 	}
149414d371cStb 
150414d371cStb 	old_parameter = NULL;
151414d371cStb 
152414d371cStb 	/* This frees parameters and ignores pval. */
153414d371cStb 	if ((ret = X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)) != 1) {
154414d371cStb 		fprintf(stderr, "FAIL: %s: "
155414d371cStb 		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)"
156414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
157414d371cStb 		goto failure;
158414d371cStb 	}
159414d371cStb 	if (alg->algorithm != NULL) {
160414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
161414d371cStb 		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)\n", __func__);
162414d371cStb 		goto failure;
163414d371cStb 	}
164414d371cStb 	if (alg->parameter != NULL) {
165414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL parameter after "
166414d371cStb 		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, NULL)\n", __func__);
167414d371cStb 		goto failure;
168414d371cStb 	}
169414d371cStb 
170414d371cStb 	/* This frees parameters and ignores "foo". */
171414d371cStb 	if ((ret = X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, "foo")) != 1) {
172414d371cStb 		fprintf(stderr, "FAIL: %s: X509_ALGOR_set0(alg, NULL, 0, \"foo\")"
173414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
174414d371cStb 		goto failure;
175414d371cStb 	}
176414d371cStb 	if (alg->algorithm != NULL) {
177414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL algorithm after "
178414d371cStb 		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, \"foo\")\n", __func__);
179414d371cStb 		goto failure;
180414d371cStb 	}
181414d371cStb 	if (alg->parameter != NULL) {
182414d371cStb 		fprintf(stderr, "FAIL: %s: want NULL parameter after "
183414d371cStb 		    "X509_ALGOR_set0(alg, NULL, V_ASN1_UNDEF, \"foo\")\n", __func__);
184414d371cStb 		goto failure;
185414d371cStb 	}
186414d371cStb 
187414d371cStb 	if ((oid = OBJ_nid2obj(NID_sha512_224)) == NULL) {
188414d371cStb 		fprintf(stderr, "FAIL: %s: OBJ_nid2obj(NID_sha512_224)\n", __func__);
189414d371cStb 		goto failure;
190414d371cStb 	}
191414d371cStb 	if ((aint = aint_ref = ASN1_INTEGER_new()) == NULL)
192414d371cStb 		errx(1, "%s: ASN1_INTEGER_new()", __func__);
193414d371cStb 	if (!ASN1_INTEGER_set_uint64(aint, 57))
194414d371cStb 		errx(1, "%s: ASN1_INTEGER_set_uint64()", __func__);
195414d371cStb 
196414d371cStb 	if ((ret = X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)) != 1) {
197414d371cStb 		fprintf(stderr, "Fail: %s: "
19806de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
199414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
200414d371cStb 		goto failure;
201414d371cStb 	}
202414d371cStb 	aint = NULL;
203414d371cStb 	if (alg->algorithm != oid) {
204414d371cStb 		fprintf(stderr, "FAIL: %s: unexpected oid on alg after "
20506de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
206414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
207414d371cStb 		goto failure;
208414d371cStb 	}
209414d371cStb 	if (alg->parameter == NULL) {
210414d371cStb 		fprintf(stderr, "FAIL: %s: expected non-NULL parameter after "
21106de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
212414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
213414d371cStb 		goto failure;
214414d371cStb 	}
215414d371cStb 	if (alg->parameter->type != V_ASN1_INTEGER) {
216414d371cStb 		fprintf(stderr, "FAIL: %s: want %d parameter type after "
21706de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint), got %d\n",
218414d371cStb 		    __func__, V_ASN1_INTEGER, alg->parameter->type);
219414d371cStb 		goto failure;
220414d371cStb 	}
221414d371cStb 	if (alg->parameter->value.asn1_string != aint_ref) {
222414d371cStb 		fprintf(stderr, "FAIL: %s: unexpected parameter value after "
22306de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_NULL, aint)\n", __func__);
224414d371cStb 		goto failure;
225414d371cStb 	}
226414d371cStb 
227414d371cStb 	failed = 0;
228414d371cStb 
229414d371cStb  failure:
230414d371cStb 	X509_ALGOR_free(alg);
231414d371cStb 	ASN1_INTEGER_free(aint);
232414d371cStb 
233414d371cStb 	return failed;
234414d371cStb }
235414d371cStb 
236414d371cStb static int
x509_algor_get0_test(void)237414d371cStb x509_algor_get0_test(void)
238414d371cStb {
239414d371cStb 	X509_ALGOR *alg;
240414d371cStb 	const ASN1_OBJECT *aobj = NULL;
241414d371cStb 	int ptype = 0;
242414d371cStb 	const void *pval = NULL;
243414d371cStb 	ASN1_OBJECT *oid;
244414d371cStb 	ASN1_INTEGER *aint = NULL, *aint_ref = NULL;
245414d371cStb 	int ret;
246414d371cStb 	int failed = 1;
247414d371cStb 
248414d371cStb 	if ((alg = X509_ALGOR_new()) == NULL)
249414d371cStb 		errx(1, "%s: X509_ALGOR_new", __func__);
250414d371cStb 
251414d371cStb 	X509_ALGOR_get0(&aobj, NULL, NULL, alg);
252414d371cStb 	if (aobj == NULL) {
253414d371cStb 		fprintf(stderr, "FAIL: %s: expected non-NULL aobj\n", __func__);
254414d371cStb 		goto failure;
255414d371cStb 	}
256414d371cStb 	X509_ALGOR_get0(NULL, &ptype, NULL, alg);
257414d371cStb 	if (ptype != V_ASN1_UNDEF) {
258414d371cStb 		fprintf(stderr, "FAIL: %s: want %d, got %d\n",
259414d371cStb 		    __func__, V_ASN1_UNDEF, ptype);
260414d371cStb 		goto failure;
261414d371cStb 	}
262414d371cStb 
263414d371cStb 	if ((oid = OBJ_nid2obj(NID_ED25519)) == NULL)
264414d371cStb 		errx(1, "%s: OBJ_nid2obj(NID_ED25519)", __func__);
265414d371cStb 	if ((aint = aint_ref = ASN1_INTEGER_new()) == NULL)
266414d371cStb 		errx(1, "%s: ASN1_INTEGER_new()", __func__);
267414d371cStb 	if (!ASN1_INTEGER_set_uint64(aint, 99))
268414d371cStb 		errx(1, "%s: ASN1_INTEGER_set_uint64()", __func__);
269414d371cStb 
270414d371cStb 	if ((ret = X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)) != 1) {
271414d371cStb 		fprintf(stderr, "Fail: %s: "
27206de2224Stb 		    "X509_ALGOR_set0(alg, oid, V_ASN1_INTEGER, aint)"
273414d371cStb 		    ", want: %d, got %d\n", __func__, 1, ret);
274414d371cStb 		goto failure;
275414d371cStb 	}
276414d371cStb 	aint = NULL;
277414d371cStb 
278414d371cStb 	X509_ALGOR_get0(&aobj, NULL, NULL, alg);
279414d371cStb 	if (aobj != oid) {
280414d371cStb 		fprintf(stderr, "FAIL: %s: expected Ed25519 oid\n", __func__);
281414d371cStb 		goto failure;
282414d371cStb 	}
283414d371cStb 	X509_ALGOR_get0(NULL, &ptype, NULL, alg);
284414d371cStb 	if (ptype != V_ASN1_INTEGER) {
285414d371cStb 		fprintf(stderr, "FAIL: %s: expected %d, got %d\n",
286414d371cStb 		    __func__, V_ASN1_INTEGER, ptype);
287414d371cStb 		goto failure;
288414d371cStb 	}
289414d371cStb 	pval = oid;
290414d371cStb 	X509_ALGOR_get0(NULL, NULL, &pval, alg);
291414d371cStb 	if (pval != NULL) {
292fc20c835Stb 		fprintf(stderr, "FAIL: %s: got non-NULL pval\n", __func__);
293fc20c835Stb 		goto failure;
294414d371cStb 	}
295414d371cStb 
296414d371cStb 	aobj = NULL;
297414d371cStb 	ptype = V_ASN1_UNDEF;
298414d371cStb 	pval = oid;
299414d371cStb 	X509_ALGOR_get0(&aobj, &ptype, &pval, alg);
300414d371cStb 	if (aobj != oid) {
301414d371cStb 		fprintf(stderr, "FAIL: %s: expected Ed25519 oid 2\n", __func__);
302414d371cStb 		goto failure;
303414d371cStb 	}
304414d371cStb 	if (ptype != V_ASN1_INTEGER) {
305414d371cStb 		fprintf(stderr, "FAIL: %s: expected %d, got %d 2\n",
306414d371cStb 		    __func__, V_ASN1_INTEGER, ptype);
307414d371cStb 		goto failure;
308414d371cStb 	}
309414d371cStb 	if (pval != aint_ref) {
310414d371cStb 		fprintf(stderr, "FAIL: %s: expected ASN.1 integer\n", __func__);
311414d371cStb 		goto failure;
312414d371cStb 	}
313414d371cStb 
314414d371cStb 	failed = 0;
315414d371cStb 
316414d371cStb  failure:
317414d371cStb 	X509_ALGOR_free(alg);
318414d371cStb 	ASN1_INTEGER_free(aint);
319414d371cStb 
320414d371cStb 	return failed;
321414d371cStb }
322414d371cStb 
323414d371cStb static int
x509_algor_set_evp_md_test(void)324*00ee6dc4Stb x509_algor_set_evp_md_test(void)
325414d371cStb {
326414d371cStb 	X509_ALGOR *alg = NULL;
327414d371cStb 	const ASN1_OBJECT *aobj;
328414d371cStb 	int ptype = 0, nid = 0;
329414d371cStb 	int failed = 1;
330414d371cStb 
331414d371cStb 	if ((alg = X509_ALGOR_new()) == NULL)
332414d371cStb 		errx(1, "%s: X509_ALGOR_new", __func__);
333414d371cStb 
334*00ee6dc4Stb 	if (!X509_ALGOR_set_evp_md(alg, EVP_sm3())) {
335*00ee6dc4Stb 		fprintf(stderr, "%s: X509_ALGOR_set_evp_md to sm3 failed\n",
336*00ee6dc4Stb 		    __func__);
337*00ee6dc4Stb 		goto failure;
338*00ee6dc4Stb 	}
339414d371cStb 	X509_ALGOR_get0(&aobj, &ptype, NULL, alg);
340414d371cStb 	if ((nid = OBJ_obj2nid(aobj)) != NID_sm3) {
341414d371cStb 		fprintf(stderr, "%s: sm3 want %d, got %d\n", __func__,
342414d371cStb 		    NID_sm3, nid);
343414d371cStb 		goto failure;
344414d371cStb 	}
345414d371cStb 	if (ptype != V_ASN1_UNDEF) {
346414d371cStb 		fprintf(stderr, "%s: sm3 want %d, got %d\n", __func__,
347414d371cStb 		    V_ASN1_UNDEF, ptype);
348414d371cStb 		goto failure;
349414d371cStb 	}
350414d371cStb 
3517e2b1f45Stb 	/* Preallocate as recommended in the manual. */
3527e2b1f45Stb 	if (!X509_ALGOR_set0(alg, NULL, 0, NULL))
3537e2b1f45Stb 		errx(1, "%s: X509_ALGOR_set0", __func__);
3547e2b1f45Stb 
355*00ee6dc4Stb 	if (!X509_ALGOR_set_evp_md(alg, EVP_md5())) {
356*00ee6dc4Stb 		fprintf(stderr, "%s: X509_ALGOR_set_evp_md to md5 failed\n",
357*00ee6dc4Stb 		    __func__);
358*00ee6dc4Stb 		goto failure;
359*00ee6dc4Stb 	}
360414d371cStb 	X509_ALGOR_get0(&aobj, &ptype, NULL, alg);
361414d371cStb 	if ((nid = OBJ_obj2nid(aobj)) != NID_md5) {
362*00ee6dc4Stb 		fprintf(stderr, "%s: md5 want %d, got %d\n", __func__,
363414d371cStb 		    NID_sm3, nid);
364414d371cStb 		goto failure;
365414d371cStb 	}
366414d371cStb 	if (ptype != V_ASN1_NULL) {
367*00ee6dc4Stb 		fprintf(stderr, "%s: md5 want %d, got %d\n", __func__,
368414d371cStb 		    V_ASN1_NULL, ptype);
369414d371cStb 		goto failure;
370414d371cStb 	}
371414d371cStb 
372414d371cStb 	failed = 0;
373414d371cStb 
374414d371cStb  failure:
375414d371cStb 	X509_ALGOR_free(alg);
376414d371cStb 
377414d371cStb 	return failed;
378414d371cStb }
379414d371cStb 
380414d371cStb int
main(void)381414d371cStb main(void)
382414d371cStb {
383414d371cStb 	int failed = 0;
384414d371cStb 
385414d371cStb 	failed |= x509_algor_new_test();
386414d371cStb 	failed |= x509_algor_set0_test();
387414d371cStb 	failed |= x509_algor_get0_test();
388*00ee6dc4Stb 	failed |= x509_algor_set_evp_md_test();
389414d371cStb 
390414d371cStb 	return failed;
391414d371cStb }
392