/*
* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
*/
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#include "p12lib.h"
/*
* OpenSSL provides a framework for pushing error codes onto a stack.
* When an error occurs, the consumer may use the framework to
* pop the errors off the stack and provide a trace of where the
* errors occurred.
*
* Our PKCS12 code plugs into this framework by calling
* ERR_load_SUNW_strings(). To push an error (which by the way, consists
* of a function code and an error code) onto the stack our PKCS12 code
* calls SUNWerr().
*
* Consumers of our PKCS12 code can then call the OpenSSL error routines
* when an error occurs and retrieve the stack of errors.
*/
#ifndef OPENSSL_NO_ERR
/* Function codes and their matching strings */
{ 0, NULL }
};
/* Error codes and their matching strings */
{ SUNW_R_INVALID_ARG, "invalid argument" },
{ SUNW_R_MEMORY_FAILURE, "memory failure" },
{ SUNW_R_MAC_VERIFY_FAILURE, "mac verify failure" },
{ SUNW_R_MAC_CREATE_FAILURE, "mac create failure" },
{ SUNW_R_BAD_FILETYPE, "bad file type" },
{ SUNW_R_BAD_PKEY, "bad or missing private key" },
{ SUNW_R_BAD_PKEYTYPE, "unsupported key type" },
{ SUNW_R_PKEY_READ_ERR, "unable to read private key" },
{ SUNW_R_NO_TRUST_ANCHOR, "no trust anchors found" },
{ SUNW_R_READ_TRUST_ERR, "unable to read trust anchor" },
{ SUNW_R_ADD_TRUST_ERR, "unable to add trust anchor" },
{ SUNW_R_PKCS12_PARSE_ERR, "PKCS12 parse error" },
{ SUNW_R_PKCS12_CREATE_ERR, "PKCS12 create error" },
{ SUNW_R_BAD_CERTTYPE, "unsupported certificate type" },
{ SUNW_R_PARSE_CERT_ERR, "error parsing PKCS12 certificate" },
{ SUNW_R_PARSE_BAG_ERR, "error parsing PKCS12 bag" },
{ SUNW_R_MAKE_BAG_ERR, "error making PKCS12 bag" },
{ SUNW_R_BAD_LKID, "bad localKeyID format" },
{ SUNW_R_SET_LKID_ERR, "error setting localKeyID" },
{ SUNW_R_BAD_FNAME, "bad friendlyName format" },
{ SUNW_R_SET_FNAME_ERR, "error setting friendlyName" },
{ SUNW_R_BAD_TRUST, "bad or missing trust anchor" },
{ SUNW_R_BAD_BAGTYPE, "unsupported bag type" },
{ SUNW_R_CERT_ERR, "certificate error" },
{ SUNW_R_PKEY_ERR, "private key error" },
{ SUNW_R_READ_ERR, "error reading file" },
{ SUNW_R_ADD_ATTR_ERR, "error adding attribute" },
{ SUNW_R_STR_CONVERT_ERR, "error converting string" },
{ SUNW_R_PKCS12_EMPTY_ERR, "empty PKCS12 structure" },
{ SUNW_R_PASSWORD_ERR, "bad password" },
{ 0, NULL }
};
/*
* The library name that our module will be known as. This name
* may be retrieved via OpenSSLs error APIs.
*/
{ 0, SUNW_LIB_NAME },
{ 0, NULL }
};
#endif
/*
* The value of this variable (initialized by a call to
* ERR_load_SUNW_strings()) is what identifies our errors
* to OpenSSL as being ours.
*/
static int SUNW_lib_error_code = 0;
/* local routines */
static int parse_pkcs12(PKCS12 *, const char *, int, char *, int, char *,
static int parse_one_bag(PKCS12_SAFEBAG *, const char *,
static ASN1_BMPSTRING *asc2bmpstring(const char *, int);
/*
* ----------------------------------------------------------------------------
* Public routines
* ----------------------------------------------------------------------------
*/
/*
* sunw_PKCS12_parse - Parse a PKCS12 structure and break it into its parts.
*
* other (CA) certs. Note either ca should be NULL, *ca should be NULL,
* or it should point to a valid STACK_OF(X509) structure. pkey and cert can
* be passed uninitialized.
*
* Arguments:
* p12 - Structure with pkcs12 info to be parsed
* pass - Pass phrase for the private key (possibly empty) or NULL if
* there is none.
* keyid - If private key localkeyids friendlynames are to match a
* predetermined value, the value to match. This value should
* be an octet string.
* keyid_len- Length of the keyid byte string.
* name_str - If friendlynames are to match a predetermined value, the value
* to match. This value should be a NULL terminated string.
* pkey - Points to location pointing to the private key returned.
* cert - Points to locaiton which points to the client cert returned
* ca - Points to location that points to a stack of 'certificate
*
* Match based on the value of 'matchty' and the contents of 'keyid'
* private keys which were taken from the pkcs12 structure, looking for
* matches of the requested type. This function only searches the lists of
* matching private keys and client certificates. Kinds of matches allowed,
* and the order in which they will be checked, are:
*
* 'keyid'.
* 'name_str'
*
* Append to the CA list, the certs which do not have matching private
* keys and which were not selected.
*
* If none of the bits are set, no client certs or private keys will be
* returned. CA (aka trust anchor) certs can be.
*
* Notes: If #3 is selected, then #4 will never occur. CA certs will be
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - Objects were found and returned. Which objects are indicated by
* which bits are set (FOUND_PKEY, FOUND_CERT, FOUND_CA_CERTS).
*/
int
{
/* If NULL PKCS12 structure, this is an error */
return (-1);
}
/* Set up arguments.... These will be allocated if needed */
if (pkey)
if (cert)
/*
* If there is already a ca list, use it. Otherwise, allocate one
* and free is later if an error occurs or whatever.)
*/
return (-1);
}
}
/*
* If password is zero length or NULL then try verifying both cases
* to determine which password is correct. The reason for this is that
* under PKCS#12 password based encryption no password and a zero
* length password are two different things. If the password has a
* non-zero length and is not NULL then call PKCS12_verify_mac() with
* a length of '-1' and let it use strlen() to figure out the length
* of the password.
*/
/* Check the mac */
pass = "";
else {
goto err;
}
goto err;
}
if (retval < 0) {
goto err;
}
return (retval);
err:
}
return (-1);
}
/*
* sunw_PEM_contents() parses a PEM file and returns component parts found
*
* Parse and decrypt a PEM file, returning any user keys and certs.
*
* There are some limits to this function. It will ignore the following:
* - certificates identified by "TRUSTED CERTIFICATE"
* - CERTIFICATE REQUEST and NEW CERTIFICATE REQUEST records.
* - X509 CRL
* - DH PARAMETERS
* - DSA PARAMETERS
* - Any PUBLIC KEY
* - PKCS7
* - PRIVATE KEY or ENCRYPTED PRIVATE KEY (PKCS 8)
*
* Arguments:
* fp - File pointer for file containing PEM data.
* pass - Pass phrase for the private key or NULL if there is none.
* pkeys - Points to address of a stack of private keys to return.
* certs - Points to address of a stack of client certs to return.
*
* The pointers to stacks should either be NULL or their contents should
* either be NULL or should point to a valid STACK_OF(X509) structure.
* If the stacks contain information, corresponding information from the
* file will be appended to the original contents.
*
* Note: Client certs and and their matching private keys will be in any
* order.
*
* Certs which have no matching private key are assumed to be ca certs.
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - Objects were found and returned. Which objects are indicated by
* which bits are set (FOUND_PKEY, FOUND_CERT)
*/
{
/*
* Allocate the working stacks for private key and for the
* ca certs.
*/
goto cleanup;
}
goto cleanup;
}
/* Error strings are set within the following. */
goto cleanup;
}
/* on error, set_results() returns an error on the stack */
NULL);
}
return (retval);
}
/*
* sunw_PKCS12_contents() parses a pkcs#12 structure and returns component
* parts found, without evaluation.
*
* various certs. Note these should either be NULL, *whatever should
* be NULL, or it should point to a valid STACK_OF(X509) structure.
*
* Arguments:
* p12 - Structure with pkcs12 info to be parsed
* pass - Pass phrase for the private key and entire pkcs12 wad (possibly
* empty) or NULL if there is none.
* pkeys - Points to address of a stack of private keys to return.
* certs - Points to address of a stack of client certs return.
*
* Note: The certs and keys being returned are in random order.
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - Objects were found and returned. Which objects are indicated by
* which bits are set (FOUND_PKEY or FOUND_CERT)
*/
int
{
/*
* Allocate the working stacks for private key and for the
* ca certs.
*/
goto cleanup;
}
goto cleanup;
}
/*
* Error already on stack
*/
goto cleanup;
}
/* on error, set_results() returns an error on the stack */
}
return (retval);
}
/*
* sunw_split_certs() - Given a list of certs and a list of private keys,
* moves certs which match one of the keys to a different stack.
*
* Arguments:
* allkeys - Points to a stack of private keys to search.
* allcerts - Points to a stack of certs to be searched.
* keycerts - Points to address of a stack of certs with matching private
* keys. They are moved from 'allcerts'. This may not be NULL
* when called. If *keycerts is NULL upon entry, a new stack will
* be allocated. Otherwise, it must be a valid STACK_OF(509).
* nocerts - Points to address of a stack for keys which have no matching
* certs. Keys are moved from 'allkeys' here when they have no
* matching certs. If this is NULL, matchless keys will be
* discarded.
*
* Notes: If an error occurs while moving certs, the cert being move may be
* lost. 'keycerts' may only contain part of the matching certs. The number
* of certs successfully moved can be found by checking sk_X509_num(keycerts).
*
* If there is a key which does not have a matching cert, it is moved to
* the list nocerts.
*
* caller's responsibility to free the empty stacks.
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - The number of certs moved from 'cert' to 'pkcerts'.
*/
int
{
int count = 0;
int found;
int res;
int i;
int k;
return (-1);
}
k = 0;
while (k < sk_EVP_PKEY_num(allkeys)) {
found = 0;
for (i = 0; i < sk_X509_num(allcerts); i++) {
if (res != 0) {
count++;
found = 1;
return (-1);
}
break;
}
}
if (found != 0) {
/*
* Found a match - keep the key & check out the next
* one.
*/
k++;
} else {
/*
* No cert matching this key. Move the key if
* possible or discard it. Don't increment the
* index.
*/
} else {
return (-1);
}
}
return (-1);
}
}
}
}
return (count);
}
/*
* sunw_PKCS12_create() creates a pkcs#12 structure and given component parts.
*
* return an encrypted PKCS12 structure containing them.
*
* Arguments:
* pass - Pass phrase for the pkcs12 structure and private key (possibly
* empty) or NULL if there is none. It will be used to encrypt
* both the private key(s) and as the pass phrase for the whole
* pkcs12 wad.
* pkeys - Points to stack of private keys.
* certs - Points to stack of client (public ke) certs
* cacerts - Points to stack of 'certificate authority' certs (or trust
* anchors).
*
* Note that any of these may be NULL.
*
* Returns:
* NULL - An error occurred.
* != NULL - Address of PKCS12 structure. The user is responsible for
* freeing the memory when done.
*/
PKCS12 *
{
int certs_there = 0;
int keys_there = 0;
int len;
int i;
return (NULL);
}
goto err_ret;
}
for (i = 0; i < sk_X509_num(certs); i++) {
/* Add user certificate */
goto err_ret;
}
/*
* Error already on stack
*/
goto err_ret;
}
(char const *) str,
goto err_ret;
}
}
goto err_ret;
}
}
goto err_ret;
}
certs_there++;
}
}
/* Put all certs in structure */
for (i = 0; i < sk_X509_num(cacerts); i++) {
goto err_ret;
}
/*
* Error already on stack
*/
goto err_ret;
}
goto err_ret;
}
}
goto err_ret;
}
}
goto err_ret;
}
certs_there++;
}
}
/* Turn certbags into encrypted authsafe */
goto err_ret;
}
goto err_ret;
}
}
goto err_ret;
}
for (i = 0; i < sk_EVP_PKEY_num(pkeys); i++) {
/* Make a shrouded key bag */
goto err_ret;
}
goto err_ret;
}
(char **)&str);
goto err_ret;
}
}
goto err_ret;
}
}
goto err_ret;
}
keys_there++;
}
if (keys_there) {
/* Turn into unencrypted authsafe */
goto err_ret;
}
}
}
}
if (certs_there == 0 && keys_there == 0) {
goto err_ret;
}
goto err_ret;
}
/*
* Note that safes is copied by the following. Therefore, it needs
* to be freed whether or not the following succeeds.
*/
goto err_ret;
}
goto err_ret;
}
/* Fallthrough is intentional */
return (ret_p12);
}
/*
* sunw_evp_pkey_free() Given an EVP_PKEY structure, free any attributes
* that are attached. Then free the EVP_PKEY itself.
*
* This is a replacement for EVP_PKEY_free() for the sunw stuff.
* It should be used in places where EVP_PKEY_free would be used,
* including calls to sk_EVP_PKEY_pop_free().
*
* Arguments:
* pkey - Entry which potentially has attributes to be freed.
*
* Returns:
* None.
*/
void
{
}
}
}
/*
* sunw_set_localkeyid() sets the localkeyid in a cert, a private key or
* both. Any existing localkeyid will be discarded.
*
* Arguments:
* keyid_str- A byte string with the localkeyid to set
* keyid_len- Length of the keyid byte string.
* pkey - Points to a private key to set the keyidstr in.
* cert - Points to a cert to set the keyidstr in.
*
* Note that setting a keyid into a cert which will not be written out as
* a PKCS12 cert is pointless since it will be lost.
*
* Returns:
* 0 - Success.
* < 0 - An error occurred. It was probably an error in allocating
* memory. The error will be set in the error stack. Call
* ERR_get_error() to get specific information.
*/
int
{
int i;
== 0) {
goto cleanup;
}
}
goto cleanup;
}
/*
* Error already on stack
*/
goto cleanup;
}
goto cleanup;
}
} else {
if (i >= 0)
}
goto cleanup;
}
}
retval = 0;
return (retval);
}
/*
* sunw_get_pkey_localkeyid() gets the localkeyid from a private key. It can
* optionally remove the value found.
*
* Arguments:
* dowhat - What to do with the attributes (remove them or copy them).
* pkey - Points to a private key to set the keyidstr in.
* keyid_str- Points to a location which will receive the pointer to
* a byte string containing the binary localkeyid. Note that
* this is a copy, and the caller must free it.
* keyid_len- Length of keyid_str.
*
* Returns:
* >= 0 - The number of characters in the keyid returned.
* < 0 - An error occurred. It was probably an error in allocating
* memory. The error will be set in the error stack. Call
* ERR_get_error() to get specific information.
*/
int
{
int len = 0;
int i;
*keyid_len = 0;
return (0);
}
return (0);
}
return (0);
}
return (0);
}
return (-1);
}
return (len);
}
/*
* sunw_get_pkey_fname() gets the friendlyName from a private key. It can
* optionally remove the value found.
*
* Arguments:
* dowhat - What to do with the attributes (remove them or copy them).
* pkey - Points to a private key to get the frientlyname from
* fname - Points to a location which will receive the pointer to a
* byte string with the ASCII friendlyname
*
* Returns:
* >= 0 - The number of characters in the frienlyname returned.
* < 0 - An error occurred. It was probably an error in allocating
* memory. The error will be set in the error stack. Call
* ERR_get_error() to get specific information.
*/
int
{
int len = 0;
int i;
return (0);
}
return (0);
}
return (0);
}
return (0);
}
#if OPENSSL_VERSION_NUMBER < 0x10000000L
#else
#endif
return (-1);
}
return (len);
}
/*
* sunw_find_localkeyid() searches stacks of certs and private keys,
*
* Look for a keyid in a stack of certs. if 'certs' is NULL and 'pkeys' is
* not NULL, search the list of private keys. Move the matching cert to
* 'matching_cert' and its matching private key to 'matching_pkey'. If no
* cert or keys match, no match occurred.
*
* Arguments:
* keyid_str- A byte string with the localkeyid to match
* keyid_len- Length of the keyid byte string.
* pkeys - Points to a stack of private keys which match the certs.
* This may be NULL, in which case no keys are returned.
* certs - Points to a stack of certs to search. If NULL, search the
* stack of keys instead.
* matching_pkey
* - Pointer to receive address of first matching pkey found.
* 'matching_pkey' must not be NULL; '*matching_pkey' will be
* reset.
* matching_cert
* - Pointer to receive address of first matching cert found.
* 'matching_cert' must not be NULL; '*matching_cert' will be
* reset.
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - Objects were found and returned. Which objects are indicated by
*/
int
{
int retval = 0;
/* If NULL arguments, this is an error */
return (-1);
}
if (matching_pkey != NULL)
*matching_pkey = NULL;
if (matching_cert != NULL)
*matching_cert = NULL;
return (-1);
}
&tmp_cert);
if (retval == 0) {
return (retval);
}
if (matching_pkey != NULL)
if (matching_cert != NULL)
return (retval);
}
/*
* sunw_find_fname() searches stacks of certs and private keys for one with
* key found.
*
* Look for a friendlyname in a stack of certs. if 'certs' is NULL and 'pkeys'
* is not NULL, search the list of private keys. Move the matching cert to
* 'matching_cert' and its matching private key to 'matching_pkey'. If no
* cert or keys match, no match occurred.
*
* Arguments:
* fname - Friendlyname to find (NULL-terminated ASCII string).
* pkeys - Points to a stack of private keys which match the certs.
* This may be NULL, in which case no keys are returned.
* certs - Points to a stack of certs to search. If NULL, search the
* stack of keys instead.
* matching_pkey
* - Pointer to receive address of first matching pkey found.
* matching_cert
* - Pointer to receive address of first matching cert found.
*
* Returns:
* < 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* >= 0 - Objects were found and returned. Which objects are indicated by
*/
int
{
int retval = 0;
/* If NULL arguments, this is an error */
return (-1);
}
if (matching_pkey != NULL)
*matching_pkey = NULL;
if (matching_cert != NULL)
*matching_cert = NULL;
/*
* Error already on stack
*/
return (-1);
}
&tmp_cert);
if (retval == 0) {
return (retval);
}
if (matching_pkey != NULL)
if (matching_cert != NULL)
return (retval);
}
/*
* sunw_get_cert_fname() gets the fiendlyname from a cert. It can
* optionally remove the value found.
*
* Arguments:
* dowhat - What to do with the attributes (remove them or copy them).
* cert - Points to a cert to get the friendlyName from.
* fname - Points to a location which will receive the pointer to a
* byte string with the ASCII friendlyname
*
* Returns:
* >= 0 - The number of characters in the friendlyname returned.
* < 0 - An error occurred. It was probably an error in allocating
* memory. The error will be set in the error stack. Call
* ERR_get_error() to get specific information.
*/
int
{
int len;
return (0);
}
/* Delete the entry */
return (0);
}
/*
* Error already on stack
*/
return (-1);
}
return (len);
}
/*
* sunw_set_fname() sets the friendlyName in a cert, a private key or
* both. Any existing friendlyname will be discarded.
*
* Arguments:
* ascname - An ASCII string with the friendlyName to set
* pkey - Points to a private key to set the fname in.
* cert - Points to a cert to set the fname in.
*
* Note that setting a friendlyName into a cert which will not be written out
* as a PKCS12 cert is pointless since it will be lost.
*
* Returns:
* 0 - Success.
* <0 - An error occurred. It was probably an error in allocating
* memory. The error will be set in the error stack. Call
* ERR_get_error() to get specific information.
*/
int
{
int len;
int i;
/*
* Error already on stack
*/
return (-1);
}
}
i = -23;
goto cleanup;
}
}
goto cleanup;
}
/*
* Error already on stack
*/
goto cleanup;
}
goto cleanup;
}
NID_friendlyName)) >= 0) {
}
goto cleanup;
}
}
retval = 0;
return (retval);
}
/*
* sunw_check_keys() compares the public key in the certificate and a
* private key to ensure that they match.
*
* Arguments:
* cert - Points to a certificate.
* pkey - Points to a private key.
*
* Returns:
* == 0 - These do not match.
* != 0 - The cert's public key and the private key match.
*/
int
{
int retval = 0;
return (retval);
}
/*
* sunw_check_cert_times() compares the time fields in a certificate
*
* Compare the 'not before' and the 'not after' times in the cert
* to the current time. Return the results of the comparison (bad time formats,
* cert not yet in force, cert expired or in range)
*
* Arguments:
* dowhat - what field(s) to check.
* cert - Points to a cert to check
*
* Returns:
* Results of the comparison.
*/
{
}
/*
* ----------------------------------------------------------------------------
* Local routines
* ----------------------------------------------------------------------------
*/
/*
* parse_pkcs12 - Oversee parsing of the pkcs12 structure. Get it
* parsed. After that either return what's found directly, or
* do any required matching.
*
* Arguments:
* p12 - Structure with pkcs12 info to be parsed
* pass - Pass phrase for the private key (possibly empty) or NULL if
* there is none.
* keyid - If private key localkeyids friendlynames are to match a
* predetermined value, the value to match. This value should
* be an octet string.
* keyid_len- Length of the keyid byte string.
* name_str - If friendlynames are to match a predetermined value, the value
* to match. This value should be a NULL terminated string.
* pkey - Points to location pointing to the private key returned.
* cert - Points to locaiton which points to the client cert returned
* ca - Points to location that points to a stack of 'certificate
*
* Note about error codes: This function is an internal function, and the
* place where it is called sets error codes. Therefore only set an error
* code if it is something that is unique or if the function which detected
* the error doesn't set one.
*
* Returns:
* == -1 - An error occurred. Call ERR_get_error() to get error information.
* Where possible, memory has been freed.
* == 0 - No matching returns were found.
* > 0 - This is the aithmetic 'or' of the FOUND_* bits that indicate which
* of the requested entries were found.
*/
static int
{
int retval = 0;
int n;
if (retval < 0) {
goto cleanup;
} else if (retval == 0) {
/*
* Not really an error here - its just that nothing was found.
*/
goto cleanup;
}
if (sk_EVP_PKEY_num(work_kl) > 0) {
< 0) {
goto cleanup;
}
}
/*
* Go through the lists of certs and private keys which were
* returned, looking for matches of the appropriate type. Do these
* in the order described above.
*/
if ((matchty & DO_FIND_KEYID) != 0) {
retval = -1;
goto cleanup;
}
/* See if string matches localkeyid's */
if (retval != 0) {
if (retval == -1)
goto cleanup;
else
goto last_part;
}
}
if ((matchty & DO_FIND_FN) != 0) {
retval = -1;
goto cleanup;
}
/* See if string matches friendly names */
if (retval != 0) {
if (retval == -1)
goto cleanup;
else
goto last_part;
}
}
if (matchty & DO_FIRST_PAIR) {
/* Find the first cert and private key and return them */
if (retval != 0) {
if (retval == -1)
goto cleanup;
else
goto last_part;
}
}
if (matchty & DO_LAST_PAIR) {
/*
* Find the last matching cert and private key and return
* them. Since keys which don't have matching client certs
* are at the end of the list of keys, use the number of
* client certs to compute the position of the last private
* key which matches a client cert.
*/
if (retval != 0) {
if (retval == -1)
goto cleanup;
else
goto last_part;
}
}
if (matchty & DO_UNMATCHING) {
/* Find the first cert and private key and return them */
if (retval != 0) {
if (retval == -1)
goto cleanup;
else
goto last_part;
}
}
/* If no errors, terminate normally */
if (retval != -1)
if (retval >= 0) {
goto clean_part;
}
/* Fallthrough is intentional in error cases. */
}
}
}
return (retval);
}
/*
* parse_outer - Unpack the outer PKCS#12 structure and go through the
* individual bags. Return stacks of certs, private keys found and
* CA certs found.
*
* Note about error codes: This function is an internal function, and the
* place where it is called sets error codes.
*
* Returns:
* 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* 1 - PKCS12 data object was parsed and lists of certs and private keys
* were returned.
*/
static int
{
int i, bagnid;
return (0);
for (i = 0; i < sk_PKCS7_num(asafes); i++) {
if (bagnid == NID_pkcs7_data) {
} else if (bagnid == NID_pkcs7_encrypted) {
/*
* A length of '-1' means strlen() can be used
* to determine the password length.
*/
} else {
return (0);
}
return (0);
}
return (0);
}
}
return (1);
}
/*
* parse_all_bags - go through the stack of bags, parsing each.
*
* Note about error codes: This function is an internal function, and the
* place where it is called sets error codes.
*
* Returns:
* 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* 1 - Stack of safebags was parsed and lists of certs and private keys
* were returned.
*/
static int
{
int i;
for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
return (0);
}
return (1);
}
/*
* parse_one_bag - Parse an individual bag
*
* i = parse_one_bag(bag, pass, kl, cl);
*
* Arguments:
* bag - pkcs12 safebag to parse.
* pass - password for use in decryption of shrouded keybag
* kl - Stack of private keys found so far. New private keys will
* be added here if found.
* cl - Stack of certs found so far. New certificates will be
* added here if found.
*
* Returns:
* 0 - An error returned. Call ERR_get_error() to get errors information.
* Where possible, memory has been freed.
* 1 - one safebag was parsed. If it contained a cert or private key, it
* was added to the stack of certs or private keys found, respectively.
* localKeyId or friendlyName attributes are returned with the
* private key or certificate.
*/
static int
{
switch (M_PKCS12_bag_type(bag)) {
case NID_keyBag:
retval = 0;
break;
}
break;
case NID_pkcs8ShroudedKeyBag:
/*
* A length of '-1' means strlen() can be used
* to determine the password length.
*/
retval = 0;
break;
}
retval = 0;
}
break;
case NID_certBag:
break;
}
retval = 0;
break;
}
retval = 0;
break;
}
if (X509_keyid_set1(x509,
retval = 0;
break;
}
}
int len;
retval = 0;
break;
}
if (len < 0) {
retval = 0;
break;
}
retval = 0;
break;
}
}
retval = 0;
break;
}
break;
case NID_safeContentsBag:
/*
* Error already on stack
*/
return (0);
}
return (1);
default:
return (0);
}
retval = 0;
}
}
/*
* Error already on stack
*/
retval = 0;
else {
attr) == 0) {
retval = 0;
} else {
}
}
}
/*
* Error already on stack
*/
retval = 0;
} else {
attr) == 0) {
retval = 0;
} else {
}
}
}
/* Save the private key */
if (retval != 0) {
retval = 0;
} else {
}
}
}
}
return (retval);
}
/*
* This function uses the only function that reads PEM files, regardless of
* the kinds of information included (private keys, public keys, cert requests,
* certs). Other interfaces that read files require that the application
* specifically know what kinds of things to read next, and call different
* interfaces for the different kinds of entities.
*
* There is only one aspect of this function that's a bit problematic.
* If it finds an encrypted private key, it does not decrypt it. It returns
* the encrypted data and other information needed to decrypt it. The caller
* must do the decryption. This function does the decoding.
*/
static int
{
X509_INFO *x;
int retval = 0;
int i;
return (-1);
}
/*
* Allocate the working stacks for private key(s) and for the cert(s).
*/
retval = -1;
goto cleanup;
}
retval = -1;
goto cleanup;
}
/*
* Go through the entries in the info structure.
*/
for (i = 0; i < sk_X509_INFO_num(info); i++) {
x = sk_X509_INFO_value(info, i);
if (x->x509) {
retval = -1;
break;
}
}
const uchar_t *p;
/*
* If the key was encrypted, PEM_X509_INFO_read does
* not decrypt it. If that is the case, the 'enc_pkey'
* field is set to point to the unencrypted key data.
* Go through the additional steps to decode it before
* going on.
*/
if (PEM_do_header(&x->enc_cipher,
(long *)&x->enc_len,
if (ERR_GET_REASON(ERR_peek_error()) ==
} else {
}
retval = -1;
break;
}
if (d2i_RSAPrivateKey(pp, &p,
retval = -1;
break;
}
} else {
if (d2i_DSAPrivateKey(pp, &p,
retval = -1;
break;
}
}
}
/* Save the key. */
if (retval == 0) {
retval = -1;
break;
}
retval = -1;
break;
}
}
if (retval == -1)
goto cleanup;
/* If error occurs, then error already on stack */
}
return (retval);
}
/*
* sunw_append_keys - Given two stacks of private keys, remove the keys from
* the second stack and append them to the first. Both stacks must exist
* at time of call.
*
* Arguments:
* dst - the stack to receive the keys from 'src'
* src - the stack whose keys are to be moved.
*
* Returns:
* -1 - An error occurred. The error status is set.
* >= 0 - The number of keys that were copied.
*/
static int
{
int count = 0;
while (sk_EVP_PKEY_num(src) > 0) {
return (-1);
}
count ++;
}
return (count);
}
/*
* move_certs - Given two stacks of certs, remove the certs from
* the second stack and append them to the first.
*
* Arguments:
* dst - the stack to receive the certs from 'src'
* src - the stack whose certs are to be moved.
*
* Returns:
* -1 - An error occurred. The error status is set.
* >= 0 - The number of certs that were copied.
*/
static int
{
int count = 0;
while (sk_X509_num(src) > 0) {
return (-1);
}
count++;
}
return (count);
}
/*
* get_key_cert - Get a cert and its matching key from the stacks of certs
* and keys. They are removed from the stacks.
*
* Arguments:
* n - Offset of the entries to return.
* kl - Points to a stack of private keys that matches the list of
* certs below.
* pkey - Points at location where the address of the matching private
* key will be stored.
* cl - Points to a stack of client certs with matching private keys.
* cert - Points to locaiton where the address of the matching client cert
* will be returned
*
* with entries in the same order and hence at the same offset. Provided
* the key and cert selected match, each will be removed from its stack and
* returned.
*
* A stack of certs can be passed in without a stack of private keys, and vise
*
* Returns:
* 0 - No matches were found.
* > 0 - Bits set based on FOUND_* definitions, indicating what is returned.
* This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
*/
static int
{
int retval = 0;
int nk;
int nc;
retval |= FOUND_PKEY;
}
}
retval |= FOUND_CERT;
}
}
return (retval);
}
/*
* asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in
* ASN1_BMPSTRING format.
*
* Arguments:
* str - String to be convered.
* len - Length of the string.
*
* Returns:
* == NULL - An error occurred. Error information (accessible by
* ERR_get_error()) is set.
* != NULL - Points to an ASN1_BMPSTRING structure with the converted
* string as a value.
*/
static ASN1_BMPSTRING *
{
int unilen;
/* Convert the character to the bmp format. */
#if OPENSSL_VERSION_NUMBER < 0x10000000L
#else
#endif
return (NULL);
}
/*
* Adjust for possible pair of NULL bytes at the end because
* asc2uni() returns a doubly null terminated string.
*/
unilen -= 2;
/* Construct comparison string with correct format */
bmp = M_ASN1_BMPSTRING_new();
return (NULL);
}
return (bmp);
}
/*
* utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string.
* This goes through an intermediate step with a ASN1_STRING type of
* IA5STRING (International Alphabet 5, which is the same as ASCII).
*
* Arguments:
* str - UTF8STRING to be converted.
*
* Returns:
* == NULL - An error occurred. Error information (accessible by
* ERR_get_error()) is set.
* != NULL - Points to a NULL-termianted ASCII string. The caller must
* free it.
*/
static uchar_t *
{
int mbflag;
int ret;
return (NULL);
}
if (ret < 0) {
return (NULL);
}
return (NULL);
}
return (retstr);
}
/*
* type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type
* specified by the given NID.
*
* Arguments:
* ty - Type structure to be made into an attribute
* nid - NID of the attribute
*
* Returns:
* NULL An error occurred.
* != NULL An X509_ATTRIBUTE structure.
*/
{
X509_ATTRIBUTE *a;
if ((a = X509_ATTRIBUTE_new()) == NULL ||
if (a != NULL)
return (NULL);
}
a->single = 0;
return (a);
}
/*
* attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE
* component
*
* Arguments:
* attr - Attribute structure containing a type.
*
* Returns:
* NULL An error occurred.
* != NULL An ASN1_TYPE structure.
*/
static ASN1_TYPE *
{
return (NULL);
return (ty);
}
/*
* find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE
* of the type specified by the given NID.
*
* Arguments:
* attrs - Stack of attributes to search
* nid - NID of the attribute being searched for
*
* Returns:
* -1 None found
* != -1 Offset of the matching attribute.
*/
static int
{
X509_ATTRIBUTE *a;
int i;
return (-1);
for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
a = sk_X509_ATTRIBUTE_value(attrs, i);
return (i);
}
return (-1);
}
/*
* Called by our PKCS12 code to read our function and error codes
* into memory so that the OpenSSL framework can retrieve them.
*/
void
ERR_load_SUNW_strings(void)
{
assert(SUNW_lib_error_code == 0);
#ifndef OPENSSL_NO_ERR
/*
* Have OpenSSL provide us with a unique ID.
*/
#endif
}
/*
* The SUNWerr macro resolves to this routine. So when we need
* to push an error, this routine does it for us. Notice that
* the SUNWerr macro provides a filename and line #.
*/
void
{
assert(SUNW_lib_error_code != 0);
#ifndef OPENSSL_NO_ERR
#endif
}
/*
* check_time - Given an indication of the which time(s) to check, check
* that time or those times against the current time and return the
* relationship.
*
* Arguments:
* chkwhat - What kind of check to do.
* cert - The cert to check.
*
* Returns:
* CHKERR_* values.
*/
static chk_errs_t
{
int i;
if (i == 0)
return (CHKERR_TIME_BEFORE_BAD);
if (i > 0)
return (CHKERR_TIME_IS_BEFORE);
/* The current time is after the 'not before' time */
}
if (i == 0)
return (CHKERR_TIME_AFTER_BAD);
if (i < 0)
return (CHKERR_TIME_HAS_EXPIRED);
}
return (CHKERR_TIME_OK);
}
/*
* find_attr - Look for a given attribute of the type associated with the NID.
*
* Arguments:
* nid - NID for the attribute to be found (either NID_friendlyName or
* NID_locakKeyId)
* str - ASN1_STRING-type structure containing the value to be found,
* FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a
* ASN1_STRING.
* kl - Points to a stack of private keys.
* pkey - Points at a location where the address of the matching private
* key will be stored.
* cl - Points to a stack of client certs with matching private keys.
* cert - Points to locaiton where the address of the matching client cert
* will be returned
*
* This function is designed to process lists of certs and private keys.
* This is made complex because these the attributes are stored differently
* for certs and for keys. For certs, only a few attributes are retained.
* FriendlyName is stored in the aux structure, under the name 'alias'.
* LocalKeyId is also stored in the aux structure, under the name 'keyid'.
* A pkey structure has a stack of attributes.
*
* The basic approach is:
* - If there there is no stack of certs but a stack of private keys exists,
* search the stack of keys for a match. Alternately, if there is a stack
* of certs and no private keys, search the certs.
*
* - If there are both certs and keys, assume that the matching certs and
* keys are in their respective stacks, with matching entries in the same
* order. Search for the name or keyid in the stack of certs. If it is
* not found, then this function returns 0 (nothing found).
*
* - Once a cert is found, verify that the key actually matches by
* comparing the private key with the public key (in the cert).
* If they don't match, return an error.
*
* in the return arguments.
*
* Returns:
* 0 - No matches were found.
* > 0 - Bits set based on FOUND_* definitions, indicating what was found.
* This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
*/
static int
{
ASN1_STRING *s;
ASN1_TYPE *t;
EVP_PKEY *p;
X509 *x;
int found = 0;
int chkcerts;
int len;
int res;
int c = -1;
int k = -1;
ustr = ASN1_UTF8STRING_new();
return (0);
}
return (0);
}
return (0);
}
}
if (chkcerts) {
for (c = 0; c < sk_X509_num(cl); c++) {
res = -1;
x = sk_X509_value(cl, c);
continue;
}
} else {
continue;
}
}
if (res == 0) {
found = FOUND_CERT;
break;
}
}
}
}
/*
* Looking for pkey to match a cert? If so, assume that
* lists of certs and their matching pkeys are in the same
* order. Call X509_check_private_key() to verify this
* assumption.
*/
k = c;
p = sk_EVP_PKEY_value(kl, k);
if (X509_check_private_key(x, p) != 0) {
found |= FOUND_PKEY;
}
for (k = 0; k < sk_EVP_PKEY_num(kl); k++) {
p = sk_EVP_PKEY_value(kl, k);
continue;
t->value.asn1_string) == 0)
continue;
found |= FOUND_PKEY;
break;
}
}
}
return (found);
}
/*
* set_results - Given two pointers to stacks of private keys, certs or CA
* CA certs, either copy the second stack to the first, or append the
* contents of the second to the first.
*
* Arguments:
* pkeys - Points to stack of pkeys
* work_kl - Points to working stack of pkeys
* certs - Points to stack of certs
* work_cl - Points to working stack of certs
* cacerts - Points to stack of CA certs
* work_ca - Points to working stack of CA certs
* xtrakeys - Points to stack of unmatcned pkeys
* work_xl - Points to working stack of unmatcned pkeys
*
* The arguments are in pairs. The first of each pair points to a stack
* of keys or certs. The second of the pair points at a 'working stack'
* of the same type of entities. Actions taken are as follows:
*
* - If either the first or second argument is NULL, or if there are no
* members in the second stack, there is nothing to do.
* - If the first argument points to a pointer which is NULL, then there
* is no existing stack for the first argument. Copy the stack pointer
* from the second argument to the first argument and NULL out the stack
* pointer for the second.
* - Otherwise, go through the elements of the second stack, removing each
* and adding it to the first stack.
*
* Returns:
* == -1 - An error occurred. Call ERR_get_error() to get error information.
* == 0 - No matching returns were found.
* > 0 - This is the arithmetic 'or' of the FOUND_* bits that indicate which
* of the requested entries were manipulated.
*/
static int
{
int retval = 0;
sk_EVP_PKEY_num(*work_kl) > 0) {
} else {
return (-1);
}
}
retval |= FOUND_PKEY;
}
sk_X509_num(*work_cl) > 0) {
} else {
return (-1);
}
}
retval |= FOUND_CERT;
}
sk_X509_num(*work_ca) > 0) {
} else {
return (-1);
}
}
retval |= FOUND_CA_CERTS;
}
sk_EVP_PKEY_num(*work_xl) > 0) {
} else {
return (-1);
}
}
retval |= FOUND_XPKEY;
}
return (retval);
}