diff options
Diffstat (limited to 'src/regress/lib/libcrypto/x509/x509_name_test.c')
-rw-r--r-- | src/regress/lib/libcrypto/x509/x509_name_test.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/src/regress/lib/libcrypto/x509/x509_name_test.c b/src/regress/lib/libcrypto/x509/x509_name_test.c new file mode 100644 index 0000000000..24e62cc766 --- /dev/null +++ b/src/regress/lib/libcrypto/x509/x509_name_test.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* $OpenBSD: x509_name_test.c,v 1.3 2025/05/05 06:33:34 tb Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2025 Theo Buehler <tb@openbsd.org> | ||
5 | * Copyright (c) 2025 Kenjiro Nakayama <nakayamakenjiro@gmail.com> | ||
6 | * Copyright (c) 2018 Ingo Schwarze <schwarze@openbsd.org> | ||
7 | * | ||
8 | * Permission to use, copy, modify, and distribute this software for any | ||
9 | * purpose with or without fee is hereby granted, provided that the above | ||
10 | * copyright notice and this permission notice appear in all copies. | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
19 | */ | ||
20 | |||
21 | #include <err.h> | ||
22 | #include <stdio.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include <openssl/x509.h> | ||
26 | |||
27 | static const struct x509_name_legacy { | ||
28 | const char *compat; | ||
29 | const char *oneline; | ||
30 | const uint8_t der[255]; | ||
31 | size_t der_len; | ||
32 | } x509_name_legacy_test[] = { | ||
33 | { | ||
34 | .compat = | ||
35 | "C=HU, " | ||
36 | "L=Budapest, " | ||
37 | "O=Microsec Ltd., " | ||
38 | "CN=Microsec e-Szigno Root CA 2009, " | ||
39 | "emailAddress=info@e-szigno.hu", | ||
40 | .oneline = | ||
41 | "/C=HU" | ||
42 | "/L=Budapest" | ||
43 | "/O=Microsec Ltd." | ||
44 | "/CN=Microsec e-Szigno Root CA 2009" | ||
45 | "/emailAddress=info@e-szigno.hu", | ||
46 | .der = { | ||
47 | 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, | ||
48 | 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, | ||
49 | 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, | ||
50 | 0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, | ||
51 | 0x65, 0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, | ||
52 | 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69, | ||
53 | 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, | ||
54 | 0x74, 0x64, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, | ||
55 | 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x4d, 0x69, | ||
56 | 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x65, | ||
57 | 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, | ||
58 | 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, | ||
59 | 0x32, 0x30, 0x30, 0x39, 0x31, 0x1f, 0x30, 0x1d, | ||
60 | 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, | ||
61 | 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, | ||
62 | 0x6f, 0x40, 0x65, 0x2d, 0x73, 0x7a, 0x69, 0x67, | ||
63 | 0x6e, 0x6f, 0x2e, 0x68, 0x75, | ||
64 | }, | ||
65 | .der_len = 133, | ||
66 | }, | ||
67 | |||
68 | { | ||
69 | .compat = | ||
70 | "serialNumber=G63287510, " | ||
71 | "C=ES, " | ||
72 | "O=ANF Autoridad de Certificacion, " | ||
73 | "OU=ANF CA Raiz, " | ||
74 | "CN=ANF Secure Server Root CA", | ||
75 | .oneline = | ||
76 | "/serialNumber=G63287510" | ||
77 | "/C=ES" | ||
78 | "/O=ANF Autoridad de Certificacion" | ||
79 | "/OU=ANF CA Raiz" | ||
80 | "/CN=ANF Secure Server Root CA", | ||
81 | .der = { | ||
82 | 0x30, 0x81, 0x84, 0x31, 0x12, 0x30, 0x10, 0x06, | ||
83 | 0x03, 0x55, 0x04, 0x05, 0x13, 0x09, 0x47, 0x36, | ||
84 | 0x33, 0x32, 0x38, 0x37, 0x35, 0x31, 0x30, 0x31, | ||
85 | 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, | ||
86 | 0x13, 0x02, 0x45, 0x53, 0x31, 0x27, 0x30, 0x25, | ||
87 | 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x41, | ||
88 | 0x4e, 0x46, 0x20, 0x41, 0x75, 0x74, 0x6f, 0x72, | ||
89 | 0x69, 0x64, 0x61, 0x64, 0x20, 0x64, 0x65, 0x20, | ||
90 | 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, | ||
91 | 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, | ||
92 | 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b, | ||
93 | 0x41, 0x4e, 0x46, 0x20, 0x43, 0x41, 0x20, 0x52, | ||
94 | 0x61, 0x69, 0x7a, 0x31, 0x22, 0x30, 0x20, 0x06, | ||
95 | 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, 0x4e, | ||
96 | 0x46, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, | ||
97 | 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, | ||
98 | 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, | ||
99 | }, | ||
100 | .der_len = 135, | ||
101 | }, | ||
102 | |||
103 | { | ||
104 | .compat = | ||
105 | "C=GB, " | ||
106 | "ST=Greater Manchester, " | ||
107 | "L=Salford, " | ||
108 | "O=COMODO CA Limited, " | ||
109 | "CN=COMODO Certification Authority", | ||
110 | .oneline = | ||
111 | "/C=GB" | ||
112 | "/ST=Greater Manchester" | ||
113 | "/L=Salford" | ||
114 | "/O=COMODO CA Limited" | ||
115 | "/CN=COMODO Certification Authority", | ||
116 | .der = { | ||
117 | 0x30, 0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, | ||
118 | 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, | ||
119 | 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, | ||
120 | 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, | ||
121 | 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, | ||
122 | 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, | ||
123 | 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, | ||
124 | 0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, | ||
125 | 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, | ||
126 | 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, | ||
127 | 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, | ||
128 | 0x74, 0x65, 0x64, 0x31, 0x27, 0x30, 0x25, 0x06, | ||
129 | 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x43, 0x4f, | ||
130 | 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72, | ||
131 | 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, | ||
132 | 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, | ||
133 | 0x72, 0x69, 0x74, 0x79, | ||
134 | }, | ||
135 | .der_len = 132, | ||
136 | }, | ||
137 | |||
138 | { | ||
139 | .compat = | ||
140 | "C=HU, " | ||
141 | "L=Budapest, " | ||
142 | "O=Microsec Ltd., " | ||
143 | "2.5.4.97=VATHU-23584497, " | ||
144 | "CN=e-Szigno Root CA 2017", | ||
145 | .oneline = | ||
146 | "/C=HU" | ||
147 | "/L=Budapest" | ||
148 | "/O=Microsec Ltd." | ||
149 | "/2.5.4.97=VATHU-23584497" | ||
150 | "/CN=e-Szigno Root CA 2017", | ||
151 | .der = { | ||
152 | 0x30, 0x71, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, | ||
153 | 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31, | ||
154 | 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, | ||
155 | 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, | ||
156 | 0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, | ||
157 | 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69, 0x63, | ||
158 | 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, | ||
159 | 0x64, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, | ||
160 | 0x55, 0x04, 0x61, 0x0c, 0x0e, 0x56, 0x41, 0x54, | ||
161 | 0x48, 0x55, 0x2d, 0x32, 0x33, 0x35, 0x38, 0x34, | ||
162 | 0x34, 0x39, 0x37, 0x31, 0x1e, 0x30, 0x1c, 0x06, | ||
163 | 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x65, 0x2d, | ||
164 | 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, | ||
165 | 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, | ||
166 | 0x30, 0x31, 0x37, | ||
167 | }, | ||
168 | .der_len = 115, | ||
169 | }, | ||
170 | |||
171 | { | ||
172 | |||
173 | .compat = | ||
174 | "C=ES, " | ||
175 | "O=FNMT-RCM, " | ||
176 | "OU=Ceres, " | ||
177 | "2.5.4.97=VATES-Q2826004J, " | ||
178 | "CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS", | ||
179 | .oneline = | ||
180 | "/C=ES" | ||
181 | "/O=FNMT-RCM" | ||
182 | "/OU=Ceres" | ||
183 | "/2.5.4.97=VATES-Q2826004J" | ||
184 | "/CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS", | ||
185 | .der = { | ||
186 | 0x30, 0x78, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, | ||
187 | 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, | ||
188 | 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, | ||
189 | 0x0c, 0x08, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, | ||
190 | 0x43, 0x4d, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, | ||
191 | 0x55, 0x04, 0x0b, 0x0c, 0x05, 0x43, 0x65, 0x72, | ||
192 | 0x65, 0x73, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, | ||
193 | 0x55, 0x04, 0x61, 0x0c, 0x0f, 0x56, 0x41, 0x54, | ||
194 | 0x45, 0x53, 0x2d, 0x51, 0x32, 0x38, 0x32, 0x36, | ||
195 | 0x30, 0x30, 0x34, 0x4a, 0x31, 0x2c, 0x30, 0x2a, | ||
196 | 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x41, | ||
197 | 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, | ||
198 | 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x20, | ||
199 | 0x53, 0x45, 0x52, 0x56, 0x49, 0x44, 0x4f, 0x52, | ||
200 | 0x45, 0x53, 0x20, 0x53, 0x45, 0x47, 0x55, 0x52, | ||
201 | 0x4f, 0x53 | ||
202 | }, | ||
203 | .der_len = 122, | ||
204 | }, | ||
205 | }; | ||
206 | |||
207 | #define N_X509_NAME_COMPAT \ | ||
208 | (sizeof(x509_name_legacy_test) / sizeof(x509_name_legacy_test[0])) | ||
209 | |||
210 | static int | ||
211 | x509_name_compat_testcase(const struct x509_name_legacy *test) | ||
212 | { | ||
213 | const uint8_t *p; | ||
214 | X509_NAME *name = NULL; | ||
215 | unsigned char *der = NULL; | ||
216 | int der_len = 0; | ||
217 | BIO *bio = NULL; | ||
218 | char *got; | ||
219 | int got_len; | ||
220 | char *buf = NULL; | ||
221 | int failed = 1; | ||
222 | |||
223 | p = test->der; | ||
224 | if ((name = d2i_X509_NAME(NULL, &p, test->der_len)) == NULL) | ||
225 | errx(1, "d2i_X509_NAME"); | ||
226 | |||
227 | if ((der_len = i2d_X509_NAME(name, &der)) <= 0) { | ||
228 | fprintf(stderr, "FAIL: %s: i2d_X509_NAME", __func__); | ||
229 | der_len = 0; | ||
230 | goto err; | ||
231 | } | ||
232 | |||
233 | if (test->der_len != (size_t)der_len) { | ||
234 | fprintf(stderr, "FAIL: %s: der len: want %zu, got %d\n", | ||
235 | __func__, test->der_len, der_len); | ||
236 | goto err; | ||
237 | } | ||
238 | |||
239 | if (memcmp(test->der, der, test->der_len) != 0) { | ||
240 | fprintf(stderr, "FAIL: %s: DER mismatch\n", __func__); | ||
241 | goto err; | ||
242 | } | ||
243 | |||
244 | if ((bio = BIO_new(BIO_s_mem())) == NULL) | ||
245 | errx(1, "BIO_new"); | ||
246 | |||
247 | if (!X509_NAME_print_ex(bio, name, 0, XN_FLAG_COMPAT)) { | ||
248 | fprintf(stderr, "FAIL: %s: X509_NAME_print_ex", __func__); | ||
249 | goto err; | ||
250 | } | ||
251 | |||
252 | if ((got_len = BIO_get_mem_data(bio, &got)) < 0) | ||
253 | errx(1, "BIO_get_mem_data"); | ||
254 | |||
255 | if (strcmp(test->compat, got) != 0) { | ||
256 | fprintf(stderr, "FAIL: %s compat:\nwant: \"%s\",\ngot: \"%s\"\n", | ||
257 | __func__, test->compat, got); | ||
258 | goto err; | ||
259 | } | ||
260 | |||
261 | if ((buf = X509_NAME_oneline(name, NULL, 0)) == NULL) | ||
262 | errx(1, "X509_NAME_oneline"); | ||
263 | |||
264 | if (strcmp(test->oneline, buf) != 0) { | ||
265 | fprintf(stderr, "FAIL: %s oneline:\nwant: \"%s\",\ngot: \"%s\"\n", | ||
266 | __func__, test->compat, got); | ||
267 | goto err; | ||
268 | } | ||
269 | |||
270 | failed = 0; | ||
271 | |||
272 | err: | ||
273 | BIO_free(bio); | ||
274 | free(buf); | ||
275 | X509_NAME_free(name); | ||
276 | freezero(der, der_len); | ||
277 | |||
278 | return failed; | ||
279 | } | ||
280 | |||
281 | static int | ||
282 | x509_name_compat_test(void) | ||
283 | { | ||
284 | size_t i; | ||
285 | int failed = 0; | ||
286 | |||
287 | for (i = 0; i < N_X509_NAME_COMPAT; i++) | ||
288 | failed |= x509_name_compat_testcase(&x509_name_legacy_test[i]); | ||
289 | |||
290 | return failed; | ||
291 | } | ||
292 | |||
293 | static const struct x509_name_entry_test { | ||
294 | const char *field; | ||
295 | const char *value; | ||
296 | int loc; | ||
297 | int set; | ||
298 | const char *expected_str; | ||
299 | const int expected_set[4]; | ||
300 | const int expected_count; | ||
301 | } entry_tests[] = { | ||
302 | { | ||
303 | .field = "ST", | ||
304 | .value = "BaWue", | ||
305 | .loc = -1, | ||
306 | .set = 0, | ||
307 | .expected_str = "ST=BaWue", | ||
308 | .expected_set = { 0 }, | ||
309 | .expected_count = 1, | ||
310 | }, | ||
311 | { | ||
312 | .field = "O", | ||
313 | .value = "KIT", | ||
314 | .loc = -1, | ||
315 | .set = 0, | ||
316 | .expected_str = "ST=BaWue, O=KIT", | ||
317 | .expected_set = { 0, 1 }, | ||
318 | .expected_count = 2, | ||
319 | }, | ||
320 | { | ||
321 | .field = "L", | ||
322 | .value = "Karlsruhe", | ||
323 | .loc = 1, | ||
324 | .set = 0, | ||
325 | .expected_str = "ST=BaWue, L=Karlsruhe, O=KIT", | ||
326 | .expected_set = { 0, 1, 2 }, | ||
327 | .expected_count = 3, | ||
328 | }, | ||
329 | { | ||
330 | .field = "C", | ||
331 | .value = "DE", | ||
332 | .loc = 0, | ||
333 | .set = 1, | ||
334 | .expected_str = "C=DE + ST=BaWue, L=Karlsruhe, O=KIT", | ||
335 | .expected_set = { 0, 0, 1, 2 }, | ||
336 | .expected_count = 4, | ||
337 | }, | ||
338 | }; | ||
339 | |||
340 | #define N_ENTRY_TESTS (sizeof(entry_tests) / sizeof(entry_tests[0])) | ||
341 | |||
342 | static int | ||
343 | verify_x509_name_output(X509_NAME *name, const struct x509_name_entry_test *tc) | ||
344 | { | ||
345 | BIO *bio; | ||
346 | char *got; | ||
347 | long got_len; | ||
348 | int loc, ret; | ||
349 | int failed = 1; | ||
350 | |||
351 | if ((bio = BIO_new(BIO_s_mem())) == NULL) | ||
352 | goto fail; | ||
353 | |||
354 | if ((ret = X509_NAME_print_ex(bio, name, 0, XN_FLAG_SEP_CPLUS_SPC)) == -1) | ||
355 | goto fail; | ||
356 | |||
357 | if ((got_len = BIO_get_mem_data(bio, &got)) < 0) | ||
358 | goto fail; | ||
359 | |||
360 | if (ret != got_len || strlen(tc->expected_str) != (size_t)ret) | ||
361 | goto fail; | ||
362 | |||
363 | if (strncmp(tc->expected_str, got, got_len) != 0) | ||
364 | goto fail; | ||
365 | |||
366 | if (X509_NAME_entry_count(name) != tc->expected_count) | ||
367 | goto fail; | ||
368 | |||
369 | for (loc = 0; loc < X509_NAME_entry_count(name); loc++) { | ||
370 | X509_NAME_ENTRY *e = X509_NAME_get_entry(name, loc); | ||
371 | if (e == NULL || X509_NAME_ENTRY_set(e) != tc->expected_set[loc]) | ||
372 | goto fail; | ||
373 | } | ||
374 | |||
375 | failed = 0; | ||
376 | |||
377 | fail: | ||
378 | BIO_free(bio); | ||
379 | |||
380 | return failed; | ||
381 | } | ||
382 | |||
383 | static int | ||
384 | x509_name_add_entry_test(void) | ||
385 | { | ||
386 | X509_NAME *name; | ||
387 | int failed = 1; | ||
388 | |||
389 | if ((name = X509_NAME_new()) == NULL) | ||
390 | goto done; | ||
391 | |||
392 | for (size_t i = 0; i < N_ENTRY_TESTS; i++) { | ||
393 | const struct x509_name_entry_test *t = &entry_tests[i]; | ||
394 | |||
395 | if (!X509_NAME_add_entry_by_txt(name, t->field, MBSTRING_ASC, | ||
396 | (const unsigned char *)t->value, -1, t->loc, t->set)) | ||
397 | goto done; | ||
398 | |||
399 | if (verify_x509_name_output(name, t)) | ||
400 | goto done; | ||
401 | } | ||
402 | |||
403 | failed = 0; | ||
404 | |||
405 | done: | ||
406 | X509_NAME_free(name); | ||
407 | |||
408 | return failed; | ||
409 | } | ||
410 | |||
411 | int | ||
412 | main(void) | ||
413 | { | ||
414 | int failed = 0; | ||
415 | |||
416 | failed |= x509_name_compat_test(); | ||
417 | failed |= x509_name_add_entry_test(); | ||
418 | |||
419 | return failed; | ||
420 | } | ||