diff options
author | krishna <none@none> | 2006-05-04 17:20:55 -0700 |
---|---|---|
committer | krishna <none@none> | 2006-05-04 17:20:55 -0700 |
commit | 164c0dd6f561db19bdaf1d0b7f2a8dec44355b69 (patch) | |
tree | f17c82e0a0cbdb749d3863b145b236e2711afa38 /usr/src/cmd | |
parent | 769b977d34538d5f208de3a6178f04cb0876b7ca (diff) | |
download | illumos-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')
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; |