summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorkrishna <none@none>2006-05-04 17:20:55 -0700
committerkrishna <none@none>2006-05-04 17:20:55 -0700
commit164c0dd6f561db19bdaf1d0b7f2a8dec44355b69 (patch)
treef17c82e0a0cbdb749d3863b145b236e2711afa38 /usr/src/cmd
parent769b977d34538d5f208de3a6178f04cb0876b7ca (diff)
downloadillumos-gate-164c0dd6f561db19bdaf1d0b7f2a8dec44355b69.tar.gz
PSARC 2006/263 Certificate chain support in kernel SSL
5106865 cert chain support is needed in kernel SSL 6406654 ksslcfg(1M) should check for a match between the certificate and private key
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h19
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c252
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c245
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c9
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c19
5 files changed, 392 insertions, 152 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
index 4f1f118959..fa22c51307 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,6 +44,8 @@ extern "C" {
#define FAILURE 1
#define ERROR_USAGE 2
+#define MAX_CHAIN_LENGTH 12
+
extern boolean_t verbose;
extern int do_create(int argc, char *argv[]);
@@ -52,11 +54,10 @@ extern void usage_create(boolean_t do_print);
extern void usage_delete(boolean_t do_print);
extern uchar_t *get_modulus(uchar_t *ber_buf, int buflen, int *modlen);
-extern RSA *PEM_get_rsa_key(const char *filename, char *passphrase);
-extern uchar_t *PEM_get_cert(const char *filename, char *passphrase,
- int *cert_size);
-extern int PKCS12_get_rsa_key_cert(const char *filename, const char *password,
- RSA **rsa, uchar_t **cert, int *cert_size);
+extern uchar_t **PEM_get_rsa_key_certs(const char *filename,
+ char *password_file, RSA **rsa, int **cert_sizes, int *ncerts);
+extern uchar_t **PKCS12_get_rsa_key_certs(const char *filename,
+ const char *password_file, RSA **rsa, int **cert_sizes, int *ncerts);
extern int get_passphrase(const char *password_file, char *buf, int buf_size);
extern int kssl_send_command(char *buf, int cmd);
extern int parse_and_set_addr(char *arg1, char *arg2, struct sockaddr_in *addr);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
index 5ed9c52302..e8d4909e31 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/kssladm_create.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,6 +28,7 @@
#include <arpa/inet.h>
#include <errno.h>
+#include <sys/sysmacros.h>
#include <netdb.h> /* hostent */
#include <netinet/in.h>
#include <openssl/rsa.h>
@@ -49,14 +50,15 @@ usage_create(boolean_t do_print)
(void) fprintf(stderr, "kssladm create"
" -f pkcs11 [-d softtoken_directory] -T <token_label>"
" -C <certificate_label> -x <proxy_port>"
+ " [-h <ca_certchain_file>]"
" [options] [<server_address>] [<server_port>]\n");
(void) fprintf(stderr, "kssladm create"
- " -f pkcs12 -i <certificate_file> -x <proxy_port>"
+ " -f pkcs12 -i <cert_and_key_pk12file> -x <proxy_port>"
" [options] [<server_address>] [<server_port>]\n");
(void) fprintf(stderr, "kssladm create"
- " -f pem -i <certificate_file> -x <proxy_port>"
+ " -f pem -i <cert_and_key_pemfile> -x <proxy_port>"
" [options] [<server_address>] [<server_port>]\n");
(void) fprintf(stderr, "options are:\n"
@@ -107,13 +109,14 @@ get_cert_val(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE cert_obj, int *len)
* Everything is allocated in one single contiguous buffer.
* The layout is the following:
* . the kssl_params_t structure
- * . the array of sizes of the certificates, (value of sc_sizes_offset)
* . the array of key attribute structs, (value of ck_attrs)
- * . the certificates values (values of sc_certs[i])
* . 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.
+ * 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 *
pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
@@ -152,7 +155,7 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
/* Get the sizes */
bufsize = sizeof (kssl_params_t);
cert_size = (uint32_t)cert_attrs[0].ulValueLen;
- bufsize += cert_size + sizeof (uint32_t);
+ bufsize += cert_size + MAX_CHAIN_LENGTH * sizeof (uint32_t);
/* and the required key attributes */
rv = C_GetAttributeValue(sess, privkey_obj, privkey_attrs,
@@ -194,6 +197,9 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
attr_cnt++;
}
+ /* Add 4-byte cushion as sc_sizes[0] needs 32-bit aligment */
+ bufsize += sizeof (uint32_t);
+
/* Now the big memory allocation */
if ((buf = calloc(bufsize, 1)) == NULL) {
(void) fprintf(stderr,
@@ -207,11 +213,6 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
buf = (char *)(kssl_params + 1);
- kssl_params->kssl_certs.sc_count = 1;
- bcopy(&cert_size, buf, sizeof (uint32_t));
- kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
- buf += sizeof (uint32_t);
-
/* the keys attributes structs array */
key = &kssl_params->kssl_privkey;
key->ks_format = CRYPTO_KEY_ATTR_LIST;
@@ -219,18 +220,6 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
key->ks_attrs_offset = buf - (char *)kssl_params;
buf += attr_cnt * sizeof (kssl_object_attribute_t);
- /* now the certs values */
- cert_attrs[0].pValue = buf;
- kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
- buf += cert_attrs[0].ulValueLen;
-
- rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
- if (rv != CKR_OK) {
- (void) fprintf(stderr, "Cannot get cert value."
- " error = %s\n", pkcs11_strerror(rv));
- return (NULL);
- }
-
/* then the attributes values */
for (i = 0; i < attr_cnt; i++) {
privkey_attrs[i].pValue = buf;
@@ -245,6 +234,7 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
buf += privkey_attrs[i].ulValueLen;
}
+
/* then the key attributes values */
rv = C_GetAttributeValue(sess, privkey_obj, privkey_attrs, attr_cnt);
if (rv != CKR_OK) {
@@ -257,13 +247,31 @@ pkcs11_to_kssl(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE privkey_obj,
bcopy(kssl_attrs, ((char *)kssl_params) + key->ks_attrs_offset,
attr_cnt * sizeof (kssl_object_attribute_t));
+ buf = (char *)P2ROUNDUP((uintptr_t)buf, sizeof (uint32_t));
+ kssl_params->kssl_certs.sc_count = 1;
+ bcopy(&cert_size, buf, sizeof (uint32_t));
+ kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
+ buf += MAX_CHAIN_LENGTH * sizeof (uint32_t);
+
+ /* now the certs values */
+ cert_attrs[0].pValue = buf;
+ kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
+ buf += cert_attrs[0].ulValueLen;
+
+ rv = C_GetAttributeValue(sess, cert_obj, cert_attrs, 1);
+ if (rv != CKR_OK) {
+ (void) fprintf(stderr, "Cannot get cert value."
+ " error = %s\n", pkcs11_strerror(rv));
+ return (NULL);
+ }
+
*paramsize = bufsize;
return (kssl_params);
}
#define max_num_cert 32
-kssl_params_t *
+static kssl_params_t *
load_from_pkcs11(const char *token_label, const char *password_file,
const char *certname, int *bufsize)
{
@@ -384,7 +392,7 @@ load_from_pkcs11(const char *token_label, const char *password_file,
rv = C_FindObjectsInit(sess, cert_tmpl, cert_tmpl_count);
if (rv != CKR_OK) {
(void) fprintf(stderr,
- "Cannot intialize cert search."
+ "Cannot initialize cert search."
" error = %s\n", pkcs11_strerror(rv));
return (NULL);
}
@@ -562,11 +570,15 @@ load_from_pkcs11(const char *token_label, const char *password_file,
}
}
-
+/*
+ * See the comments for pkcs11_to_kssl() for the layout of the
+ * returned buffer.
+ */
static kssl_params_t *
-openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
+openssl_to_kssl(RSA *rsa, int ncerts, uchar_t *cert_bufs[], int *cert_sizes,
+ int *paramsize)
{
- int i;
+ int i, tcsize;
kssl_params_t *kssl_params;
kssl_key_t *key;
char *buf;
@@ -585,8 +597,12 @@ openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
BIGNUM *priv_key_bignums[MAX_ATTR_CNT];
int attr_cnt;
+ tcsize = 0;
+ for (i = 0; i < ncerts; i++)
+ tcsize += cert_sizes[i];
+
bufsize = sizeof (kssl_params_t);
- bufsize += cert_size + sizeof (uint32_t);
+ bufsize += (tcsize + MAX_CHAIN_LENGTH * sizeof (uint32_t));
/* and the key attributes */
priv_key_bignums[0] = rsa->n; /* MODULUS */
@@ -616,6 +632,9 @@ openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
attr_cnt++;
}
+ /* Add 4-byte cushion as sc_sizes[0] needs 32-bit aligment */
+ bufsize += sizeof (uint32_t);
+
/* Now the big memory allocation */
if ((buf = calloc(bufsize, 1)) == NULL) {
(void) fprintf(stderr,
@@ -629,11 +648,6 @@ openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
buf = (char *)(kssl_params + 1);
- kssl_params->kssl_certs.sc_count = 1;
- bcopy(&cert_size, buf, sizeof (uint32_t));
- kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
- buf += sizeof (uint32_t);
-
/* the keys attributes structs array */
key = &kssl_params->kssl_privkey;
key->ks_format = CRYPTO_KEY_ATTR_LIST;
@@ -641,11 +655,6 @@ openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
key->ks_attrs_offset = buf - (char *)kssl_params;
buf += attr_cnt * sizeof (kssl_object_attribute_t);
- /* now the certs values */
- bcopy(cert_buf, buf, cert_size);
- kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
- buf += cert_size;
-
attr_cnt = 0;
/* then the key attributes values */
for (i = 0; i < MAX_ATTR_CNT; i++) {
@@ -661,68 +670,143 @@ openssl_to_kssl(RSA *rsa, uchar_t *cert_buf, int cert_size, int *paramsize)
bcopy(kssl_attrs, ((char *)kssl_params) + key->ks_attrs_offset,
attr_cnt * sizeof (kssl_object_attribute_t));
+ buf = (char *)P2ROUNDUP((uintptr_t)buf, sizeof (uint32_t));
+ kssl_params->kssl_certs.sc_count = ncerts;
+ bcopy(cert_sizes, buf, ncerts * sizeof (uint32_t));
+ kssl_params->kssl_certs.sc_sizes_offset = buf - (char *)kssl_params;
+ buf += MAX_CHAIN_LENGTH * sizeof (uint32_t);
+
+ kssl_params->kssl_certs.sc_certs_offset = buf - (char *)kssl_params;
+ /* now the certs values */
+ for (i = 0; i < ncerts; i++) {
+ bcopy(cert_bufs[i], buf, cert_sizes[i]);
+ buf += cert_sizes[i];
+ }
+
*paramsize = bufsize;
return (kssl_params);
}
-kssl_params_t *
-load_from_pem(const char *filename, const char *password_file, int *paramsize)
+static kssl_params_t *
+add_cacerts(kssl_params_t *old_params, const char *cacert_chain_file,
+ const char *password_file)
{
- uchar_t *cert_buf;
- int cert_size;
- RSA *rsa;
+ int i, ncerts, newlen;
+ int *cert_sizes;
+ uint32_t certlen = 0;
+ char *buf;
+ uchar_t **cert_bufs;
kssl_params_t *kssl_params;
- rsa = PEM_get_rsa_key(filename, (char *)password_file);
- if (rsa == NULL) {
- (void) fprintf(stderr, "cannot read the private key\n");
+ ncerts = 0;
+ cert_bufs = PEM_get_rsa_key_certs(cacert_chain_file,
+ (char *)password_file, NULL, &cert_sizes, &ncerts);
+ if (cert_bufs == NULL || ncerts == 0) {
+ free(old_params);
return (NULL);
}
- if (verbose)
- (void) printf("private key read successfully\n");
+ if (verbose) {
+ (void) printf("%d certificates read successfully\n", ncerts);
+ }
+
+ newlen = old_params->kssl_params_size;
+ for (i = 0; i < ncerts; i++)
+ newlen += cert_sizes[i];
+
+ /*
+ * Get a bigger structure and update the
+ * fields to account for the additional certs.
+ */
+ kssl_params = realloc(old_params, newlen);
+
+ kssl_params->kssl_params_size = newlen;
+ kssl_params->kssl_certs.sc_count += ncerts;
- cert_buf = PEM_get_cert(filename, (char *)password_file, &cert_size);
- if (cert_buf == NULL) {
- RSA_free(rsa);
+ /* Put the cert_sizes starting from sc_sizes[1] */
+ buf = (char *)kssl_params;
+ buf += kssl_params->kssl_certs.sc_sizes_offset;
+ bcopy(buf, &certlen, sizeof (uint32_t));
+ buf += sizeof (uint32_t);
+ bcopy(cert_sizes, buf, ncerts * sizeof (uint32_t));
+
+ /* Put the cert_bufs starting from sc_certs[1] */
+ buf = (char *)kssl_params;
+ buf += kssl_params->kssl_certs.sc_certs_offset;
+ buf += certlen;
+
+ /* now the certs values */
+ for (i = 0; i < ncerts; i++) {
+ bcopy(cert_bufs[i], buf, cert_sizes[i]);
+ buf += cert_sizes[i];
+ }
+
+ for (i = 0; i < ncerts; i++)
+ free(cert_bufs[i]);
+ free(cert_bufs);
+ free(cert_sizes);
+
+ return (kssl_params);
+}
+
+static kssl_params_t *
+load_from_pem(const char *filename, const char *password_file, int *paramsize)
+{
+ uchar_t **cert_bufs;
+ int *cert_sizes, ncerts, i;
+ RSA *rsa;
+ kssl_params_t *kssl_params;
+
+ ncerts = 0;
+ cert_bufs = PEM_get_rsa_key_certs(filename, (char *)password_file,
+ &rsa, &cert_sizes, &ncerts);
+ if (rsa == NULL || cert_bufs == NULL || ncerts == 0) {
return (NULL);
}
if (verbose)
- (void) printf("certificate read successfully size=%d\n",
- cert_size);
+ (void) printf("%d certificates read successfully\n", ncerts);
- kssl_params = openssl_to_kssl(rsa, cert_buf, cert_size, paramsize);
+ kssl_params = openssl_to_kssl(rsa, ncerts, cert_bufs,
+ cert_sizes, paramsize);
- free(cert_buf);
+ for (i = 0; i < ncerts; i++)
+ free(cert_bufs[i]);
+ free(cert_bufs);
+ free(cert_sizes);
RSA_free(rsa);
return (kssl_params);
}
-kssl_params_t *
+static kssl_params_t *
load_from_pkcs12(const char *filename, const char *password_file,
int *paramsize)
{
- uchar_t *cert_buf;
- int cert_size;
RSA *rsa;
kssl_params_t *kssl_params;
+ uchar_t **cert_bufs;
+ int *cert_sizes, ncerts, i;
- if (PKCS12_get_rsa_key_cert(filename, password_file, &rsa, &cert_buf,
- &cert_size) < 0) {
+ ncerts = 0;
+ cert_bufs = PKCS12_get_rsa_key_certs(filename, password_file, &rsa,
+ &cert_sizes, &ncerts);
+ if (cert_bufs == NULL || ncerts == 0) {
(void) fprintf(stderr,
"Unable to read cert and/or key from %s\n", filename);
return (NULL);
}
if (verbose)
- (void) printf(
- "key/certificate read successfully cert_size=%d\n",
- cert_size);
+ (void) printf("%d certificates read successfully\n", ncerts);
+
+ kssl_params = openssl_to_kssl(rsa, ncerts, cert_bufs,
+ cert_sizes, paramsize);
- kssl_params = openssl_to_kssl(rsa, cert_buf, cert_size, paramsize);
+ for (i = 0; i < ncerts; i++)
+ free(cert_bufs[i]);
+ free(cert_bufs);
+ free(cert_sizes);
- free(cert_buf);
RSA_free(rsa);
return (kssl_params);
}
@@ -782,7 +866,7 @@ struct csuite {
{"rsa_des_cbc_sha", SSL_RSA_WITH_DES_CBC_SHA, B_FALSE},
};
-int
+static int
check_suites(char *suites, uint16_t *sarray)
{
int i;
@@ -827,7 +911,8 @@ do_create(int argc, char *argv[])
const char *softtoken_dir = NULL;
const char *token_label = NULL;
const char *password_file = NULL;
- const char *filename = NULL;
+ const char *cert_key_file = NULL;
+ const char *cacert_chain_file = NULL;
const char *certname = NULL;
char *suites = NULL;
uint32_t timeout = DEFAULT_SID_TIMEOUT;
@@ -844,7 +929,7 @@ do_create(int argc, char *argv[])
argc -= 1;
argv += 1;
- while ((c = getopt(argc, argv, "vT:d:f:i:p:c:C:t:x:z:")) != -1) {
+ while ((c = getopt(argc, argv, "vT:d:f:h:i:p:c:C:t:x:z:")) != -1) {
switch (c) {
case 'd':
softtoken_dir = optarg;
@@ -858,8 +943,11 @@ do_create(int argc, char *argv[])
case 'f':
format = optarg;
break;
+ case 'h':
+ cacert_chain_file = optarg;
+ break;
case 'i':
- filename = optarg;
+ cert_key_file = optarg;
break;
case 'T':
token_label = optarg;
@@ -926,17 +1014,17 @@ do_create(int argc, char *argv[])
kssl_params = load_from_pkcs11(
token_label, password_file, certname, &bufsize);
} else if (strcmp(format, "pkcs12") == 0) {
- if (filename == NULL) {
+ if (cert_key_file == NULL) {
goto err;
}
kssl_params = load_from_pkcs12(
- filename, password_file, &bufsize);
+ cert_key_file, password_file, &bufsize);
} else if (strcmp(format, "pem") == 0) {
- if (filename == NULL) {
+ if (cert_key_file == NULL) {
goto err;
}
kssl_params = load_from_pem(
- filename, password_file, &bufsize);
+ cert_key_file, password_file, &bufsize);
} else {
(void) fprintf(stderr, "Unsupported cert format: %s\n", format);
goto err;
@@ -955,6 +1043,14 @@ do_create(int argc, char *argv[])
kssl_params->kssl_proxy_port = proxy_port;
kssl_params->kssl_session_cache_size = scache_size;
+ if (cacert_chain_file != NULL) {
+ kssl_params = add_cacerts(kssl_params, cacert_chain_file,
+ password_file);
+ if (kssl_params == NULL) {
+ return (FAILURE);
+ }
+ }
+
if (kssl_send_command((char *)kssl_params, KSSL_ADD_ENTRY) < 0) {
(void) fprintf(stderr, "Error loading cert and key");
return (FAILURE);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
index 27b1f4c159..56097e3cb8 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,6 +31,7 @@
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
+#include <openssl/pkcs12.h>
#include "kssladm.h"
static void
@@ -49,7 +50,7 @@ pem_password_callback(char *buf, int size, int rwflag, void *userdata)
static STACK_OF(X509_INFO) *
-PEM_get_x509_info_stack(const char *filename, char *passphrase)
+PEM_get_x509_info_stack(const char *filename, char *password_file)
{
FILE *fp;
STACK_OF(X509_INFO) *x509_info_stack;
@@ -66,7 +67,7 @@ PEM_get_x509_info_stack(const char *filename, char *passphrase)
OpenSSL_add_all_algorithms();
x509_info_stack = PEM_X509_INFO_read(
- fp, NULL, pem_password_callback, passphrase);
+ fp, NULL, pem_password_callback, password_file);
(void) fclose(fp);
if (x509_info_stack == NULL) {
@@ -76,12 +77,11 @@ PEM_get_x509_info_stack(const char *filename, char *passphrase)
return (x509_info_stack);
}
-
-RSA *
-PEM_get_rsa_key(const char *filename, char *passphrase)
+static EVP_PKEY *
+PEM_get_key(const char *filename, const char *password_file)
{
FILE *fp;
- RSA *rsa_key;
+ EVP_PKEY *pkey = NULL;
fp = fopen(filename, "r");
if (fp == NULL) {
@@ -89,19 +89,19 @@ PEM_get_rsa_key(const char *filename, char *passphrase)
return (NULL);
}
if (verbose)
- (void) printf("In PEM_get_rsa_key: %s opened\n", filename);
+ (void) printf("In PEM_get_key: %s opened\n", filename);
OpenSSL_add_all_algorithms();
- rsa_key = PEM_read_RSAPrivateKey(
- fp, NULL, pem_password_callback, passphrase);
+ pkey = PEM_read_PrivateKey(fp, NULL, pem_password_callback,
+ (char *)password_file);
(void) fclose(fp);
- if (rsa_key == NULL) {
+ if (pkey == NULL) {
print_crypto_error();
}
- return (rsa_key);
+ return (pkey);
}
uchar_t *
@@ -154,33 +154,121 @@ X509_to_bytes(X509 *cert, int *cert_size)
return (cert_buf);
}
+static uchar_t **
+init_cert_vars(int **rlens)
+{
+ int i;
+ uchar_t **cert_bufs;
+ int *lcert_lens;
-/* Returns DER encoded cert */
-uchar_t *
-PEM_get_cert(const char *filename, char *passphrase, int *cert_size)
+ cert_bufs = (uchar_t **)malloc(MAX_CHAIN_LENGTH * sizeof (uchar_t **));
+ if (cert_bufs == NULL)
+ return (NULL);
+ for (i = 0; i < MAX_CHAIN_LENGTH; i++)
+ cert_bufs[i] = NULL;
+
+ lcert_lens = malloc(MAX_CHAIN_LENGTH * sizeof (int));
+ if (lcert_lens == NULL) {
+ free(cert_bufs);
+ return (NULL);
+ }
+ for (i = 0; i < MAX_CHAIN_LENGTH; i++)
+ lcert_lens[i] = 0;
+
+ *rlens = lcert_lens;
+ return (cert_bufs);
+}
+
+static void
+print_subject(X509 *x)
{
- STACK_OF(X509_INFO) *x509_info_stack;
- uchar_t *cert_buf;
+ char buf[256];
+
+ (void) X509_NAME_oneline(X509_get_subject_name(x),
+ buf, sizeof (buf));
+ (void) fprintf(stdout, "/* subject: %s */ \n", buf);
+}
+
+/*
+ * Returns DER encoded certs in an array of pointers
+ * and their sizes in cert_sizes. If the rsa argument is
+ * not NULL, we return the RSA key in it. The caller needs
+ * to free the structures when done.
+ */
+uchar_t **
+PEM_get_rsa_key_certs(const char *filename, char *password_file,
+ RSA **rsa, int **cert_sizes, int *n)
+{
+ int i, cert_size, ncerts;
+ int *cert_lens;
+ uchar_t **cert_bufs;
+ EVP_PKEY *pkey = NULL;
X509_INFO *info;
+ X509_INFO *cert_infos[MAX_CHAIN_LENGTH];
+ STACK_OF(X509_INFO) *x509_info_stack;
- x509_info_stack = PEM_get_x509_info_stack(filename, passphrase);
+ x509_info_stack = PEM_get_x509_info_stack(filename, password_file);
if (x509_info_stack == NULL) {
return (NULL);
}
+ ncerts = 0;
/* LINTED */
- info = sk_X509_INFO_pop(x509_info_stack);
- if (info == NULL || info->x509 == NULL) {
+ while ((info = sk_X509_INFO_pop(x509_info_stack)) != NULL &&
+ ncerts < MAX_CHAIN_LENGTH) {
+ cert_infos[ncerts] = info;
+ ncerts++;
+ if (verbose)
+ print_subject(info->x509);
+ }
+
+ if (ncerts == 0) {
(void) fprintf(stderr, "No cert found\n");
return (NULL);
}
- cert_buf = X509_to_bytes(info->x509, cert_size);
- X509_INFO_free(info);
- return (cert_buf);
+ if (rsa != NULL) {
+ X509 *x;
+
+ pkey = PEM_get_key(filename, password_file);
+ if (pkey == NULL)
+ return (NULL);
+
+ x = cert_infos[ncerts - 1]->x509;
+ if (!X509_check_private_key(x, pkey)) {
+ (void) fprintf(stderr, "Error: Server certificate "
+ "and server private key do not match.\n");
+ EVP_PKEY_free(pkey);
+ return (NULL);
+ }
+
+ *rsa = EVP_PKEY_get1_RSA(pkey);
+ }
+
+ if ((cert_bufs = init_cert_vars(&cert_lens)) == NULL) {
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+ return (NULL);
+ }
+
+ /*
+ * cert_infos[] is constructed from a stack of certificates structure
+ * and hence the order is high level CA certificate first. SSL protocol
+ * needs the certificates in the order of low level CA certificate
+ * first. So, we walk cert_infos[] in reverse order below.
+ */
+ for (i = 0; i < ncerts; i++) {
+ info = cert_infos[ncerts - 1 - i];
+ cert_bufs[i] = X509_to_bytes(info->x509, &cert_size);
+ cert_lens[i] = cert_size;
+ X509_INFO_free(info);
+ }
+
+ *cert_sizes = cert_lens;
+ *n = ncerts;
+ return (cert_bufs);
}
-#include <openssl/pkcs12.h>
static PKCS12 *
PKCS12_load(const char *filename)
{
@@ -189,7 +277,7 @@ PKCS12_load(const char *filename)
fp = fopen(filename, "r");
if (fp == NULL) {
- perror("Unnable to open file for reading");
+ perror("Unable to open file for reading");
return (NULL);
}
@@ -207,59 +295,112 @@ PKCS12_load(const char *filename)
return (p12);
}
-int
-PKCS12_get_rsa_key_cert(const char *filename, const char *password_file,
- RSA **rsa, uchar_t **cert, int *cert_size)
+/*
+ * Returns DER encoded certs in an array of pointers and their
+ * sizes in cert_sizes. The RSA key is returned in the rsa argument.
+ * The caller needs to free the structures when done.
+ */
+uchar_t **
+PKCS12_get_rsa_key_certs(const char *filename, const char *password_file,
+ RSA **rsa, int **cert_sizes, int *n)
{
- int rv = -1;
- EVP_PKEY *pkey = NULL;
- X509 *x509 = NULL;
+ int i, ncerts, cert_size;
+ int *cert_lens;
char *password = NULL;
char password_buf[1024];
- PKCS12 *p12;
+ uchar_t **cert_bufs = NULL;
+ uchar_t *cert_buf;
+ PKCS12 *p12 = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ X509 *certs[MAX_CHAIN_LENGTH];
+ STACK_OF(X509) *ca = NULL;
p12 = PKCS12_load(filename);
if (p12 == NULL) {
- goto out0;
+ return (NULL);
}
if (! PKCS12_verify_mac(p12, NULL, 0)) {
if (get_passphrase(
password_file, password_buf, sizeof (password_buf)) <= 0) {
- perror("Unnable to read passphrase");
- goto out0;
+ perror("Unable to read passphrase");
+ goto done;
}
password = password_buf;
}
- (void) PKCS12_parse(p12, password, &pkey, &x509, NULL);
+ if (PKCS12_parse(p12, password, &pkey, &x509, &ca) <= 0) {
+ (void) fprintf(stderr, "Unable to parse PKCS12 file.\n");
+ goto done;
+ }
- PKCS12_free(p12);
if (pkey == NULL) {
(void) fprintf(stderr, "No key returned\n");
- goto out0;
+ goto done;
}
if (x509 == NULL) {
(void) fprintf(stderr, "No cert returned\n");
- goto out1;
+ goto done;
+ }
+
+ if (!X509_check_private_key(x509, pkey)) {
+ (void) fprintf(stderr, "Error: Server certificate and server "
+ "private key do not match.\n");
+ goto done;
}
+ cert_buf = X509_to_bytes(x509, &cert_size);
+ if (cert_buf == NULL)
+ goto done;
+ X509_free(x509);
+
*rsa = EVP_PKEY_get1_RSA(pkey);
if (*rsa == NULL) {
- goto out2;
+ goto done;
+ }
+
+ if ((cert_bufs = init_cert_vars(&cert_lens)) == NULL) {
+ RSA_free(*rsa);
+ goto done;
}
- *cert = X509_to_bytes(x509, cert_size);
+ ncerts = 0;
+ cert_bufs[0] = cert_buf;
+ cert_lens[0] = cert_size;
+ ncerts++;
- if (*cert != NULL) {
- rv = 0;
+ /* LINTED */
+ while ((ca != NULL) && ((x509 = sk_X509_pop(ca)) != NULL) &&
+ ncerts < MAX_CHAIN_LENGTH) {
+ certs[ncerts] = x509;
+ ncerts++;
+ if (verbose)
+ print_subject(x509);
}
-out2:
- X509_free(x509);
-out1:
- EVP_PKEY_free(pkey);
-out0:
- return (rv);
+ /*
+ * certs[1..ncerts-1] is constructed from a stack of certificates
+ * structure and hence the order is high level CA certificate first.
+ * SSL protocol needs the certificates in the order of low level CA
+ * certificate first. So, we walk certs[] in reverse order below.
+ */
+ for (i = 1; i < ncerts; i++) {
+ x509 = certs[ncerts - i];
+ cert_bufs[i] = X509_to_bytes(x509, &cert_size);
+ cert_lens[i] = cert_size;
+ X509_free(x509);
+ }
+
+ *cert_sizes = cert_lens;
+ *n = ncerts;
+
+done:
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+ if (p12 != NULL)
+ PKCS12_free(p12);
+
+ return (cert_bufs);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
index de98986984..d4005fe2d6 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,7 +46,7 @@
* It makes use of kssladm(1M) which does the grunt work.
*/
-#define KSSLCFG_VERSION "1.0"
+#define KSSLCFG_VERSION "v%I%"
boolean_t verbose = B_FALSE;
const char *SERVICE_NAME = "network/ssl/proxy";
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
index 68a6262b44..6e4988c52d 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg_create.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,15 +42,16 @@ usage_create(boolean_t do_print)
(void) fprintf(stderr, gettext("Usage:\n"));
(void) fprintf(stderr, "ksslcfg create"
" -f pkcs11 [-d softtoken_directory] -T <token_label>"
- " -C <certificate_subject> -x <proxy_port>"
+ " -C <certificate_label> -x <proxy_port>"
+ " [-h <ca_certchain_file>]"
" [options] [<server_address>] <server_port>\n");
(void) fprintf(stderr, "ksslcfg create"
- " -f pkcs12 -i <certificate_file> -x <proxy_port>"
+ " -f pkcs12 -i <cert_and_key_pk12file> -x <proxy_port>"
" [options] [<server_address>] <server_port>\n");
(void) fprintf(stderr, "ksslcfg create"
- " -f pem -i <certificate_file> -x <proxy_port>"
+ " -f pem -i <cert_and_key_pemfile> -x <proxy_port>"
" [options] [<server_address>] <server_port>\n");
(void) fprintf(stderr, gettext("options are:\n"));
@@ -474,7 +475,7 @@ do_create(int argc, char *argv[])
* of the arguments. This is the reason we ignore optarg
* for some of the cases below.
*/
- while ((c = getopt(argc, argv, "vT:d:f:i:p:c:C:t:u:x:z:")) != -1) {
+ while ((c = getopt(argc, argv, "vT:d:f:h:i:p:c:C:t:u:x:z:")) != -1) {
switch (c) {
case 'd':
break;
@@ -486,6 +487,8 @@ do_create(int argc, char *argv[])
case 'f':
format = optarg;
break;
+ case 'h':
+ break;
case 'i':
filename = optarg;
break;