Fixes to host checking.
[oweals/openssl.git] / crypto / x509v3 / v3nametest.c
1 #include <openssl/x509.h>
2 #include <openssl/x509v3.h>
3 #include "../e_os.h"
4 #include <string.h>
5
6 static const char *const names[] =
7         {
8         "a", "b", ".", "*", "@",
9         ".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
10         "@@", "**", "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
11         "*@example.com", "test@*.example.com", "example.com", "www.example.com",
12         "test.www.example.com", "*.example.com", "*.www.example.com",
13         "test.*.example.com", "www.*.com",
14         "example.net", "xn--rger-koa.example.com",
15         "a.example.com", "b.example.com",
16         "postmaster@example.com", "Postmaster@example.com",
17         "postmaster@EXAMPLE.COM",
18         NULL
19         };
20
21 static const char *const exceptions[] =
22         {
23         "set CN: host: [*.example.com] matches [a.example.com]",
24         "set CN: host: [*.example.com] matches [b.example.com]",
25         "set CN: host: [*.example.com] matches [www.example.com]",
26         "set CN: host: [*.example.com] matches [xn--rger-koa.example.com]",
27         "set CN: host: [*.www.example.com] matches [test.www.example.com]",
28         "set emailAddress: email: [postmaster@example.com] does not match [Postmaster@example.com]",
29         "set emailAddress: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
30         "set emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]",
31         "set emailAddress: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
32         "set dnsName: host: [*.example.com] matches [www.example.com]",
33         "set dnsName: host: [*.example.com] matches [a.example.com]",
34         "set dnsName: host: [*.example.com] matches [b.example.com]",
35         "set dnsName: host: [*.example.com] matches [xn--rger-koa.example.com]",
36         "set dnsName: host: [*.www.example.com] matches [test.www.example.com]",
37         "set rfc822Name: email: [postmaster@example.com] does not match [Postmaster@example.com]",
38         "set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@example.com]",
39         "set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
40         "set rfc822Name: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
41         NULL
42         };
43
44 static int is_exception(const char *msg)
45         {
46         const char *const *p;
47         for (p = exceptions; *p; ++p)
48                 if (strcmp(msg, *p) == 0)
49                         return 1;
50         return 0;
51         }
52
53 static int set_cn(X509 *crt, ...)
54         {
55         int ret = 0;
56         X509_NAME *n = NULL;
57         va_list ap;
58         va_start(ap, crt);
59         n = X509_NAME_new();
60         if (n == NULL)
61                 goto out;
62         while (1) {
63                 int nid;
64                 const char *name;
65                 nid = va_arg(ap, int);
66                 if (nid == 0)
67                         break;
68                 name = va_arg(ap, const char *);
69                 if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC,
70                                                         (unsigned char *)name,
71                                                 -1, -1, 1))
72                         goto out;
73         }
74         if (!X509_set_subject_name(crt, n))
75                 goto out;
76         ret = 1;
77  out:
78         X509_NAME_free(n);
79         va_end(ap);
80         return ret;
81         }
82
83 /*
84 int             X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
85 X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
86                         int nid, int crit, ASN1_OCTET_STRING *data);
87 int             X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
88 */
89
90 static int set_altname(X509 *crt, ...)
91         {
92         int ret = 0;
93         GENERAL_NAMES *gens = NULL;
94         GENERAL_NAME *gen = NULL;
95         ASN1_IA5STRING *ia5 = NULL;
96         va_list ap;
97         va_start(ap, crt);
98         gens = sk_GENERAL_NAME_new_null();
99         if (gens == NULL)
100                 goto out;
101         while (1) {
102                 int type;
103                 const char *name;
104                 type = va_arg(ap, int);
105                 if (type == 0)
106                         break;
107                 name = va_arg(ap, const char *);
108
109                 gen = GENERAL_NAME_new();
110                 if (gen == NULL)
111                         goto out;
112                 ia5 = ASN1_IA5STRING_new();
113                 if (ia5 == NULL)
114                         goto out;
115                 if (!ASN1_STRING_set(ia5, name, -1))
116                         goto out;
117                 switch (type)
118                         {
119                         case GEN_EMAIL:
120                         case GEN_DNS:
121                                 GENERAL_NAME_set0_value(gen, type, ia5);
122                                 ia5 = NULL;
123                                 break;
124                         default:
125                                 abort();
126                         }
127                 sk_GENERAL_NAME_push(gens, gen);
128                 gen = NULL;
129         }
130         if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
131                 goto out;
132         ret = 1;
133  out:
134         ASN1_IA5STRING_free(ia5);
135         GENERAL_NAME_free(gen);
136         GENERAL_NAMES_free(gens);
137         va_end(ap);
138         return ret;
139         }
140
141 static int set_cn1(X509 *crt, const char *name)
142         {
143         return set_cn(crt, NID_commonName, name, 0);
144         }
145
146
147 static int set_cn_and_email(X509 *crt, const char *name)
148         {
149         return set_cn(crt, NID_commonName, name,
150                       NID_pkcs9_emailAddress, "dummy@example.com", 0);
151         }
152
153 static int set_cn2(X509 *crt, const char *name)
154         {
155         return set_cn(crt, NID_commonName, "dummy value",
156                       NID_commonName, name, 0);
157         }
158
159 static int set_cn3(X509 *crt, const char *name)
160         {
161         return set_cn(crt, NID_commonName, name,
162                       NID_commonName, "dummy value", 0);
163         }
164
165 static int set_email1(X509 *crt, const char *name)
166         {
167         return set_cn(crt, NID_pkcs9_emailAddress, name, 0);
168         }
169
170 static int set_email2(X509 *crt, const char *name)
171         {
172         return set_cn(crt, NID_pkcs9_emailAddress, "dummy@example.com",
173                       NID_pkcs9_emailAddress, name, 0);
174         }
175
176 static int set_email3(X509 *crt, const char *name)
177         {
178         return set_cn(crt, NID_pkcs9_emailAddress, name,
179                       NID_pkcs9_emailAddress, "dummy@example.com", 0);
180         }
181
182 static int set_email_and_cn(X509 *crt, const char *name)
183         {
184         return set_cn(crt, NID_pkcs9_emailAddress, name,
185                       NID_commonName, "www.example.org", 0);
186         }
187
188 static int set_altname_dns(X509 *crt, const char *name)
189         {
190         return set_altname(crt, GEN_DNS, name, 0);
191         }
192
193 static int set_altname_email(X509 *crt, const char *name)
194         {
195         return set_altname(crt, GEN_EMAIL, name, 0);
196         }
197
198 struct set_name_fn
199         {
200         int (*fn)(X509 *, const char *);
201         const char *name;
202         int host;
203         int email;
204         };
205
206 static const struct set_name_fn name_fns[] =
207         {
208         {set_cn1, "set CN", 1, 0},
209         {set_cn2, "set CN", 1, 0},
210         {set_cn3, "set CN", 1, 0},
211         {set_cn_and_email, "set CN", 1, 0},
212         {set_email1, "set emailAddress", 0, 1},
213         {set_email2, "set emailAddress", 0, 1},
214         {set_email3, "set emailAddress", 0, 1},
215         {set_email_and_cn, "set emailAddress", 0, 1},
216         {set_altname_dns, "set dnsName", 1, 0},
217         {set_altname_email, "set rfc822Name", 0, 1},
218         {NULL, NULL, 0}
219         };
220
221 static X509 *make_cert()
222         {
223         X509 *ret = NULL;
224         X509 *crt = NULL;
225         X509_NAME *issuer = NULL;
226         crt = X509_new();
227         if (crt == NULL)
228                 goto out;
229         if (!X509_set_version(crt, 3))
230                 goto out;
231         ret = crt;
232         crt = NULL;
233  out:
234         X509_NAME_free(issuer);
235         return ret;
236         }
237
238 static int errors;
239
240 static void check_message(const struct set_name_fn *fn, const char *op,
241                           const char *nameincert, int match, const char *name)
242         {
243         char msg[1024];
244         if (match < 0)
245                 return;
246         BIO_snprintf(msg, sizeof(msg), "%s: %s: [%s] %s [%s]",
247                  fn->name, op, nameincert,
248                  match ? "matches" : "does not match", name);
249         if (is_exception(msg))
250                 return;
251         puts(msg);
252         ++errors;
253         }
254
255 static void run_cert(X509 *crt, const char *nameincert,
256                      const struct set_name_fn *fn)
257         {
258         const char *const *pname = names;
259         while (*pname)
260                 {
261                 int samename = strcasecmp(nameincert, *pname) == 0;
262                 size_t namelen = strlen(*pname);
263                 char *name = malloc(namelen);
264                 int match, ret;
265                 memcpy(name, *pname, namelen);
266
267                 ret = X509_check_host(crt, (const unsigned char *)name,
268                                       namelen, 0);
269                 match = -1;
270                 if (ret < 0)
271                         {
272                         fprintf(stderr, "internal error in X509_check_host");
273                         ++errors;
274                         }
275                 else if (fn->host)
276                         {
277                         if (ret == 1 && !samename)
278                                 match = 1;
279                         if (ret == 0 && samename)
280                                 match = 0;
281                         }
282                 else if (ret == 1)
283                         match = 1;
284                 check_message(fn, "host", nameincert, match, *pname);
285
286                 ret = X509_check_host(crt, (const unsigned char *)name,
287                                       namelen, X509_CHECK_FLAG_NO_WILDCARDS);
288                 match = -1;
289                 if (ret < 0)
290                         {
291                         fprintf(stderr, "internal error in X509_check_host");
292                         ++errors;
293                         }
294                 else if (fn->host)
295                         {
296                         if (ret == 1 && !samename)
297                                 match = 1;
298                         if (ret == 0 && samename)
299                                 match = 0;
300                         }
301                 else if (ret == 1)
302                         match = 1;
303                 check_message(fn, "host-no-wildcards",
304                               nameincert, match, *pname);
305
306                 ret = X509_check_email(crt, (const unsigned char *)name,
307                                        namelen, 0);
308                 match = -1;
309                 if (fn->email)
310                         {
311                         if (ret && !samename)
312                                 match = 1;
313                         if (!ret && samename && strchr(nameincert, '@') != NULL)
314                                 match = 0;
315                         }
316                 else if (ret)
317                         match = 1;
318                 check_message(fn, "email", nameincert, match, *pname);
319                 ++pname;
320                 free(name);
321                 }
322         }
323
324 int
325 main(void)
326         {
327         const struct set_name_fn *pfn = name_fns;
328         while (pfn->name) {
329                 const char *const *pname = names;
330                 while (*pname)
331                         {
332                         X509 *crt = make_cert();
333                         if (crt == NULL)
334                                 {
335                                 fprintf(stderr, "make_cert failed\n");
336                                 return 1;
337                                 }
338                         if (!pfn->fn(crt, *pname))
339                                 {
340                                 fprintf(stderr, "X509 name setting failed\n");
341                                 return 1;
342                                 }
343                         run_cert(crt, *pname, pfn);
344                         X509_free(crt);
345                         ++pname;
346                         }
347                 ++pfn;
348         }
349         return errors > 0 ? 1 : 0;
350         }