1 /* 2 * Written by Dr Stephen N Henson (steve (at) openssl.org) for the OpenSSL project 3 * 2004. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2004 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing (at) OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay (at) cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh (at) cryptsoft.com). */ 56 57 #include <string.h> 58 59 #include <openssl/buf.h> 60 #include <openssl/mem.h> 61 #include <openssl/obj.h> 62 #include <openssl/stack.h> 63 #include <openssl/x509.h> 64 #include <openssl/x509v3.h> 65 66 #include "vpm_int.h" 67 #include "../internal.h" 68 69 70 /* X509_VERIFY_PARAM functions */ 71 72 #define SET_HOST 0 73 #define ADD_HOST 1 74 75 static char *str_copy(char *s) 76 { 77 return OPENSSL_strdup(s); 78 } 79 80 static void str_free(char *s) 81 { 82 OPENSSL_free(s); 83 } 84 85 #define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free) 86 87 static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, 88 const char *name, size_t namelen) 89 { 90 char *copy; 91 92 /* 93 * Refuse names with embedded NUL bytes. 94 * XXX: Do we need to push an error onto the error stack? 95 */ 96 if (name && OPENSSL_memchr(name, '\0', namelen)) 97 return 0; 98 99 if (mode == SET_HOST && id->hosts) { 100 string_stack_free(id->hosts); 101 id->hosts = NULL; 102 } 103 if (name == NULL || namelen == 0) 104 return 1; 105 106 copy = BUF_strndup(name, namelen); 107 if (copy == NULL) 108 return 0; 109 110 if (id->hosts == NULL && 111 (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) { 112 OPENSSL_free(copy); 113 return 0; 114 } 115 116 if (!sk_OPENSSL_STRING_push(id->hosts, copy)) { 117 OPENSSL_free(copy); 118 if (sk_OPENSSL_STRING_num(id->hosts) == 0) { 119 sk_OPENSSL_STRING_free(id->hosts); 120 id->hosts = NULL; 121 } 122 return 0; 123 } 124 125 return 1; 126 } 127 128 static void x509_verify_param_zero(X509_VERIFY_PARAM *param) 129 { 130 X509_VERIFY_PARAM_ID *paramid; 131 if (!param) 132 return; 133 param->name = NULL; 134 param->purpose = 0; 135 param->trust = 0; 136 /* 137 * param->inh_flags = X509_VP_FLAG_DEFAULT; 138 */ 139 param->inh_flags = 0; 140 param->flags = 0; 141 param->depth = -1; 142 if (param->policies) { 143 sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); 144 param->policies = NULL; 145 } 146 paramid = param->id; 147 if (paramid->hosts) { 148 string_stack_free(paramid->hosts); 149 paramid->hosts = NULL; 150 } 151 if (paramid->peername) { 152 OPENSSL_free(paramid->peername); 153 paramid->peername = NULL; 154 } 155 if (paramid->email) { 156 OPENSSL_free(paramid->email); 157 paramid->email = NULL; 158 paramid->emaillen = 0; 159 } 160 if (paramid->ip) { 161 OPENSSL_free(paramid->ip); 162 paramid->ip = NULL; 163 paramid->iplen = 0; 164 } 165 166 } 167 168 X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) 169 { 170 X509_VERIFY_PARAM *param; 171 X509_VERIFY_PARAM_ID *paramid; 172 param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM)); 173 if (!param) 174 return NULL; 175 paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM_ID)); 176 if (!paramid) { 177 OPENSSL_free(param); 178 return NULL; 179 } 180 OPENSSL_memset(param, 0, sizeof(X509_VERIFY_PARAM)); 181 OPENSSL_memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID)); 182 param->id = paramid; 183 x509_verify_param_zero(param); 184 return param; 185 } 186 187 void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) 188 { 189 if (param == NULL) 190 return; 191 x509_verify_param_zero(param); 192 OPENSSL_free(param->id); 193 OPENSSL_free(param); 194 } 195 196 /*- 197 * This function determines how parameters are "inherited" from one structure 198 * to another. There are several different ways this can happen. 199 * 200 * 1. If a child structure needs to have its values initialized from a parent 201 * they are simply copied across. For example SSL_CTX copied to SSL. 202 * 2. If the structure should take on values only if they are currently unset. 203 * For example the values in an SSL structure will take appropriate value 204 * for SSL servers or clients but only if the application has not set new 205 * ones. 206 * 207 * The "inh_flags" field determines how this function behaves. 208 * 209 * Normally any values which are set in the default are not copied from the 210 * destination and verify flags are ORed together. 211 * 212 * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied 213 * to the destination. Effectively the values in "to" become default values 214 * which will be used only if nothing new is set in "from". 215 * 216 * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether 217 * they are set or not. Flags is still Ored though. 218 * 219 * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead 220 * of ORed. 221 * 222 * If X509_VP_FLAG_LOCKED is set then no values are copied. 223 * 224 * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed 225 * after the next call. 226 */ 227 228 /* Macro to test if a field should be copied from src to dest */ 229 230 #define test_x509_verify_param_copy(field, def) \ 231 (to_overwrite || \ 232 ((src->field != (def)) && (to_default || (dest->field == (def))))) 233 234 /* As above but for ID fields */ 235 236 #define test_x509_verify_param_copy_id(idf, def) \ 237 test_x509_verify_param_copy(id->idf, def) 238 239 /* Macro to test and copy a field if necessary */ 240 241 #define x509_verify_param_copy(field, def) \ 242 if (test_x509_verify_param_copy(field, def)) \ 243 dest->field = src->field 244 245 int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, 246 const X509_VERIFY_PARAM *src) 247 { 248 unsigned long inh_flags; 249 int to_default, to_overwrite; 250 X509_VERIFY_PARAM_ID *id; 251 if (!src) 252 return 1; 253 id = src->id; 254 inh_flags = dest->inh_flags | src->inh_flags; 255 256 if (inh_flags & X509_VP_FLAG_ONCE) 257 dest->inh_flags = 0; 258 259 if (inh_flags & X509_VP_FLAG_LOCKED) 260 return 1; 261 262 if (inh_flags & X509_VP_FLAG_DEFAULT) 263 to_default = 1; 264 else 265 to_default = 0; 266 267 if (inh_flags & X509_VP_FLAG_OVERWRITE) 268 to_overwrite = 1; 269 else 270 to_overwrite = 0; 271 272 x509_verify_param_copy(purpose, 0); 273 x509_verify_param_copy(trust, 0); 274 x509_verify_param_copy(depth, -1); 275 276 /* If overwrite or check time not set, copy across */ 277 278 if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) { 279 dest->check_time = src->check_time; 280 dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME; 281 /* Don't need to copy flag: that is done below */ 282 } 283 284 if (inh_flags & X509_VP_FLAG_RESET_FLAGS) 285 dest->flags = 0; 286 287 dest->flags |= src->flags; 288 289 if (test_x509_verify_param_copy(policies, NULL)) { 290 if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) 291 return 0; 292 } 293 294 /* Copy the host flags if and only if we're copying the host list */ 295 if (test_x509_verify_param_copy_id(hosts, NULL)) { 296 if (dest->id->hosts) { 297 string_stack_free(dest->id->hosts); 298 dest->id->hosts = NULL; 299 } 300 if (id->hosts) { 301 dest->id->hosts = 302 sk_OPENSSL_STRING_deep_copy(id->hosts, str_copy, str_free); 303 if (dest->id->hosts == NULL) 304 return 0; 305 dest->id->hostflags = id->hostflags; 306 } 307 } 308 309 if (test_x509_verify_param_copy_id(email, NULL)) { 310 if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen)) 311 return 0; 312 } 313 314 if (test_x509_verify_param_copy_id(ip, NULL)) { 315 if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen)) 316 return 0; 317 } 318 319 return 1; 320 } 321 322 int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, 323 const X509_VERIFY_PARAM *from) 324 { 325 unsigned long save_flags = to->inh_flags; 326 int ret; 327 to->inh_flags |= X509_VP_FLAG_DEFAULT; 328 ret = X509_VERIFY_PARAM_inherit(to, from); 329 to->inh_flags = save_flags; 330 return ret; 331 } 332 333 static int int_x509_param_set1(char **pdest, size_t *pdestlen, 334 const char *src, size_t srclen) 335 { 336 void *tmp; 337 if (src) { 338 if (srclen == 0) { 339 tmp = BUF_strdup(src); 340 srclen = strlen(src); 341 } else 342 tmp = BUF_memdup(src, srclen); 343 if (!tmp) 344 return 0; 345 } else { 346 tmp = NULL; 347 srclen = 0; 348 } 349 if (*pdest) 350 OPENSSL_free(*pdest); 351 *pdest = tmp; 352 if (pdestlen) 353 *pdestlen = srclen; 354 return 1; 355 } 356 357 int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) 358 { 359 if (param->name) 360 OPENSSL_free(param->name); 361 param->name = BUF_strdup(name); 362 if (param->name) 363 return 1; 364 return 0; 365 } 366 367 int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) 368 { 369 param->flags |= flags; 370 if (flags & X509_V_FLAG_POLICY_MASK) 371 param->flags |= X509_V_FLAG_POLICY_CHECK; 372 return 1; 373 } 374 375 int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, 376 unsigned long flags) 377 { 378 param->flags &= ~flags; 379 return 1; 380 } 381 382 unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) 383 { 384 return param->flags; 385 } 386 387 int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) 388 { 389 return X509_PURPOSE_set(¶m->purpose, purpose); 390 } 391 392 int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) 393 { 394 return X509_TRUST_set(¶m->trust, trust); 395 } 396 397 void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) 398 { 399 param->depth = depth; 400 } 401 402 void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) 403 { 404 param->check_time = t; 405 param->flags |= X509_V_FLAG_USE_CHECK_TIME; 406 } 407 408 int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, 409 ASN1_OBJECT *policy) 410 { 411 if (!param->policies) { 412 param->policies = sk_ASN1_OBJECT_new_null(); 413 if (!param->policies) 414 return 0; 415 } 416 if (!sk_ASN1_OBJECT_push(param->policies, policy)) 417 return 0; 418 return 1; 419 } 420 421 int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, 422 STACK_OF(ASN1_OBJECT) *policies) 423 { 424 size_t i; 425 ASN1_OBJECT *oid, *doid; 426 if (!param) 427 return 0; 428 if (param->policies) 429 sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); 430 431 if (!policies) { 432 param->policies = NULL; 433 return 1; 434 } 435 436 param->policies = sk_ASN1_OBJECT_new_null(); 437 if (!param->policies) 438 return 0; 439 440 for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) { 441 oid = sk_ASN1_OBJECT_value(policies, i); 442 doid = OBJ_dup(oid); 443 if (!doid) 444 return 0; 445 if (!sk_ASN1_OBJECT_push(param->policies, doid)) { 446 ASN1_OBJECT_free(doid); 447 return 0; 448 } 449 } 450 param->flags |= X509_V_FLAG_POLICY_CHECK; 451 return 1; 452 } 453 454 int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, 455 const char *name, size_t namelen) 456 { 457 return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen); 458 } 459 460 int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, 461 const char *name, size_t namelen) 462 { 463 return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen); 464 } 465 466 void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, 467 unsigned int flags) 468 { 469 param->id->hostflags = flags; 470 } 471 472 char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) 473 { 474 return param->id->peername; 475 } 476 477 int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, 478 const char *email, size_t emaillen) 479 { 480 return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen, 481 email, emaillen); 482 } 483 484 int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, 485 const unsigned char *ip, size_t iplen) 486 { 487 if (iplen != 0 && iplen != 4 && iplen != 16) 488 return 0; 489 return int_x509_param_set1((char **)¶m->id->ip, ¶m->id->iplen, 490 (char *)ip, iplen); 491 } 492 493 int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) 494 { 495 unsigned char ipout[16]; 496 size_t iplen; 497 498 iplen = (size_t)a2i_ipadd(ipout, ipasc); 499 if (iplen == 0) 500 return 0; 501 return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); 502 } 503 504 int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) 505 { 506 return param->depth; 507 } 508 509 const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) 510 { 511 return param->name; 512 } 513 514 static const X509_VERIFY_PARAM_ID _empty_id = 515 { NULL, 0U, NULL, NULL, 0, NULL, 0 }; 516 517 #define vpm_empty_id ((X509_VERIFY_PARAM_ID *)&_empty_id) 518 519 /* 520 * Default verify parameters: these are used for various applications and can 521 * be overridden by the user specified table. NB: the 'name' field *must* be 522 * in alphabetical order because it will be searched using OBJ_search. 523 */ 524 525 static const X509_VERIFY_PARAM default_table[] = { 526 { 527 (char *)"default", /* X509 default parameters */ 528 0, /* Check time */ 529 0, /* internal flags */ 530 0, /* flags */ 531 0, /* purpose */ 532 0, /* trust */ 533 100, /* depth */ 534 NULL, /* policies */ 535 vpm_empty_id}, 536 { 537 (char *)"pkcs7", /* S/MIME sign parameters */ 538 0, /* Check time */ 539 0, /* internal flags */ 540 0, /* flags */ 541 X509_PURPOSE_SMIME_SIGN, /* purpose */ 542 X509_TRUST_EMAIL, /* trust */ 543 -1, /* depth */ 544 NULL, /* policies */ 545 vpm_empty_id}, 546 { 547 (char *)"smime_sign", /* S/MIME sign parameters */ 548 0, /* Check time */ 549 0, /* internal flags */ 550 0, /* flags */ 551 X509_PURPOSE_SMIME_SIGN, /* purpose */ 552 X509_TRUST_EMAIL, /* trust */ 553 -1, /* depth */ 554 NULL, /* policies */ 555 vpm_empty_id}, 556 { 557 (char *)"ssl_client", /* SSL/TLS client parameters */ 558 0, /* Check time */ 559 0, /* internal flags */ 560 0, /* flags */ 561 X509_PURPOSE_SSL_CLIENT, /* purpose */ 562 X509_TRUST_SSL_CLIENT, /* trust */ 563 -1, /* depth */ 564 NULL, /* policies */ 565 vpm_empty_id}, 566 { 567 (char *)"ssl_server", /* SSL/TLS server parameters */ 568 0, /* Check time */ 569 0, /* internal flags */ 570 0, /* flags */ 571 X509_PURPOSE_SSL_SERVER, /* purpose */ 572 X509_TRUST_SSL_SERVER, /* trust */ 573 -1, /* depth */ 574 NULL, /* policies */ 575 vpm_empty_id} 576 }; 577 578 static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; 579 580 static int param_cmp(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b) 581 { 582 return strcmp((*a)->name, (*b)->name); 583 } 584 585 int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) 586 { 587 X509_VERIFY_PARAM *ptmp; 588 if (!param_table) { 589 param_table = sk_X509_VERIFY_PARAM_new(param_cmp); 590 if (!param_table) 591 return 0; 592 } else { 593 size_t idx; 594 595 if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param)) { 596 ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); 597 X509_VERIFY_PARAM_free(ptmp); 598 (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); 599 } 600 } 601 if (!sk_X509_VERIFY_PARAM_push(param_table, param)) 602 return 0; 603 return 1; 604 } 605 606 int X509_VERIFY_PARAM_get_count(void) 607 { 608 int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); 609 if (param_table) 610 num += sk_X509_VERIFY_PARAM_num(param_table); 611 return num; 612 } 613 614 const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id) 615 { 616 int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); 617 if (id < num) 618 return default_table + id; 619 return sk_X509_VERIFY_PARAM_value(param_table, id - num); 620 } 621 622 const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) 623 { 624 X509_VERIFY_PARAM pm; 625 unsigned i, limit; 626 627 pm.name = (char *)name; 628 if (param_table) { 629 size_t idx; 630 if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm)) 631 return sk_X509_VERIFY_PARAM_value(param_table, idx); 632 } 633 634 limit = sizeof(default_table) / sizeof(X509_VERIFY_PARAM); 635 for (i = 0; i < limit; i++) { 636 if (strcmp(default_table[i].name, name) == 0) { 637 return &default_table[i]; 638 } 639 } 640 return NULL; 641 } 642 643 void X509_VERIFY_PARAM_table_cleanup(void) 644 { 645 if (param_table) 646 sk_X509_VERIFY_PARAM_pop_free(param_table, X509_VERIFY_PARAM_free); 647 param_table = NULL; 648 } 649