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