1/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2 * project 1999. */
3/* ====================================================================
4 * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * 3. All advertising materials mentioning features or use of this
19 *    software must display the following acknowledgment:
20 *    "This product includes software developed by the OpenSSL Project
21 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
22 *
23 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24 *    endorse or promote products derived from this software without
25 *    prior written permission. For written permission, please contact
26 *    licensing@OpenSSL.org.
27 *
28 * 5. Products derived from this software may not be called "OpenSSL"
29 *    nor may "OpenSSL" appear in their names without prior written
30 *    permission of the OpenSSL Project.
31 *
32 * 6. Redistributions of any form whatsoever must retain the following
33 *    acknowledgment:
34 *    "This product includes software developed by the OpenSSL Project
35 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48 * OF THE POSSIBILITY OF SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This product includes cryptographic software written by Eric Young
52 * (eay@cryptsoft.com).  This product includes software written by Tim
53 * Hudson (tjh@cryptsoft.com). */
54
55#include <stdarg.h>
56#include <string.h>
57
58#include <openssl/crypto.h>
59#include <openssl/mem.h>
60#include <openssl/x509.h>
61#include <openssl/x509v3.h>
62
63
64static const char *const names[] =
65	{
66	"a", "b", ".", "*", "@",
67	".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
68	"@@", "**", "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
69	"*@example.com", "test@*.example.com", "example.com", "www.example.com",
70	"test.www.example.com", "*.example.com", "*.www.example.com",
71	"test.*.example.com", "www.*.com",
72	".www.example.com", "*www.example.com",
73	"example.net", "xn--rger-koa.example.com",
74	"a.example.com", "b.example.com",
75	"postmaster@example.com", "Postmaster@example.com",
76	"postmaster@EXAMPLE.COM",
77	NULL
78	};
79
80static const char *const exceptions[] =
81	{
82	"set CN: host: [*.example.com] matches [a.example.com]",
83	"set CN: host: [*.example.com] matches [b.example.com]",
84	"set CN: host: [*.example.com] matches [www.example.com]",
85	"set CN: host: [*.example.com] matches [xn--rger-koa.example.com]",
86	"set CN: host: [*.www.example.com] matches [test.www.example.com]",
87	"set CN: host: [*.www.example.com] matches [.www.example.com]",
88	"set CN: host: [*www.example.com] matches [www.example.com]",
89	"set CN: host: [test.www.example.com] matches [.www.example.com]",
90	"set CN: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
91	"set CN: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
92	"set emailAddress: email: [postmaster@example.com] does not match [Postmaster@example.com]",
93	"set emailAddress: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
94	"set emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]",
95	"set emailAddress: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
96	"set dnsName: host: [*.example.com] matches [www.example.com]",
97	"set dnsName: host: [*.example.com] matches [a.example.com]",
98	"set dnsName: host: [*.example.com] matches [b.example.com]",
99	"set dnsName: host: [*.example.com] matches [xn--rger-koa.example.com]",
100	"set dnsName: host: [*.www.example.com] matches [test.www.example.com]",
101	"set dnsName: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
102	"set dnsName: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
103	"set dnsName: host: [*.www.example.com] matches [.www.example.com]",
104	"set dnsName: host: [*www.example.com] matches [www.example.com]",
105	"set dnsName: host: [test.www.example.com] matches [.www.example.com]",
106	"set rfc822Name: email: [postmaster@example.com] does not match [Postmaster@example.com]",
107	"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@example.com]",
108	"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
109	"set rfc822Name: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
110	NULL
111	};
112
113static int is_exception(const char *msg)
114	{
115	const char *const *p;
116	for (p = exceptions; *p; ++p)
117		if (strcmp(msg, *p) == 0)
118			return 1;
119	return 0;
120	}
121
122static int set_cn(X509 *crt, ...)
123	{
124	int ret = 0;
125	X509_NAME *n = NULL;
126	va_list ap;
127	va_start(ap, crt);
128	n = X509_NAME_new();
129	if (n == NULL)
130		goto out;
131	while (1) {
132		int nid;
133		const char *name;
134		nid = va_arg(ap, int);
135		if (nid == 0)
136			break;
137		name = va_arg(ap, const char *);
138		if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC,
139							(unsigned char *)name,
140						-1, -1, 1))
141			goto out;
142	}
143	if (!X509_set_subject_name(crt, n))
144		goto out;
145	ret = 1;
146 out:
147	X509_NAME_free(n);
148	va_end(ap);
149	return ret;
150	}
151
152/*
153int		X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
154X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
155			int nid, int crit, ASN1_OCTET_STRING *data);
156int		X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
157*/
158
159static int set_altname(X509 *crt, ...)
160	{
161	int ret = 0;
162	GENERAL_NAMES *gens = NULL;
163	GENERAL_NAME *gen = NULL;
164	ASN1_IA5STRING *ia5 = NULL;
165	va_list ap;
166	va_start(ap, crt);
167	gens = sk_GENERAL_NAME_new_null();
168	if (gens == NULL)
169		goto out;
170	while (1) {
171		int type;
172		const char *name;
173		type = va_arg(ap, int);
174		if (type == 0)
175			break;
176		name = va_arg(ap, const char *);
177
178		gen = GENERAL_NAME_new();
179		if (gen == NULL)
180			goto out;
181		ia5 = ASN1_IA5STRING_new();
182		if (ia5 == NULL)
183			goto out;
184		if (!ASN1_STRING_set(ia5, name, -1))
185			goto out;
186		switch (type)
187			{
188			case GEN_EMAIL:
189			case GEN_DNS:
190				GENERAL_NAME_set0_value(gen, type, ia5);
191				ia5 = NULL;
192				break;
193			default:
194				abort();
195			}
196		sk_GENERAL_NAME_push(gens, gen);
197		gen = NULL;
198	}
199	if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
200		goto out;
201	ret = 1;
202 out:
203	ASN1_IA5STRING_free(ia5);
204	GENERAL_NAME_free(gen);
205	GENERAL_NAMES_free(gens);
206	va_end(ap);
207	return ret;
208	}
209
210static int set_cn1(X509 *crt, const char *name)
211	{
212	return set_cn(crt, NID_commonName, name, 0);
213	}
214
215
216static int set_cn_and_email(X509 *crt, const char *name)
217	{
218	return set_cn(crt, NID_commonName, name,
219		      NID_pkcs9_emailAddress, "dummy@example.com", 0);
220	}
221
222static int set_cn2(X509 *crt, const char *name)
223	{
224	return set_cn(crt, NID_commonName, "dummy value",
225		      NID_commonName, name, 0);
226	}
227
228static int set_cn3(X509 *crt, const char *name)
229	{
230	return set_cn(crt, NID_commonName, name,
231		      NID_commonName, "dummy value", 0);
232	}
233
234static int set_email1(X509 *crt, const char *name)
235	{
236	return set_cn(crt, NID_pkcs9_emailAddress, name, 0);
237	}
238
239static int set_email2(X509 *crt, const char *name)
240	{
241	return set_cn(crt, NID_pkcs9_emailAddress, "dummy@example.com",
242		      NID_pkcs9_emailAddress, name, 0);
243	}
244
245static int set_email3(X509 *crt, const char *name)
246	{
247	return set_cn(crt, NID_pkcs9_emailAddress, name,
248		      NID_pkcs9_emailAddress, "dummy@example.com", 0);
249	}
250
251static int set_email_and_cn(X509 *crt, const char *name)
252	{
253	return set_cn(crt, NID_pkcs9_emailAddress, name,
254		      NID_commonName, "www.example.org", 0);
255	}
256
257static int set_altname_dns(X509 *crt, const char *name)
258	{
259	return set_altname(crt, GEN_DNS, name, 0);
260	}
261
262static int set_altname_email(X509 *crt, const char *name)
263	{
264	return set_altname(crt, GEN_EMAIL, name, 0);
265	}
266
267struct set_name_fn
268	{
269	int (*fn)(X509 *, const char *);
270	const char *name;
271	int host;
272	int email;
273	};
274
275static const struct set_name_fn name_fns[] =
276	{
277	{set_cn1, "set CN", 1, 0},
278	{set_cn2, "set CN", 1, 0},
279	{set_cn3, "set CN", 1, 0},
280	{set_cn_and_email, "set CN", 1, 0},
281	{set_email1, "set emailAddress", 0, 1},
282	{set_email2, "set emailAddress", 0, 1},
283	{set_email3, "set emailAddress", 0, 1},
284	{set_email_and_cn, "set emailAddress", 0, 1},
285	{set_altname_dns, "set dnsName", 1, 0},
286	{set_altname_email, "set rfc822Name", 0, 1},
287	{NULL, NULL, 0}
288	};
289
290static X509 *make_cert(void)
291	{
292	X509 *ret = NULL;
293	X509 *crt = NULL;
294	X509_NAME *issuer = NULL;
295	crt = X509_new();
296	if (crt == NULL)
297		goto out;
298	if (!X509_set_version(crt, 3))
299		goto out;
300	ret = crt;
301	crt = NULL;
302 out:
303	X509_NAME_free(issuer);
304	return ret;
305	}
306
307static int errors;
308
309static void check_message(const struct set_name_fn *fn, const char *op,
310			  const char *nameincert, int match, const char *name)
311	{
312	char msg[1024];
313	if (match < 0)
314		return;
315	BIO_snprintf(msg, sizeof(msg), "%s: %s: [%s] %s [%s]",
316		 fn->name, op, nameincert,
317		 match ? "matches" : "does not match", name);
318	if (is_exception(msg))
319		return;
320	puts(msg);
321	++errors;
322	}
323
324static void run_cert(X509 *crt, const char *nameincert,
325		     const struct set_name_fn *fn)
326	{
327	const char *const *pname = names;
328	while (*pname)
329		{
330		int samename = OPENSSL_strcasecmp(nameincert, *pname) == 0;
331		size_t namelen = strlen(*pname);
332		char *name = malloc(namelen);
333		int match, ret;
334		memcpy(name, *pname, namelen);
335
336		ret = X509_check_host(crt, name, namelen, 0, NULL);
337		match = -1;
338		if (ret < 0)
339			{
340			fprintf(stderr, "internal error in X509_check_host");
341			++errors;
342			}
343		else if (fn->host)
344			{
345			if (ret == 1 && !samename)
346				match = 1;
347			if (ret == 0 && samename)
348				match = 0;
349			}
350		else if (ret == 1)
351			match = 1;
352		check_message(fn, "host", nameincert, match, *pname);
353
354		ret = X509_check_host(crt, name, namelen,
355				      X509_CHECK_FLAG_NO_WILDCARDS, NULL);
356		match = -1;
357		if (ret < 0)
358			{
359			fprintf(stderr, "internal error in X509_check_host");
360			++errors;
361			}
362		else if (fn->host)
363			{
364			if (ret == 1 && !samename)
365				match = 1;
366			if (ret == 0 && samename)
367				match = 0;
368			}
369		else if (ret == 1)
370			match = 1;
371		check_message(fn, "host-no-wildcards",
372			      nameincert, match, *pname);
373
374		ret = X509_check_email(crt, name, namelen, 0);
375		match = -1;
376		if (fn->email)
377			{
378			if (ret && !samename)
379				match = 1;
380			if (!ret && samename && strchr(nameincert, '@') != NULL)
381				match = 0;
382			}
383		else if (ret)
384			match = 1;
385		check_message(fn, "email", nameincert, match, *pname);
386		++pname;
387		free(name);
388		}
389	}
390
391int
392main(void)
393	{
394	CRYPTO_library_init();
395
396	const struct set_name_fn *pfn = name_fns;
397	while (pfn->name) {
398		const char *const *pname = names;
399		while (*pname)
400			{
401			X509 *crt = make_cert();
402			if (crt == NULL)
403				{
404				fprintf(stderr, "make_cert failed\n");
405				return 1;
406				}
407			if (!pfn->fn(crt, *pname))
408				{
409				fprintf(stderr, "X509 name setting failed\n");
410				return 1;
411				}
412			run_cert(crt, *pname, pfn);
413			X509_free(crt);
414			++pname;
415			}
416		++pfn;
417	}
418	if (errors == 0) {
419	  printf("PASS\n");
420	}
421	return errors > 0 ? 1 : 0;
422	}
423