1 /* 2 * ==================================================================== 3 * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this 18 * software must display the following acknowledgment: 19 * "This product includes software developed by the OpenSSL Project 20 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 21 * 22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For written permission, please contact 25 * licensing@OpenSSL.org. 26 * 27 * 5. Products derived from this software may not be called "OpenSSL" 28 * nor may "OpenSSL" appear in their names without prior written 29 * permission of the OpenSSL Project. 30 * 31 * 6. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This product includes cryptographic software written by Eric Young 51 * (eay@cryptsoft.com). This product includes software written by Tim 52 * Hudson (tjh@cryptsoft.com). 53 * 54 */ 55 56 /* 57 * Copyright 2002, 2003 Sun Microsystems, Inc. All rights reserved. 58 * Use is subject to license terms. 59 * 60 * All of the functions included here are internal to the pkcs12 functions 61 * in this library. None of these are exposed. 62 */ 63 64 /* 65 * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved. 66 */ 67 68 #pragma ident "%Z%%M% %I% %E% SMI" 69 70 #include <stdio.h> 71 #include <string.h> 72 73 #include <openssl/crypto.h> 74 #include <openssl/err.h> 75 #include <openssl/x509.h> 76 77 #include <openssl/pkcs12.h> 78 #include <p12aux.h> 79 #include <auxutil.h> 80 #include <p12err.h> 81 82 /* 83 * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in 84 * ASN1_BMPSTRING format. 85 * 86 * Arguments: 87 * str - String to be convered. 88 * len - Length of the string. 89 * 90 * Returns: 91 * == NULL - An error occurred. Error information (accessible by 92 * ERR_get_error()) is set. 93 * != NULL - Points to an ASN1_BMPSTRING structure with the converted 94 * string as a value. 95 */ 96 ASN1_BMPSTRING * 97 asc2bmpstring(const char *str, int len) 98 { 99 ASN1_BMPSTRING *bmp = NULL; 100 uchar_t *uni = NULL; 101 int unilen; 102 103 /* Convert the character to the bmp format. */ 104 #if OPENSSL_VERSION_NUMBER < 0x10000000L 105 if (asc2uni(str, len, &uni, &unilen) == 0) { 106 #else 107 if (OPENSSL_asc2uni(str, len, &uni, &unilen) == 0) { 108 #endif 109 SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); 110 return (NULL); 111 } 112 113 /* 114 * Adjust for possible pair of NULL bytes at the end because 115 * asc2uni() returns a doubly null terminated string. 116 */ 117 if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0') 118 unilen -= 2; 119 120 /* Construct comparison string with correct format */ 121 bmp = M_ASN1_BMPSTRING_new(); 122 if (bmp == NULL) { 123 SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); 124 OPENSSL_free(uni); 125 return (NULL); 126 } 127 128 bmp->data = uni; 129 bmp->length = unilen; 130 131 return (bmp); 132 } 133 134 /* 135 * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string. 136 * This goes through an intermediate step with a ASN1_STRING type of 137 * IA5STRING (International Alphabet 5, which is the same as ASCII). 138 * 139 * Arguments: 140 * str - UTF8STRING to be converted. 141 * 142 * Returns: 143 * == NULL - An error occurred. Error information (accessible by 144 * ERR_get_error()) is set. 145 * != NULL - Points to a NULL-termianted ASCII string. The caller must 146 * free it. 147 */ 148 uchar_t * 149 utf82ascstr(ASN1_UTF8STRING *ustr) 150 { 151 ASN1_STRING tmpstr; 152 ASN1_STRING *astr = &tmpstr; 153 uchar_t *retstr = NULL; 154 int mbflag; 155 int ret; 156 157 if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) { 158 SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG); 159 return (NULL); 160 } 161 162 mbflag = MBSTRING_ASC; 163 tmpstr.data = NULL; 164 tmpstr.length = 0; 165 166 ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag, 167 B_ASN1_IA5STRING); 168 if (ret < 0) { 169 SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR); 170 return (NULL); 171 } 172 173 retstr = OPENSSL_malloc(astr->length + 1); 174 if (retstr == NULL) { 175 SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE); 176 return (NULL); 177 } 178 179 (void) memcpy(retstr, astr->data, astr->length); 180 retstr[astr->length] = '\0'; 181 OPENSSL_free(astr->data); 182 183 return (retstr); 184 } 185 186 /* 187 * set_results - Given two pointers to stacks of private keys, certs or CA 188 * CA certs, either copy the second stack to the first, or append the 189 * contents of the second to the first. 190 * 191 * Arguments: 192 * pkeys - Points to stack of pkeys 193 * work_kl - Points to working stack of pkeys 194 * certs - Points to stack of certs 195 * work_cl - Points to working stack of certs 196 * cacerts - Points to stack of CA certs 197 * work_ca - Points to working stack of CA certs 198 * xtrakeys - Points to stack of unmatcned pkeys 199 * work_xl - Points to working stack of unmatcned pkeys 200 * 201 * The arguments are in pairs. The first of each pair points to a stack 202 * of keys or certs. The second of the pair points at a 'working stack' 203 * of the same type of entities. Actions taken are as follows: 204 * 205 * - If either the first or second argument is NULL, or if there are no 206 * members in the second stack, there is nothing to do. 207 * - If the first argument points to a pointer which is NULL, then there 208 * is no existing stack for the first argument. Copy the stack pointer 209 * from the second argument to the first argument and NULL out the stack 210 * pointer for the second. 211 * - Otherwise, go through the elements of the second stack, removing each 212 * and adding it to the first stack. 213 * 214 * Returns: 215 * == -1 - An error occurred. Call ERR_get_error() to get error information. 216 * == 0 - No matching returns were found. 217 * > 0 - This is the arithmetic 'or' of the FOUND_* bits that indicate which 218 * of the requested entries were manipulated. 219 */ 220 int 221 set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl, 222 STACK_OF(X509) **certs, STACK_OF(X509) **work_cl, 223 STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca, 224 STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl) 225 { 226 int retval = 0; 227 228 if (pkeys != NULL && work_kl != NULL && *work_kl != NULL && 229 sk_EVP_PKEY_num(*work_kl) > 0) { 230 if (*pkeys == NULL) { 231 *pkeys = *work_kl; 232 *work_kl = NULL; 233 } else { 234 if (sunw_append_keys(*pkeys, *work_kl) < 0) { 235 return (-1); 236 } 237 } 238 retval |= FOUND_PKEY; 239 } 240 if (certs != NULL && work_cl != NULL && *work_cl != NULL && 241 sk_X509_num(*work_cl) > 0) { 242 if (*certs == NULL) { 243 *certs = *work_cl; 244 *work_cl = NULL; 245 } else { 246 if (move_certs(*certs, *work_cl) < 0) { 247 return (-1); 248 } 249 } 250 retval |= FOUND_CERT; 251 } 252 253 if (cacerts != NULL && work_ca != NULL && *work_ca != NULL && 254 sk_X509_num(*work_ca) > 0) { 255 if (*cacerts == NULL) { 256 *cacerts = *work_ca; 257 *work_ca = NULL; 258 } else { 259 if (move_certs(*cacerts, *work_ca) < 0) { 260 return (-1); 261 } 262 } 263 retval |= FOUND_CA_CERTS; 264 } 265 266 if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL && 267 sk_EVP_PKEY_num(*work_xl) > 0) { 268 if (*xtrakeys == NULL) { 269 *xtrakeys = *work_xl; 270 *work_xl = NULL; 271 } else { 272 if (sunw_append_keys(*xtrakeys, *work_xl) < 0) { 273 return (-1); 274 } 275 } 276 retval |= FOUND_XPKEY; 277 } 278 279 return (retval); 280 } 281 282 /* 283 * find_attr - Look for a given attribute of the type associated with the NID. 284 * 285 * Arguments: 286 * nid - NID for the attribute to be found (either NID_friendlyName or 287 * NID_locakKeyId) 288 * str - ASN1_STRING-type structure containing the value to be found, 289 * FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a 290 * ASN1_STRING. 291 * kl - Points to a stack of private keys. 292 * pkey - Points at a location where the address of the matching private 293 * key will be stored. 294 * cl - Points to a stack of client certs with matching private keys. 295 * cert - Points to locaiton where the address of the matching client cert 296 * will be returned 297 * 298 * This function is designed to process lists of certs and private keys. 299 * This is made complex because these the attributes are stored differently 300 * for certs and for keys. For certs, only a few attributes are retained. 301 * FriendlyName is stored in the aux structure, under the name 'alias'. 302 * LocalKeyId is also stored in the aux structure, under the name 'keyid'. 303 * A pkey structure has a stack of attributes. 304 * 305 * The basic approach is: 306 * - If there there is no stack of certs but a stack of private keys exists, 307 * search the stack of keys for a match. Alternately, if there is a stack 308 * of certs and no private keys, search the certs. 309 * 310 * - If there are both certs and keys, assume that the matching certs and 311 * keys are in their respective stacks, with matching entries in the same 312 * order. Search for the name or keyid in the stack of certs. If it is 313 * not found, then this function returns 0 (nothing found). 314 * 315 * - Once a cert is found, verify that the key actually matches by 316 * comparing the private key with the public key (in the cert). 317 * If they don't match, return an error. 318 * 319 * A pointer to cert and/or pkey which matches the name or keyid is stored 320 * in the return arguments. 321 * 322 * Returns: 323 * 0 - No matches were found. 324 * > 0 - Bits set based on FOUND_* definitions, indicating what was found. 325 * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). 326 */ 327 int 328 find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, 329 STACK_OF(X509) *cl, X509 **cert) 330 { 331 ASN1_UTF8STRING *ustr = NULL; 332 ASN1_STRING *s; 333 ASN1_TYPE *t; 334 EVP_PKEY *p; 335 uchar_t *fname = NULL; 336 X509 *x; 337 int found = 0; 338 int chkcerts; 339 int len; 340 int res; 341 int c = -1; 342 int k = -1; 343 344 chkcerts = (cert != NULL || pkey != NULL) && cl != NULL; 345 if (chkcerts && nid == NID_friendlyName && 346 str->type == V_ASN1_BMPSTRING) { 347 ustr = ASN1_UTF8STRING_new(); 348 if (ustr == NULL) { 349 SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); 350 return (0); 351 } 352 len = ASN1_STRING_to_UTF8(&fname, str); 353 if (fname == NULL) { 354 ASN1_UTF8STRING_free(ustr); 355 SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR); 356 return (0); 357 } 358 359 if (ASN1_STRING_set(ustr, fname, len) == 0) { 360 ASN1_UTF8STRING_free(ustr); 361 OPENSSL_free(fname); 362 SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); 363 return (0); 364 } 365 } 366 367 if (chkcerts) { 368 for (c = 0; c < sk_X509_num(cl); c++) { 369 res = -1; 370 x = sk_X509_value(cl, c); 371 if (nid == NID_friendlyName && ustr != NULL) { 372 if (x->aux == NULL || x->aux->alias == NULL) 373 continue; 374 s = x->aux->alias; 375 if (s != NULL && s->type == ustr->type && 376 s->data != NULL) { 377 res = ASN1_STRING_cmp(s, ustr); 378 } 379 } else { 380 if (x->aux == NULL || x->aux->keyid == NULL) 381 continue; 382 s = x->aux->keyid; 383 if (s != NULL && s->type == str->type && 384 s->data != NULL) { 385 res = ASN1_STRING_cmp(s, str); 386 } 387 } 388 if (res == 0) { 389 if (cert != NULL) 390 *cert = sk_X509_delete(cl, c); 391 found = FOUND_CERT; 392 break; 393 } 394 } 395 if (ustr != NULL) { 396 ASN1_UTF8STRING_free(ustr); 397 OPENSSL_free(fname); 398 } 399 } 400 401 if (pkey != NULL && kl != NULL) { 402 /* 403 * Looking for pkey to match a cert? If so, assume that 404 * lists of certs and their matching pkeys are in the same 405 * order. Call X509_check_private_key() to verify this 406 * assumption. 407 */ 408 if (found != 0 && cert != NULL) { 409 k = c; 410 p = sk_EVP_PKEY_value(kl, k); 411 if (X509_check_private_key(x, p) != 0) { 412 if (pkey != NULL) 413 *pkey = sk_EVP_PKEY_delete(kl, k); 414 found |= FOUND_PKEY; 415 } 416 } else if (cert == NULL) { 417 for (k = 0; k < sk_EVP_PKEY_num(kl); k++) { 418 p = sk_EVP_PKEY_value(kl, k); 419 if (p == NULL || p->attributes == NULL) 420 continue; 421 422 t = PKCS12_get_attr_gen(p->attributes, nid); 423 if (t != NULL || ASN1_STRING_cmp(str, 424 t->value.asn1_string) == 0) 425 continue; 426 427 found |= FOUND_PKEY; 428 if (pkey != NULL) 429 *pkey = sk_EVP_PKEY_delete(kl, k); 430 break; 431 } 432 } 433 } 434 435 return (found); 436 } 437 438 /* 439 * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE 440 * of the type specified by the given NID. 441 * 442 * Arguments: 443 * attrs - Stack of attributes to search 444 * nid - NID of the attribute being searched for 445 * 446 * Returns: 447 * -1 None found 448 * != -1 Offset of the matching attribute. 449 */ 450 int 451 find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid) 452 { 453 X509_ATTRIBUTE *a; 454 int i; 455 456 if (attrs == NULL) 457 return (-1); 458 459 for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) { 460 a = sk_X509_ATTRIBUTE_value(attrs, i); 461 if (OBJ_obj2nid(a->object) == nid) 462 return (i); 463 } 464 return (-1); 465 } 466 467 /* 468 * get_key_cert - Get a cert and its matching key from the stacks of certs 469 * and keys. They are removed from the stacks. 470 * 471 * Arguments: 472 * n - Offset of the entries to return. 473 * kl - Points to a stack of private keys that matches the list of 474 * certs below. 475 * pkey - Points at location where the address of the matching private 476 * key will be stored. 477 * cl - Points to a stack of client certs with matching private keys. 478 * cert - Points to locaiton where the address of the matching client cert 479 * will be returned 480 * 481 * The assumption is that the stacks of keys and certs contain key/cert pairs, 482 * with entries in the same order and hence at the same offset. Provided 483 * the key and cert selected match, each will be removed from its stack and 484 * returned. 485 * 486 * A stack of certs can be passed in without a stack of private keys, and vise 487 * versa. In that case, the indicated key/cert will be returned. 488 * 489 * Returns: 490 * 0 - No matches were found. 491 * > 0 - Bits set based on FOUND_* definitions, indicating what is returned. 492 * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). 493 */ 494 int 495 get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl, 496 X509 **cert) 497 { 498 int retval = 0; 499 int nk; 500 int nc; 501 502 nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0; 503 nc = (cl != NULL) ? sk_X509_num(cl) : 0; 504 505 if (pkey != NULL && *pkey == NULL) { 506 if (nk > 0 && n >= 0 || n < nk) { 507 *pkey = sk_EVP_PKEY_delete(kl, n); 508 if (*pkey != NULL) 509 retval |= FOUND_PKEY; 510 } 511 } 512 513 if (cert != NULL && *cert == NULL) { 514 if (nc > 0 && n >= 0 && n < nc) { 515 *cert = sk_X509_delete(cl, n); 516 if (*cert != NULL) 517 retval |= FOUND_CERT; 518 } 519 } 520 521 return (retval); 522 } 523 524 /* 525 * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type 526 * specified by the given NID. 527 * 528 * Arguments: 529 * ty - Type structure to be made into an attribute 530 * nid - NID of the attribute 531 * 532 * Returns: 533 * NULL An error occurred. 534 * != NULL An X509_ATTRIBUTE structure. 535 */ 536 X509_ATTRIBUTE * 537 type2attrib(ASN1_TYPE *ty, int nid) 538 { 539 X509_ATTRIBUTE *a; 540 541 if ((a = X509_ATTRIBUTE_new()) == NULL || 542 (a->value.set = sk_ASN1_TYPE_new_null()) == NULL || 543 sk_ASN1_TYPE_push(a->value.set, ty) == 0) { 544 if (a != NULL) 545 X509_ATTRIBUTE_free(a); 546 SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE); 547 return (NULL); 548 } 549 a->single = 0; 550 a->object = OBJ_nid2obj(nid); 551 552 return (a); 553 } 554 555 /* 556 * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE 557 * component 558 * 559 * Arguments: 560 * attr - Attribute structure containing a type. 561 * 562 * Returns: 563 * NULL An error occurred. 564 * != NULL An ASN1_TYPE structure. 565 */ 566 ASN1_TYPE * 567 attrib2type(X509_ATTRIBUTE *attr) 568 { 569 ASN1_TYPE *ty = NULL; 570 571 if (attr == NULL || attr->single == 1) 572 return (NULL); 573 574 if (sk_ASN1_TYPE_num(attr->value.set) > 0) 575 ty = sk_ASN1_TYPE_value(attr->value.set, 0); 576 577 return (ty); 578 } 579 580 /* 581 * move_certs - Given two stacks of certs, remove the certs from 582 * the second stack and append them to the first. 583 * 584 * Arguments: 585 * dst - the stack to receive the certs from 'src' 586 * src - the stack whose certs are to be moved. 587 * 588 * Returns: 589 * -1 - An error occurred. The error status is set. 590 * >= 0 - The number of certs that were copied. 591 */ 592 int 593 move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src) 594 { 595 X509 *tmpc; 596 int count = 0; 597 598 while (sk_X509_num(src) > 0) { 599 tmpc = sk_X509_delete(src, 0); 600 if (sk_X509_push(dst, tmpc) == 0) { 601 X509_free(tmpc); 602 SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE); 603 return (-1); 604 } 605 count++; 606 } 607 608 return (count); 609 } 610 611 /* 612 * print_time - Given an ASN1_TIME, print one or both of the times. 613 * 614 * Arguments: 615 * fp - File to write to 616 * t - The time to format and print. 617 * 618 * Returns: 619 * 0 - Error occurred while opening or writing. 620 * > 0 - Success. 621 */ 622 int 623 print_time(FILE *fp, ASN1_TIME *t) 624 { 625 BIO *bp; 626 int ret = 1; 627 628 if ((bp = BIO_new(BIO_s_file())) == NULL) { 629 return (0); 630 } 631 632 (void) BIO_set_fp(bp, fp, BIO_NOCLOSE); 633 ret = ASN1_TIME_print(bp, t); 634 (void) BIO_free(bp); 635 636 return (ret); 637 } 638