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