/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <errno.h>
#include <sys/sysmacros.h>
#include <security/cryptoki.h>
#include <stdio.h>
#include <strings.h>
#include <netdb.h>
#include <fcntl.h>
#include <cryptoutil.h>
#include <libscf.h>
#include "kssladm.h"
#include <kmfapi.h>
void
{
if (do_print)
" -f pkcs11 [-d softtoken_directory] -T <token_label>"
" -C <certificate_label> -x <proxy_port>"
" [-h <ca_certchain_file>]"
" [options] [<server_address>] [<server_port>]\n");
" -f pkcs12 -i <cert_and_key_pk12file> -x <proxy_port>"
" [options] [<server_address>] [<server_port>]\n");
" -f pem -i <cert_and_key_pemfile> -x <proxy_port>"
" [options] [<server_address>] [<server_port>]\n");
"\t[-c <ciphersuites>]\n"
"\t[-p <password_file>]\n"
"\t[-t <ssl_session_cache_timeout>]\n"
"\t[-z <ssl_session_cache_size>]\n"
"\t[-v]\n");
}
/*
* Everything is allocated in one single contiguous buffer.
* The layout is the following:
* . the kssl_params_t structure
* . optional buffer containing pin (if key is non extractable)
* . the array of key attribute structs, (value of ck_attrs)
* . the key attributes values (values of ck_attrs[i].ck_value);
* . the array of sizes of the certificates, (referred to as sc_sizes[])
* . the certificates values (referred to as sc_certs[])
*
* The address of the certs and key attributes values are offsets
* from the beginning of the big buffer. sc_sizes_offset points
* to sc_sizes[0] and sc_certs_offset points to sc_certs[0].
*/
static kssl_params_t *
{
int i, tcsize;
char *buf;
{CKA_TOKEN, &true, sizeof (true)},
{CKA_EXTRACTABLE, &false, sizeof (false)},
};
{SUN_CKA_MODULUS, NULL, 0},
{SUN_CKA_PUBLIC_EXPONENT, NULL, 0},
{SUN_CKA_PRIVATE_EXPONENT, NULL, 0},
{SUN_CKA_PRIME_1, NULL, 0},
{SUN_CKA_PRIME_2, NULL, 0},
{SUN_CKA_EXPONENT_1, NULL, 0},
{SUN_CKA_EXPONENT_2, NULL, 0},
{SUN_CKA_COEFFICIENT, NULL, 0}
};
int attr_cnt;
}
tcsize = 0;
for (i = 0; i < ncerts; i++)
bufsize = sizeof (kssl_params_t);
if (!nxkey) {
/* and the key attributes */
"missing required attributes in private key.\n");
return (NULL);
}
attr_cnt = 0;
for (i = 0; i < MAX_ATTR_CNT; i++) {
continue;
priv_key_bignums[i].len;
bufsize += sizeof (crypto_object_attribute_t) +
attr_cnt++;
}
} else {
/*
* Compute space for the attributes and values that the
* kssl kernel module will need in order to search for
* the private key.
*/
bufsize += sizeof (crypto_object_attribute_t) +
}
if (creds)
}
/* Add 4-byte cushion as sc_sizes[0] needs 32-bit alignment */
/* Now the big memory allocation */
"Cannot allocate memory for the kssl_params "
"and values\n");
return (NULL);
}
/* LINTED */
if (!nxkey) {
/* the keys attributes structs array */
attr_cnt = 0;
/* then the key attributes values */
for (i = 0; i < MAX_ATTR_CNT; i++) {
continue;
priv_key_bignums[i].len);
buf - (char *)kssl_params;
attr_cnt++;
}
} else {
/*
* For a non-extractable key, we must provide the PIN
* so the kssl module can access the token to find
* the key handle.
*/
buf - (char *)kssl_params;
/*
* Next in the buffer, we must provide the attributes
* that the kssl module will use to search in the
* token to find the protected key handle.
*/
for (i = 0; i < attr_cnt; i++) {
exkey_attrs[i].ulValueLen);
buf - (char *)kssl_params;
}
}
/* Copy the key attributes array here */
attr_cnt * sizeof (kssl_object_attribute_t));
/*
* Finally, add the certificate chain to the buffer.
*/
/* First, an array of certificate sizes */
for (i = 0; i < ncerts; i++) {
}
/* Now add the certificate data (ASN.1 DER encoded) */
for (i = 0; i < ncerts; i++) {
}
return (kssl_params);
}
/*
*
* This function requires that we call PKCS#11 API directly since
* KMF does not yet support wrapping/unwrapping of keys. By extracting
* a sensitive key in wrapped form, we then unwrap it into a session key
* object. KMF is then used to find the session key and return it in
* KMF_RAW_KEY format which is then passed along to KSSL by the caller.
*/
static KMF_RETURN
{
int fd;
int numattr = 0;
int idx;
sizeof (aes_param)};
/* code below depends on the following attribute order */
{CKA_TOKEN, &false, sizeof (false)},
{CKA_SENSITIVE, &false, sizeof (false)},
{CKA_PRIVATE, &false, sizeof (false)},
};
/*
* Create a wrap key with random data.
*/
if (fd == -1) {
return (KMF_ERR_INTERNAL);
}
sizeof (aes_key_val)) {
return (KMF_ERR_INTERNAL);
}
/*
* Login to create the wrap key stuff.
*/
"Cannot login to the token. error = %s\n",
return (KMF_ERR_INTERNAL);
}
/*
* Turn the random key into a PKCS#11 session object.
*/
sizeof (aes_key_val), &aes_key_obj);
"Cannot create wrapping key. error = %s\n",
return (KMF_ERR_INTERNAL);
}
/*
* Find the original private key that we are going to wrap.
*/
numattr++;
numattr++;
creds, sizeof (KMF_CREDENTIAL));
numattr++;
if (keylabel) {
numattr++;
}
if (idstr) {
numattr++;
}
numattr++;
numattr++;
numattr++;
nkeys = 1;
numattr++;
key, sizeof (KMF_KEY_HANDLE));
numattr++;
goto out;
}
/*
* Get the size of the wrapped private key.
*/
/*
* Most common error here is that the token doesn't
* support the wrapping mechanism or the key is
* marked non-extractable. Return an error and let
* the caller deal with it gracefully.
*/
"Cannot get wrap key size. error = %s\n",
goto out;
}
if (wrapped_privkey == NULL) {
rv = KMF_ERR_MEMORY;
goto out;
}
/*
* Now get the actual wrapped key data.
*/
"Cannot wrap private key. error = %s\n",
goto out;
}
/*
* Create a label for the wrapped session key so we can find
* it easier later.
*/
getpid());
/*
* Unwrap the key into the template and create a temporary
* session private key.
*/
"Cannot unwrap private key. error = %s\n",
goto out;
}
/*
* Use KMF to find the session key and return it as RAW data
* so we can pass it along to KSSL.
*/
}
numattr)) != -1) {
}
if (wrapkey_label != NULL &&
}
numattr)) != -1) {
}
numattr)) != -1) {
}
numattr)) != -1) {
}
/*
* Clear the IDSTR attribute since it is not part of the
* wrapped session key.
*/
numattr)) != -1) {
}
/* The wrapped key should not be sensitive. */
&false, sizeof (false));
numattr++;
goto out;
}
out:
if (wrapped_privkey)
if (aes_key_obj != CK_INVALID_HANDLE)
if (sess_privkey_obj != CK_INVALID_HANDLE)
return (rv);
}
static kssl_params_t *
const char *token_label, const char *password_file,
{
int nxkey = 0;
int numattr = 0;
sizeof (password_buf)) <= 0) {
perror("Unable to read passphrase");
goto done;
}
numattr++;
numattr++;
}
&false, sizeof (false));
numattr++;
goto done;
}
/*
* Find the certificate matching the given label.
*/
numattr = 0;
numattr++;
if (certname) {
numattr++;
}
ncerts = 1;
numattr++;
numattr++;
goto done;
/*
* Find the associated private key for this cert by
* keying off of the label and the ASCII ID string.
*/
goto done;
numattr++;
&creds, sizeof (KMF_CREDENTIAL));
numattr++;
numattr++;
if (certname) {
numattr++;
}
if (idstr) {
numattr++;
}
&true, sizeof (true));
numattr++;
&true, sizeof (true));
numattr++;
/* We only expect to find 1 key at most */
nkeys = 1;
numattr++;
&key, sizeof (KMF_KEY_HANDLE));
numattr++;
if (rv == KMF_ERR_SENSITIVE_KEY) {
/*
* in order to get the necessary raw data fields needed
* to send to KSSL.
*/
/* Swap "key" for "rawkey" */
} else {
/* Let kssl try to find the key. */
nxkey = 1;
}
} else if (rv == KMF_ERR_UNEXTRACTABLE_KEY) {
/* Let kssl try to find the key. */
nxkey = 1;
goto done;
done:
if (ncerts != 0)
if (nkeys != 0)
if (idstr)
return (kssl_params);
}
/*
* add_cacerts
*
* Load a chain of certificates from a PEM file.
*/
static kssl_params_t *
{
int i, newlen;
char *buf;
int numattr = 0;
ncerts = 0;
&kstype, sizeof (KMF_KEYSTORE_TYPE));
numattr++;
numattr++;
numattr++;
return (0);
}
sizeof (KMF_X509_DER_CERT));
return (NULL);
}
/* add new attribute for the cert list to be returned */
numattr++;
return (NULL);
}
if (verbose) {
}
for (i = 0; i < ncerts; i++)
/*
* Get a bigger structure and update the
* fields to account for the additional certs.
*/
/* Put the cert size info starting from sc_sizes[1] */
buf = (char *)kssl_params;
for (i = 0; i < ncerts; i++) {
}
/* Put the cert_bufs starting from sc_certs[1] */
buf = (char *)kssl_params;
/* now the certs values */
for (i = 0; i < ncerts; i++) {
}
for (i = 0; i < ncerts; i++)
return (kssl_params);
}
/*
* Find a key and certificate(s) from a single PEM file.
*/
static kssl_params_t *
const char *password_file, int *paramsize)
{
int ncerts = 0, i;
return (NULL);
}
if (verbose)
for (i = 0; i < ncerts; i++)
return (kssl_params);
}
/*
* Load a raw key and certificate(s) from a PKCS#12 file.
*/
static kssl_params_t *
const char *password_file, int *paramsize)
{
int ncerts = 0, i;
return (NULL);
}
if (verbose)
for (i = 0; i < ncerts; i++)
return (kssl_params);
}
int
struct sockaddr_in6 *addr)
{
long long tmp_port;
char *ep;
if (server_port == NULL) {
return (-1);
}
if (server_address == NULL) {
} else {
int error_num;
return (-1);
}
}
errno = 0;
return (-1);
}
return (-1);
}
/* It is safe to convert since the value is inside the boundaries. */
return (0);
}
/*
* The order of the ciphers is important. It is used as the
* default order (when -c is not specified).
*/
struct csuite {
const char *suite;
};
static int
{
int i;
int err = 0;
char *suite;
int sindx = 0;
for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
sarray[i] = CIPHER_NOTSET;
} else {
for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++)
return (err);
}
do {
for (i = 0; i < CIPHER_SUITE_COUNT - 1; i++) {
if (!cipher_suites[i].seen) {
}
break;
}
}
if (i == (CIPHER_SUITE_COUNT - 1)) {
"Unknown Cipher suite name: %s\n", suite);
err++;
}
return (err);
}
int
{
char c;
int pcnt;
int bufsize;
argc -= 1;
argv += 1;
switch (c) {
case 'd':
break;
case 'c':
break;
case 'C':
break;
case 'f':
break;
case 'h':
break;
case 'i':
break;
case 'T':
break;
case 'p':
break;
case 't':
break;
case 'x':
break;
case 'v':
break;
case 'z':
break;
default:
goto err;
}
}
if (pcnt == 0) {
} else if (pcnt == 1) {
} else if (pcnt == 2) {
} else {
goto err;
}
goto err;
}
if (verbose) {
sizeof (buffer));
}
goto err;
}
goto err;
}
return (0);
}
goto err;
}
if (softtoken_dir != NULL) {
if (verbose) {
(void) printf(
"SOFTTOKEN_DIR=%s\n",
getenv("SOFTTOKEN_DIR"));
}
}
if (cert_key_file == NULL) {
goto err;
}
if (cert_key_file == NULL) {
goto err;
}
} else {
goto err;
}
if (kssl_params == NULL) {
(void) kmf_finalize(kmfh);
return (FAILURE);
}
/*
* Add the list of supported ciphers to the buffer.
*/
sizeof (kssl_params->kssl_suites));
if (cacert_chain_file != NULL) {
if (kssl_params == NULL) {
(void) kmf_finalize(kmfh);
return (FAILURE);
}
}
if (kssl_params->kssl_is_nxkey)
"Error loading cert and key: 0x%x\n", err);
(void) kmf_finalize(kmfh);
return (FAILURE);
}
if (verbose)
(void) printf("Successfully loaded cert and key\n");
(void) kmf_finalize(kmfh);
return (SUCCESS);
err:
(void) kmf_finalize(kmfh);
return (SMF_EXIT_ERR_CONFIG);
}