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 "@@", "**", "*.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 21static 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 53static 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 62static 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/*- 92int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); 93X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, 94 int nid, int crit, ASN1_OCTET_STRING *data); 95int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); 96*/ 97 98static 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 148static int set_cn1(X509 *crt, const char *name) 149{ 150 return set_cn(crt, NID_commonName, name, 0); 151} 152 153static 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 159static 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 165static 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 171static int set_email1(X509 *crt, const char *name) 172{ 173 return set_cn(crt, NID_pkcs9_emailAddress, name, 0); 174} 175 176static 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 182static 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 188static 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 194static int set_altname_dns(X509 *crt, const char *name) 195{ 196 return set_altname(crt, GEN_DNS, name, 0); 197} 198 199static int set_altname_email(X509 *crt, const char *name) 200{ 201 return set_altname(crt, GEN_EMAIL, name, 0); 202} 203 204struct set_name_fn { 205 int (*fn) (X509 *, const char *); 206 const char *name; 207 int host; 208 int email; 209}; 210 211static 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 225static 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 242static int errors; 243 244static 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 259static 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 314int 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} 337