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