2 * ====================================================================
3 * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
31 * 6. Redistributions of any form whatsoever must retain the following
33 * "This product includes software developed by the OpenSSL Project
34 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
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 * ====================================================================
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).
57 * Copyright 2002, 2003 Sun Microsystems, Inc. All rights reserved.
58 * Use is subject to license terms.
60 * All of the functions included here are internal to the pkcs12 functions
61 * in this library. None of these are exposed.
65 * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
68 #pragma ident "%Z%%M% %I% %E% SMI"
73 #include <openssl/crypto.h>
74 #include <openssl/err.h>
75 #include <openssl/x509.h>
77 #include <openssl/pkcs12.h>
83 * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in
84 * ASN1_BMPSTRING format.
87 * str - String to be convered.
88 * len - Length of the string.
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
97 asc2bmpstring(const char *str
, int len
)
99 ASN1_BMPSTRING
*bmp
= NULL
;
103 /* Convert the character to the bmp format. */
104 #if OPENSSL_VERSION_NUMBER < 0x10000000L
105 if (asc2uni(str
, len
, &uni
, &unilen
) == 0) {
107 if (OPENSSL_asc2uni(str
, len
, &uni
, &unilen
) == 0) {
109 SUNWerr(SUNW_F_ASC2BMPSTRING
, SUNW_R_MEMORY_FAILURE
);
114 * Adjust for possible pair of NULL bytes at the end because
115 * asc2uni() returns a doubly null terminated string.
117 if (uni
[unilen
- 1] == '\0' && uni
[unilen
- 2] == '\0')
120 /* Construct comparison string with correct format */
121 bmp
= M_ASN1_BMPSTRING_new();
123 SUNWerr(SUNW_F_ASC2BMPSTRING
, SUNW_R_MEMORY_FAILURE
);
129 bmp
->length
= unilen
;
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).
140 * str - UTF8STRING to be converted.
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
149 utf82ascstr(ASN1_UTF8STRING
*ustr
)
152 ASN1_STRING
*astr
= &tmpstr
;
153 uchar_t
*retstr
= NULL
;
157 if (ustr
== NULL
|| ustr
->type
!= V_ASN1_UTF8STRING
) {
158 SUNWerr(SUNW_F_UTF82ASCSTR
, SUNW_R_INVALID_ARG
);
162 mbflag
= MBSTRING_ASC
;
166 ret
= ASN1_mbstring_copy(&astr
, ustr
->data
, ustr
->length
, mbflag
,
169 SUNWerr(SUNW_F_UTF82ASCSTR
, SUNW_R_STR_CONVERT_ERR
);
173 retstr
= OPENSSL_malloc(astr
->length
+ 1);
174 if (retstr
== NULL
) {
175 SUNWerr(SUNW_F_UTF82ASCSTR
, SUNW_R_MEMORY_FAILURE
);
179 (void) memcpy(retstr
, astr
->data
, astr
->length
);
180 retstr
[astr
->length
] = '\0';
181 OPENSSL_free(astr
->data
);
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.
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
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:
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.
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.
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
)
228 if (pkeys
!= NULL
&& work_kl
!= NULL
&& *work_kl
!= NULL
&&
229 sk_EVP_PKEY_num(*work_kl
) > 0) {
230 if (*pkeys
== NULL
) {
234 if (sunw_append_keys(*pkeys
, *work_kl
) < 0) {
238 retval
|= FOUND_PKEY
;
240 if (certs
!= NULL
&& work_cl
!= NULL
&& *work_cl
!= NULL
&&
241 sk_X509_num(*work_cl
) > 0) {
242 if (*certs
== NULL
) {
246 if (move_certs(*certs
, *work_cl
) < 0) {
250 retval
|= FOUND_CERT
;
253 if (cacerts
!= NULL
&& work_ca
!= NULL
&& *work_ca
!= NULL
&&
254 sk_X509_num(*work_ca
) > 0) {
255 if (*cacerts
== NULL
) {
259 if (move_certs(*cacerts
, *work_ca
) < 0) {
263 retval
|= FOUND_CA_CERTS
;
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
;
272 if (sunw_append_keys(*xtrakeys
, *work_xl
) < 0) {
276 retval
|= FOUND_XPKEY
;
283 * find_attr - Look for a given attribute of the type associated with the NID.
286 * nid - NID for the attribute to be found (either NID_friendlyName or
288 * str - ASN1_STRING-type structure containing the value to be found,
289 * FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a
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
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.
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.
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).
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.
319 * A pointer to cert and/or pkey which matches the name or keyid is stored
320 * in the return arguments.
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).
328 find_attr(int nid
, ASN1_STRING
*str
, STACK_OF(EVP_PKEY
) *kl
, EVP_PKEY
**pkey
,
329 STACK_OF(X509
) *cl
, X509
**cert
)
331 ASN1_UTF8STRING
*ustr
= NULL
;
335 uchar_t
*fname
= NULL
;
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();
349 SUNWerr(SUNW_F_FINDATTR
, SUNW_R_MEMORY_FAILURE
);
352 len
= ASN1_STRING_to_UTF8(&fname
, str
);
354 ASN1_UTF8STRING_free(ustr
);
355 SUNWerr(SUNW_F_FINDATTR
, SUNW_R_STR_CONVERT_ERR
);
359 if (ASN1_STRING_set(ustr
, fname
, len
) == 0) {
360 ASN1_UTF8STRING_free(ustr
);
362 SUNWerr(SUNW_F_FINDATTR
, SUNW_R_MEMORY_FAILURE
);
368 for (c
= 0; c
< sk_X509_num(cl
); c
++) {
370 x
= sk_X509_value(cl
, c
);
371 if (nid
== NID_friendlyName
&& ustr
!= NULL
) {
372 if (x
->aux
== NULL
|| x
->aux
->alias
== NULL
)
375 if (s
!= NULL
&& s
->type
== ustr
->type
&&
377 res
= ASN1_STRING_cmp(s
, ustr
);
380 if (x
->aux
== NULL
|| x
->aux
->keyid
== NULL
)
383 if (s
!= NULL
&& s
->type
== str
->type
&&
385 res
= ASN1_STRING_cmp(s
, str
);
390 *cert
= sk_X509_delete(cl
, c
);
396 ASN1_UTF8STRING_free(ustr
);
401 if (pkey
!= NULL
&& kl
!= NULL
) {
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
408 if (found
!= 0 && cert
!= NULL
) {
410 p
= sk_EVP_PKEY_value(kl
, k
);
411 if (X509_check_private_key(x
, p
) != 0) {
413 *pkey
= sk_EVP_PKEY_delete(kl
, k
);
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
)
422 t
= PKCS12_get_attr_gen(p
->attributes
, nid
);
423 if (t
!= NULL
|| ASN1_STRING_cmp(str
,
424 t
->value
.asn1_string
) == 0)
429 *pkey
= sk_EVP_PKEY_delete(kl
, k
);
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.
443 * attrs - Stack of attributes to search
444 * nid - NID of the attribute being searched for
448 * != -1 Offset of the matching attribute.
451 find_attr_by_nid(STACK_OF(X509_ATTRIBUTE
) *attrs
, int nid
)
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
)
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.
472 * n - Offset of the entries to return.
473 * kl - Points to a stack of private keys that matches the list of
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
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
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.
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).
495 get_key_cert(int n
, STACK_OF(EVP_PKEY
) *kl
, EVP_PKEY
**pkey
, STACK_OF(X509
) *cl
,
502 nk
= (kl
!= NULL
) ? sk_EVP_PKEY_num(kl
) : 0;
503 nc
= (cl
!= NULL
) ? sk_X509_num(cl
) : 0;
505 if (pkey
!= NULL
&& *pkey
== NULL
) {
506 if (nk
> 0 && n
>= 0 || n
< nk
) {
507 *pkey
= sk_EVP_PKEY_delete(kl
, n
);
509 retval
|= FOUND_PKEY
;
513 if (cert
!= NULL
&& *cert
== NULL
) {
514 if (nc
> 0 && n
>= 0 && n
< nc
) {
515 *cert
= sk_X509_delete(cl
, n
);
517 retval
|= FOUND_CERT
;
525 * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type
526 * specified by the given NID.
529 * ty - Type structure to be made into an attribute
530 * nid - NID of the attribute
533 * NULL An error occurred.
534 * != NULL An X509_ATTRIBUTE structure.
537 type2attrib(ASN1_TYPE
*ty
, int nid
)
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) {
545 X509_ATTRIBUTE_free(a
);
546 SUNWerr(SUNW_F_TYPE2ATTRIB
, SUNW_R_MEMORY_FAILURE
);
550 a
->object
= OBJ_nid2obj(nid
);
556 * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE
560 * attr - Attribute structure containing a type.
563 * NULL An error occurred.
564 * != NULL An ASN1_TYPE structure.
567 attrib2type(X509_ATTRIBUTE
*attr
)
569 ASN1_TYPE
*ty
= NULL
;
571 if (attr
== NULL
|| attr
->single
== 1)
574 if (sk_ASN1_TYPE_num(attr
->value
.set
) > 0)
575 ty
= sk_ASN1_TYPE_value(attr
->value
.set
, 0);
581 * move_certs - Given two stacks of certs, remove the certs from
582 * the second stack and append them to the first.
585 * dst - the stack to receive the certs from 'src'
586 * src - the stack whose certs are to be moved.
589 * -1 - An error occurred. The error status is set.
590 * >= 0 - The number of certs that were copied.
593 move_certs(STACK_OF(X509
) *dst
, STACK_OF(X509
) *src
)
598 while (sk_X509_num(src
) > 0) {
599 tmpc
= sk_X509_delete(src
, 0);
600 if (sk_X509_push(dst
, tmpc
) == 0) {
602 SUNWerr(SUNW_F_MOVE_CERTS
, SUNW_R_MEMORY_FAILURE
);
612 * print_time - Given an ASN1_TIME, print one or both of the times.
615 * fp - File to write to
616 * t - The time to format and print.
619 * 0 - Error occurred while opening or writing.
623 print_time(FILE *fp
, ASN1_TIME
*t
)
628 if ((bp
= BIO_new(BIO_s_file())) == NULL
) {
632 (void) BIO_set_fp(bp
, fp
, BIO_NOCLOSE
);
633 ret
= ASN1_TIME_print(bp
, t
);