mem-cleanup, cont'd.
[openssl.git] / test / 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     "a", "b", ".", "*", "@",
8     ".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
9     "@@", "**", "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
10     "*@example.com", "test@*.example.com", "example.com", "www.example.com",
11     "test.www.example.com", "*.example.com", "*.www.example.com",
12     "test.*.example.com", "www.*.com",
13     ".www.example.com", "*www.example.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     "set CN: host: [*.example.com] matches [a.example.com]",
23     "set CN: host: [*.example.com] matches [b.example.com]",
24     "set CN: host: [*.example.com] matches [www.example.com]",
25     "set CN: host: [*.example.com] matches [xn--rger-koa.example.com]",
26     "set CN: host: [*.www.example.com] matches [test.www.example.com]",
27     "set CN: host: [*.www.example.com] matches [.www.example.com]",
28     "set CN: host: [*www.example.com] matches [www.example.com]",
29     "set CN: host: [test.www.example.com] matches [.www.example.com]",
30     "set CN: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
31     "set CN: host-no-wildcards: [test.www.example.com] matches [.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] matches [a.example.com]",
38     "set dnsName: host: [*.example.com] matches [b.example.com]",
39     "set dnsName: host: [*.example.com] matches [xn--rger-koa.example.com]",
40     "set dnsName: host: [*.www.example.com] matches [test.www.example.com]",
41     "set dnsName: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
42     "set dnsName: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
43     "set dnsName: host: [*.www.example.com] matches [.www.example.com]",
44     "set dnsName: host: [*www.example.com] matches [www.example.com]",
45     "set dnsName: host: [test.www.example.com] matches [.www.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     "set rfc822Name: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
50     NULL
51 };
52
53 static int is_exception(const char *msg)
54 {
55     const char *const *p;
56     for (p = exceptions; *p; ++p)
57         if (strcmp(msg, *p) == 0)
58             return 1;
59     return 0;
60 }
61
62 static int set_cn(X509 *crt, ...)
63 {
64     int ret = 0;
65     X509_NAME *n = NULL;
66     va_list ap;
67     va_start(ap, crt);
68     n = X509_NAME_new();
69     if (n == NULL)
70         goto out;
71     while (1) {
72         int nid;
73         const char *name;
74         nid = va_arg(ap, int);
75         if (nid == 0)
76             break;
77         name = va_arg(ap, const char *);
78         if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC,
79                                         (unsigned char *)name, -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         case GEN_EMAIL:
127         case GEN_DNS:
128             GENERAL_NAME_set0_value(gen, type, ia5);
129             ia5 = NULL;
130             break;
131         default:
132             abort();
133         }
134         sk_GENERAL_NAME_push(gens, gen);
135         gen = NULL;
136     }
137     if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
138         goto out;
139     ret = 1;
140  out:
141     ASN1_IA5STRING_free(ia5);
142     GENERAL_NAME_free(gen);
143     GENERAL_NAMES_free(gens);
144     va_end(ap);
145     return ret;
146 }
147
148 static int set_cn1(X509 *crt, const char *name)
149 {
150     return set_cn(crt, NID_commonName, name, 0);
151 }
152
153 static int set_cn_and_email(X509 *crt, const char *name)
154 {
155     return set_cn(crt, NID_commonName, name,
156                   NID_pkcs9_emailAddress, "dummy@example.com", 0);
157 }
158
159 static int set_cn2(X509 *crt, const char *name)
160 {
161     return set_cn(crt, NID_commonName, "dummy value",
162                   NID_commonName, name, 0);
163 }
164
165 static int set_cn3(X509 *crt, const char *name)
166 {
167     return set_cn(crt, NID_commonName, name,
168                   NID_commonName, "dummy value", 0);
169 }
170
171 static int set_email1(X509 *crt, const char *name)
172 {
173     return set_cn(crt, NID_pkcs9_emailAddress, name, 0);
174 }
175
176 static int set_email2(X509 *crt, const char *name)
177 {
178     return set_cn(crt, NID_pkcs9_emailAddress, "dummy@example.com",
179                   NID_pkcs9_emailAddress, name, 0);
180 }
181
182 static int set_email3(X509 *crt, const char *name)
183 {
184     return set_cn(crt, NID_pkcs9_emailAddress, name,
185                   NID_pkcs9_emailAddress, "dummy@example.com", 0);
186 }
187
188 static int set_email_and_cn(X509 *crt, const char *name)
189 {
190     return set_cn(crt, NID_pkcs9_emailAddress, name,
191                   NID_commonName, "www.example.org", 0);
192 }
193
194 static int set_altname_dns(X509 *crt, const char *name)
195 {
196     return set_altname(crt, GEN_DNS, name, 0);
197 }
198
199 static int set_altname_email(X509 *crt, const char *name)
200 {
201     return set_altname(crt, GEN_EMAIL, name, 0);
202 }
203
204 struct set_name_fn {
205     int (*fn) (X509 *, const char *);
206     const char *name;
207     int host;
208     int email;
209 };
210
211 static const struct set_name_fn name_fns[] = {
212     {set_cn1, "set CN", 1, 0},
213     {set_cn2, "set CN", 1, 0},
214     {set_cn3, "set CN", 1, 0},
215     {set_cn_and_email, "set CN", 1, 0},
216     {set_email1, "set emailAddress", 0, 1},
217     {set_email2, "set emailAddress", 0, 1},
218     {set_email3, "set emailAddress", 0, 1},
219     {set_email_and_cn, "set emailAddress", 0, 1},
220     {set_altname_dns, "set dnsName", 1, 0},
221     {set_altname_email, "set rfc822Name", 0, 1},
222     {NULL, NULL, 0}
223 };
224
225 static X509 *make_cert()
226 {
227     X509 *ret = NULL;
228     X509 *crt = NULL;
229     X509_NAME *issuer = NULL;
230     crt = X509_new();
231     if (crt == NULL)
232         goto out;
233     if (!X509_set_version(crt, 3))
234         goto out;
235     ret = crt;
236     crt = NULL;
237  out:
238     X509_NAME_free(issuer);
239     return ret;
240 }
241
242 static int errors;
243
244 static void check_message(const struct set_name_fn *fn, const char *op,
245                           const char *nameincert, int match, const char *name)
246 {
247     char msg[1024];
248     if (match < 0)
249         return;
250     BIO_snprintf(msg, sizeof(msg), "%s: %s: [%s] %s [%s]",
251                  fn->name, op, nameincert,
252                  match ? "matches" : "does not match", name);
253     if (is_exception(msg))
254         return;
255     puts(msg);
256     ++errors;
257 }
258
259 static void run_cert(X509 *crt, const char *nameincert,
260                      const struct set_name_fn *fn)
261 {
262     const char *const *pname = names;
263     while (*pname) {
264         int samename = strcasecmp(nameincert, *pname) == 0;
265         size_t namelen = strlen(*pname);
266         char *name = malloc(namelen);
267         int match, ret;
268         memcpy(name, *pname, namelen);
269
270         ret = X509_check_host(crt, name, namelen, 0, NULL);
271         match = -1;
272         if (ret < 0) {
273             fprintf(stderr, "internal error in X509_check_host");
274             ++errors;
275         } else if (fn->host) {
276             if (ret == 1 && !samename)
277                 match = 1;
278             if (ret == 0 && samename)
279                 match = 0;
280         } else if (ret == 1)
281             match = 1;
282         check_message(fn, "host", nameincert, match, *pname);
283
284         ret = X509_check_host(crt, name, namelen,
285                               X509_CHECK_FLAG_NO_WILDCARDS, NULL);
286         match = -1;
287         if (ret < 0) {
288             fprintf(stderr, "internal error in X509_check_host");
289             ++errors;
290         } else if (fn->host) {
291             if (ret == 1 && !samename)
292                 match = 1;
293             if (ret == 0 && samename)
294                 match = 0;
295         } else if (ret == 1)
296             match = 1;
297         check_message(fn, "host-no-wildcards", nameincert, match, *pname);
298
299         ret = X509_check_email(crt, name, namelen, 0);
300         match = -1;
301         if (fn->email) {
302             if (ret && !samename)
303                 match = 1;
304             if (!ret && samename && strchr(nameincert, '@') != NULL)
305                 match = 0;
306         } else if (ret)
307             match = 1;
308         check_message(fn, "email", nameincert, match, *pname);
309         ++pname;
310         free(name);
311     }
312 }
313
314 int main(void)
315 {
316     const struct set_name_fn *pfn = name_fns;
317     while (pfn->name) {
318         const char *const *pname = names;
319         while (*pname) {
320             X509 *crt = make_cert();
321             if (crt == NULL) {
322                 fprintf(stderr, "make_cert failed\n");
323                 return 1;
324             }
325             if (!pfn->fn(crt, *pname)) {
326                 fprintf(stderr, "X509 name setting failed\n");
327                 return 1;
328             }
329             run_cert(crt, *pname, pfn);
330             X509_free(crt);
331             ++pname;
332         }
333         ++pfn;
334     }
335     return errors > 0 ? 1 : 0;
336 }