summaryrefslogtreecommitdiff
path: root/openssl0.9.8
diff options
context:
space:
mode:
authorIgor Pashev <igor.pashev@nexenta.com>2012-10-26 17:19:15 +0400
committerIgor Pashev <igor.pashev@nexenta.com>2012-10-26 17:19:15 +0400
commita5fa80e2a069e35331af10369d810b4daa63635b (patch)
treecde72d630e4066581f9818b3a506b6433e343923 /openssl0.9.8
parenta66434a8c8bc288d863e0f649e8e465ac4525043 (diff)
downloadcibs-pkgs-a5fa80e2a069e35331af10369d810b4daa63635b.tar.gz
openssl 0.9.8 mostly done
Diffstat (limited to 'openssl0.9.8')
-rw-r--r--openssl0.9.8/Makefile88
-rw-r--r--openssl0.9.8/engines/devcrypto/e_devcrypto.c1278
-rw-r--r--openssl0.9.8/engines/devcrypto/e_devcrypto_err.c124
-rw-r--r--openssl0.9.8/engines/devcrypto/e_devcrypto_err.h61
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11.c3837
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11.h248
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11_err.c307
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11_err.h236
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11_pub.c3236
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11_uri.c870
-rw-r--r--openssl0.9.8/engines/pkcs11/hw_pk11_uri.h107
-rw-r--r--openssl0.9.8/openssl-header.p5m92
-rw-r--r--openssl0.9.8/openssl.p5m44
-rw-r--r--openssl0.9.8/patches/15-pkcs11_engine-0.9.8a.patch131
-rw-r--r--openssl0.9.8/patches/28-enginesdir.patch59
-rw-r--r--openssl0.9.8/patches/29-devcrypto_engine.patch52
-rw-r--r--openssl0.9.8/patches/CVE-2010-2939.patch12
-rw-r--r--openssl0.9.8/patches/CVE-2010-3864.patch45
-rw-r--r--openssl0.9.8/patches/CVE-2010-4180.patch63
-rw-r--r--openssl0.9.8/patches/CVE-2011-0014.patch27
-rw-r--r--openssl0.9.8/patches/CVE-2011-1945.patch23
-rw-r--r--openssl0.9.8/patches/CVE-2011-4109.patch60
-rw-r--r--openssl0.9.8/patches/CVE-2011-4576.patch14
-rw-r--r--openssl0.9.8/patches/CVE-2011-4619.patch104
-rw-r--r--openssl0.9.8/patches/CVE-2012-1165.patch22
-rw-r--r--openssl0.9.8/patches/CVE-2012-2131.patch28
-rw-r--r--openssl0.9.8/patches/CVE-2012-2333.patch13
-rw-r--r--openssl0.9.8/patches/block_diginotar.patch59
-rw-r--r--openssl0.9.8/patches/ca.patch20
-rw-r--r--openssl0.9.8/patches/debian-targets.patch56
-rw-r--r--openssl0.9.8/patches/dtls-fragment-alert.patch33
-rw-r--r--openssl0.9.8/patches/kfreebsd-pipe.patch13
-rw-r--r--openssl0.9.8/patches/make-targets.patch13
-rw-r--r--openssl0.9.8/patches/man-dir.patch13
-rw-r--r--openssl0.9.8/patches/man-section.patch32
-rw-r--r--openssl0.9.8/patches/no-rpath.patch13
-rw-r--r--openssl0.9.8/patches/no-symbolic.patch13
-rw-r--r--openssl0.9.8/patches/perl-path.diff760
-rw-r--r--openssl0.9.8/patches/pic.patch301
-rw-r--r--openssl0.9.8/patches/pkg-config.patch34
-rw-r--r--openssl0.9.8/patches/rc4-amd64.patch14
-rw-r--r--openssl0.9.8/patches/rehash-crt.patch33
-rw-r--r--openssl0.9.8/patches/rehash_pod.patch60
-rw-r--r--openssl0.9.8/patches/shared-lib-ext.patch14
-rw-r--r--openssl0.9.8/patches/stddef.patch12
-rw-r--r--openssl0.9.8/patches/valgrind.patch15
-rw-r--r--openssl0.9.8/wrapper-opensslconf.h11
47 files changed, 12700 insertions, 0 deletions
diff --git a/openssl0.9.8/Makefile b/openssl0.9.8/Makefile
new file mode 100644
index 0000000..e00cae3
--- /dev/null
+++ b/openssl0.9.8/Makefile
@@ -0,0 +1,88 @@
+include /usr/share/cibs/rules/ips.mk
+include /usr/share/cibs/rules/archive.mk
+include /usr/share/cibs/rules/patch.mk
+include /usr/share/cibs/rules/32.mk
+include /usr/share/cibs/rules/64.mk
+include /usr/share/cibs/rules/copy.mk
+# it is not autotools, but quite close to them.
+include /usr/share/cibs/rules/autotools.mk
+
+
+description := Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) \
+ and Transport Layer Security (TLS v1) protocols as well \
+ as a full-strength general purpose cryptography library
+
+license := OpenSSL
+license-file := LICENSE
+
+build-depends += \
+
+name := openssl
+home := http://www.openssl.org
+version-base := 0.9.8
+ips-version := $(version-base).23
+version := $(version-base)x
+archive := $(name)-$(version).tar.gz
+download := $(home)/source/$(archive)
+checksum := \
+ md5:ee17e9bc805c8cc7d0afac3b0ef78eda \
+ sha1:8c3be5160513c0af1e558d3f932390ecb16f59e9 \
+ sha256:7ce0c7f2c451070b4497ea7ca6f23eba6cef1a56db2e86e433f65926a7bc7497 \
+ size:3782486
+
+configure = ./Configure
+configure-env =
+
+configure-options.32 = solaris-x86-gcc
+configure-options.64 = solaris64-x86_64-gcc
+
+pkcs11.32 = /usr/lib/libpkcs11.so.1
+pkcs11.64 = /usr/lib/64/libpkcs11.so.1
+
+# We've patched Configure to support this:
+enginesdir.32 = /usr/lib/openssl-$(version-base)/engines
+enginesdir.64 = /usr/lib/openssl-$(version-base)/engines/64
+
+# Yeah...
+libdir.32 = lib
+libdir.64 = lib/$(mach64)
+
+configure-options = \
+ -DSOLARIS_OPENSSL \
+ -DNO_WINDOWS_BRAINDEATH \
+ --pk11-libname=$(pkcs11.$(bits)) \
+ --prefix=/usr \
+ --openssldir=/etc/openssl \
+ --install_prefix=$(protodir.$(bits)) \
+ --enginesdir=$(enginesdir.$(bits)) \
+ --libdir=$(libdir.$(bits)) \
+ $(configure-options.$(bits)) \
+ no-ec \
+ no-ecdh \
+ no-ecdsa \
+ no-rc3 \
+ no-rc5 \
+ no-mdc2 \
+ no-idea \
+ no-hw_4758_cca \
+ no-hw_aep \
+ no-hw_atalla \
+ no-hw_chil \
+ no-hw_gmp \
+ no-hw_ncipher \
+ no-hw_nuron \
+ no-hw_padlock \
+ no-hw_sureware \
+ no-hw_ubsec \
+ no-hw_cswift \
+ threads \
+ shared \
+ no-static \
+
+patch-stamp: add-source-stamp
+add-source-stamp:
+ cp engines/pkcs11/* $(sourcedir)/crypto/engine/
+ cp engines/devcrypto/* $(sourcedir)/engines/
+ touch $@
+
+
diff --git a/openssl0.9.8/engines/devcrypto/e_devcrypto.c b/openssl0.9.8/engines/devcrypto/e_devcrypto.c
new file mode 100644
index 0000000..2b64f82
--- /dev/null
+++ b/openssl0.9.8/engines/devcrypto/e_devcrypto.c
@@ -0,0 +1,1278 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ *
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#pragma ident "@(#)e_devcrypto.c 1.1 10/10/19 SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include <sys/crypto/ioctl.h>
+#include <sys/crypto/api.h>
+#include <openssl/bio.h>
+#include <openssl/aes.h>
+#include <openssl/engine.h>
+#include <security/cryptoki.h>
+
+#define DEVCRYPTO_LIB_NAME "devcrypto engine"
+#include "e_devcrypto_err.c"
+
+/* DEVCRYPTO CONTEXT */
+typedef struct devcrypto_ctx {
+ uint_t session_id;
+} devcrypto_ctx_t;
+
+/* Index for the supported ciphers */
+typedef enum {
+ DEV_DES_CBC,
+ DEV_DES3_CBC,
+ DEV_DES_ECB,
+ DEV_DES3_ECB,
+ DEV_RC4,
+ DEV_AES_128_CBC,
+ DEV_AES_192_CBC,
+ DEV_AES_256_CBC,
+ DEV_AES_128_ECB,
+ DEV_AES_192_ECB,
+ DEV_AES_256_ECB,
+ DEV_BLOWFISH_CBC,
+ DEV_AES_128_CTR,
+ DEV_AES_192_CTR,
+ DEV_AES_256_CTR,
+ DEV_CIPHER_MAX
+} DEV_CIPHER_ID;
+
+typedef struct devcrypto_cipher {
+ DEV_CIPHER_ID id;
+ int nid;
+ int iv_len;
+ int min_key_len;
+ int max_key_len;
+ CK_KEY_TYPE key_type;
+ CK_MECHANISM_TYPE mech_type;
+ crypto_mech_type_t pn_internal_number;
+} devcrypto_cipher_t;
+
+
+/* Constants used when creating the ENGINE */
+static const char *ENGINE_DEVCRYPTO_ID = "devcrypto";
+static const char *ENGINE_DEVCRYPTO_NAME = "/dev/crypto engine support";
+static const char *CRYPTO_DEVICE = "/dev/crypto";
+
+/* static variables */
+static int kernel_fd = -1;
+static int kernel_fd_ref = 0;
+static int slot_count = 0;
+static CK_SLOT_ID *kernel_provider_id = NULL;
+static int cipher_count = 0;
+static int *cipher_nids = NULL;
+pthread_mutex_t *kernel_fd_lock;
+
+/*
+ * NIDs for AES counter mode. They will be defined during the engine
+ * initialization.
+ */
+static int NID_aes_128_ctr = NID_undef;
+static int NID_aes_192_ctr = NID_undef;
+static int NID_aes_256_ctr = NID_undef;
+
+/*
+ * Cipher Table for all supported symmetric ciphers.
+ */
+static devcrypto_cipher_t cipher_table[] = {
+ { DEV_DES_CBC, NID_des_cbc, 8, 8, 8,
+ CKK_DES, CKM_DES_CBC, CRYPTO_MECH_INVALID},
+ { DEV_DES3_CBC, NID_des_ede3_cbc, 8, 24, 24,
+ CKK_DES3, CKM_DES3_CBC, CRYPTO_MECH_INVALID},
+ { DEV_DES_ECB, NID_des_ecb, 0, 8, 8,
+ CKK_DES, CKM_DES_ECB, CRYPTO_MECH_INVALID},
+ { DEV_DES3_ECB, NID_des_ede3_ecb, 0, 24, 24,
+ CKK_DES3, CKM_DES3_ECB, CRYPTO_MECH_INVALID},
+ { DEV_RC4, NID_rc4, 0, 16, 256,
+ CKK_RC4, CKM_RC4, CRYPTO_MECH_INVALID},
+ { DEV_AES_128_CBC, NID_aes_128_cbc, 16, 16, 16,
+ CKK_AES, CKM_AES_CBC, CRYPTO_MECH_INVALID},
+ { DEV_AES_192_CBC, NID_aes_192_cbc, 16, 24, 24,
+ CKK_AES, CKM_AES_CBC, CRYPTO_MECH_INVALID},
+ { DEV_AES_256_CBC, NID_aes_256_cbc, 16, 32, 32,
+ CKK_AES, CKM_AES_CBC, CRYPTO_MECH_INVALID},
+ { DEV_AES_128_ECB, NID_aes_128_ecb, 0, 16, 16,
+ CKK_AES, CKM_AES_ECB, CRYPTO_MECH_INVALID},
+ { DEV_AES_192_ECB, NID_aes_192_ecb, 0, 24, 24,
+ CKK_AES, CKM_AES_ECB, CRYPTO_MECH_INVALID},
+ { DEV_AES_256_ECB, NID_aes_256_ecb, 0, 32, 32,
+ CKK_AES, CKM_AES_ECB, CRYPTO_MECH_INVALID},
+ { DEV_BLOWFISH_CBC, NID_bf_cbc, 8, 16, 16,
+ CKK_BLOWFISH, CKM_BLOWFISH_CBC, CRYPTO_MECH_INVALID},
+ /*
+ * For the following 3 AES counter mode entries, we don't know the
+ * NIDs until the engine is initialized
+ */
+ { DEV_AES_128_CTR, NID_undef, 16, 16, 16,
+ CKK_AES, CKM_AES_CTR, CRYPTO_MECH_INVALID},
+ { DEV_AES_192_CTR, NID_undef, 16, 24, 24,
+ CKK_AES, CKM_AES_CTR, CRYPTO_MECH_INVALID},
+ { DEV_AES_256_CTR, NID_undef, 16, 32, 32,
+ CKK_AES, CKM_AES_CTR, CRYPTO_MECH_INVALID},
+ };
+
+
+/* Formal declaration for functions in EVP_CIPHER structure */
+static int devcrypto_cipher_init(EVP_CIPHER_CTX *, const unsigned char *,
+ const unsigned char *, int);
+static int devcrypto_cipher_do_cipher(EVP_CIPHER_CTX *, unsigned char *,
+ const unsigned char *, unsigned int);
+static int devcrypto_cipher_cleanup(EVP_CIPHER_CTX *);
+
+/* OpenSSL's libcrypto EVP stuff. This is how this engine gets wired to EVP. */
+static const EVP_CIPHER dev_des_cbc = {
+ NID_des_cbc,
+ 8, 8, 8,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+static const EVP_CIPHER dev_3des_cbc = {
+ NID_des_ede3_cbc,
+ 8, 24, 8,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+/*
+ * ECB modes don't use an Initial Vector, therefore set_asn1_parameters and
+ * get_asn1_parameters fields are set to NULL.
+ */
+static const EVP_CIPHER dev_des_ecb = {
+ NID_des_ecb,
+ 8, 8, 8,
+ EVP_CIPH_ECB_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_3des_ecb = {
+ NID_des_ede3_ecb,
+ 8, 24, 8,
+ EVP_CIPH_ECB_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_rc4 = {
+ NID_rc4,
+ 1, 16, 0,
+ EVP_CIPH_VARIABLE_LENGTH,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_aes_128_cbc = {
+ NID_aes_128_cbc,
+ 16, 16, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+static const EVP_CIPHER dev_aes_192_cbc = {
+ NID_aes_192_cbc,
+ 16, 24, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+static const EVP_CIPHER dev_aes_256_cbc = {
+ NID_aes_256_cbc,
+ 16, 32, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+
+/*
+ * ECB modes don't use IV, therefore set_asn1_parameters and
+ * get_asn1_parameters are set to NULL.
+ */
+static const EVP_CIPHER dev_aes_128_ecb = {
+ NID_aes_128_ecb,
+ 16, 16, 0,
+ EVP_CIPH_ECB_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_aes_192_ecb = {
+ NID_aes_192_ecb,
+ 16, 24, 0,
+ EVP_CIPH_ECB_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_aes_256_ecb = {
+ NID_aes_256_ecb,
+ 16, 32, 0,
+ EVP_CIPH_ECB_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ NULL,
+ NULL,
+ NULL
+};
+
+static const EVP_CIPHER dev_bf_cbc = {
+ NID_bf_cbc,
+ 8, 16, 8,
+ EVP_CIPH_VARIABLE_LENGTH,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+
+/*
+ * NID_undef's will be changed for AES counter mode, as soon they are created.
+ */
+static EVP_CIPHER dev_aes_128_ctr = {
+ NID_undef,
+ 16, 16, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+static EVP_CIPHER dev_aes_192_ctr = {
+ NID_undef,
+ 16, 24, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+static EVP_CIPHER dev_aes_256_ctr = {
+ NID_undef,
+ 16, 32, 16,
+ EVP_CIPH_CBC_MODE,
+ devcrypto_cipher_init,
+ devcrypto_cipher_do_cipher,
+ devcrypto_cipher_cleanup,
+ sizeof (devcrypto_ctx_t),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+};
+
+
+
+/*
+ * This function creates a new NID.
+ */
+static int
+devcrypto_add_NID(char *sn, char *ln)
+{
+ ASN1_OBJECT *o;
+ int nid;
+
+ if ((o = ASN1_OBJECT_create(OBJ_new_nid(1), (unsigned char *)"",
+ 1, sn, ln)) == NULL) {
+ return (0);
+ }
+
+ nid = OBJ_add_object(o); /* will return NID_undef on error */
+ ASN1_OBJECT_free(o);
+ return (nid);
+}
+
+
+/*
+ * This function creates new NIDs for AES counter mode algorithms.
+ * Note that OpenSSL doesn't support them now so we have to help
+ * ourselves here.
+ */
+static int
+devcrypto_add_aes_ctr_NIDs(void)
+{
+ if (NID_aes_256_ctr != NID_undef) /* already set */
+ return (1);
+
+ NID_aes_128_ctr = devcrypto_add_NID("AES-128-CTR", "aes-128-ctr");
+ if (NID_aes_128_ctr == NID_undef)
+ goto failed;
+ cipher_table[DEV_AES_128_CTR].nid =
+ dev_aes_128_ctr.nid = NID_aes_128_ctr;
+
+ NID_aes_192_ctr = devcrypto_add_NID("AES-192-CTR", "aes-192-ctr");
+ if (NID_aes_192_ctr == NID_undef)
+ goto failed;
+ cipher_table[DEV_AES_192_CTR].nid =
+ dev_aes_192_ctr.nid = NID_aes_192_ctr;
+
+ NID_aes_256_ctr = devcrypto_add_NID("AES-256-CTR", "aes-256-ctr");
+ if (NID_aes_256_ctr == NID_undef)
+ goto failed;
+ cipher_table[DEV_AES_256_CTR].nid =
+ dev_aes_256_ctr.nid = NID_aes_256_ctr;
+
+ return (1);
+
+failed:
+ return (0);
+}
+
+
+static void
+devcrypto_free_aes_ctr_NIDs(void)
+{
+ ASN1_OBJECT *ob = NULL;
+
+ if (NID_aes_128_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_128_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+
+ if (NID_aes_192_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_192_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+
+ if (NID_aes_256_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_256_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+}
+
+/*
+ * Open the /dev/crypto device
+ */
+static int
+devcrypto_open()
+{
+ int fd = -1;
+
+ if (kernel_fd != -1) { /* already open */
+ (void) pthread_mutex_lock(kernel_fd_lock);
+ kernel_fd_ref++;
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+ return (1);
+ }
+
+ (void) pthread_mutex_lock(kernel_fd_lock);
+ fd = open(CRYPTO_DEVICE, O_RDWR);
+ if (fd == -1) {
+#ifdef DEBUG
+ (void) fprintf(stderr,
+ "libdevcrypto: open /dev/crypto failed, errno=%x\n",
+ errno);
+#endif
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+ return (0);
+ }
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto: failed to fcntl\n");
+#endif
+ (void) close(fd);
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+ return (0);
+ }
+
+ kernel_fd = fd;
+ kernel_fd_ref++;
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+ return (1);
+}
+
+
+/*
+ * This function gets the total number of hardware providers presented in
+ * the system first. If there is any hardware providers, then it will get
+ * the kernel provider id for each hardware slot also.
+ */
+static int
+devcrypto_get_slot_info()
+{
+ crypto_get_provider_list_t *pl = NULL;
+ int ret = 1;
+ int r;
+ int i;
+
+ /* Already have the information */
+ if (kernel_provider_id != NULL)
+ return (1);
+
+ /* Find out how many hardware slots are presented. */
+ pl = OPENSSL_malloc(sizeof (crypto_get_provider_list_t));
+ if (pl == NULL)
+ return (0);
+
+ pl->pl_count = 0;
+ while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ if (r < 0 || pl->pl_return_value != CRYPTO_SUCCESS) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:CRYPTO_GET_PROVIDER_LIST:"
+ "ret (r) = 0x%x, (rv) = 0x%x\n", r, pl->pl_return_value);
+#endif /* DEBUG */
+ ret = 0;
+ goto out;
+ }
+
+ slot_count = pl->pl_count;
+ if (slot_count == 0) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto: no hw providers\n");
+#endif /* DEBUG */
+ ret = 0;
+ goto out;
+ }
+
+ /* Get the provider ID for each slot from kernel and save it */
+ kernel_provider_id = OPENSSL_malloc(sizeof (CK_SLOT_ID) * slot_count);
+ if (kernel_provider_id == NULL) {
+ ret = 0;
+ goto out;
+ }
+
+ (void) OPENSSL_free(pl);
+ pl = OPENSSL_malloc(slot_count * sizeof (crypto_get_provider_list_t));
+ if (pl == NULL) {
+ ret = 0;
+ goto out;
+ }
+
+ pl->pl_count = slot_count;
+ while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ if (r < 0 || (pl->pl_return_value != CRYPTO_SUCCESS)) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:CRYPTO_GET_PROVIDER_LIST:"
+ "ret (r) = 0x%x, (rv) = 0x%x\n", r, pl->pl_return_value);
+#endif /* DEBUG */
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < slot_count; i++) {
+ kernel_provider_id[i] = pl->pl_list[i].pe_provider_id;
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto: i = %d, "
+ "kernel_provider_id = %d\n", i, kernel_provider_id[i]);
+#endif /* DEBUG */
+ }
+
+out:
+ if (pl != NULL)
+ (void) OPENSSL_free(pl);
+
+ if (ret == 0 && kernel_provider_id != NULL) {
+ (void) OPENSSL_free(kernel_provider_id);
+ kernel_provider_id = NULL;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * This function checks if the "nid" is already in the nid list.
+ */
+static int
+nid_in_list(int nid, int *nid_list, int count)
+{
+ int i = 0;
+
+ if (nid_list == NULL || count <= 0)
+ return (0);
+
+ while (i < count) {
+ if (nid == nid_list[i])
+ break;
+ i++;
+ }
+ return (i < count ? 1 : 0);
+}
+
+/*
+ * This function is to get all the ciphers supported by hardware providers.
+ * If this function is successfully completed, then the following 2 global
+ * variables will be set.
+ * cipher_count - the number of ciphers found in all hardware providers.
+ * cipher_nids - the nid list for all the ciphers.
+ */
+static int
+devcrypto_get_hw_ciphers(void)
+{
+ crypto_get_provider_mechanism_info_t mechinfo;
+ int max_cipher_count;
+ int *tmp_nids = NULL;
+ const char *mech_string;
+ int r;
+ int i, j;
+
+ if (slot_count <= 0) /* no hardware provider */
+ return (0);
+
+ max_cipher_count = slot_count * DEV_CIPHER_MAX + 1;
+ tmp_nids = OPENSSL_malloc(max_cipher_count * sizeof (int));
+ if (tmp_nids == NULL) {
+ /* not enough memory */
+ goto failed;
+ }
+
+ for (i = 0; i < slot_count; i++) {
+ mechinfo.mi_provider_id = kernel_provider_id[i];
+ for (j = 0; j < DEV_CIPHER_MAX; j++) {
+ mech_string =
+ pkcs11_mech2str(cipher_table[j].mech_type);
+ if (mech_string == NULL) {
+ continue; /* shouldn't happen; skip it */
+ }
+
+ (void) strlcpy(mechinfo.mi_mechanism_name,
+ mech_string, CRYPTO_MAX_MECH_NAME);
+ while ((r = ioctl(kernel_fd,
+ CRYPTO_GET_PROVIDER_MECHANISM_INFO,
+ &mechinfo)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ if (r < 0) {
+ goto failed;
+ }
+
+ if (mechinfo.mi_return_value == CRYPTO_SUCCESS) {
+ /*
+ * Found this mechanism in hardware providers.
+ * If it is not in the nid list yet, add it.
+ */
+ if (!nid_in_list(cipher_table[j].nid,
+ tmp_nids, cipher_count)) {
+ tmp_nids[cipher_count] =
+ cipher_table[j].nid;
+ cipher_count++;
+ }
+ }
+ }
+ }
+
+ if (cipher_count > 0) {
+ cipher_nids = tmp_nids;
+ }
+
+ return (1);
+
+failed:
+ if (r < 0 || cipher_count == 0) {
+ if (tmp_nids != NULL)
+ OPENSSL_free(tmp_nids);
+ }
+ return (0);
+}
+
+/*
+ * Registered by the ENGINE when used to find out how to deal with
+ * a particular NID in the ENGINE. This says what we'll do at the
+ * top level - note, that list is restricted by what we answer with.
+ */
+static int
+devcrypto_get_all_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+ const int **nids, int nid)
+{
+ if (!cipher) {
+ *nids = (cipher_count > 0) ? cipher_nids : NULL;
+ return (cipher_count);
+ }
+
+ switch (nid) {
+ case NID_des_cbc:
+ *cipher = &dev_des_cbc;
+ break;
+ case NID_des_ede3_cbc:
+ *cipher = &dev_3des_cbc;
+ break;
+ case NID_des_ecb:
+ *cipher = &dev_des_ecb;
+ break;
+ case NID_des_ede3_ecb:
+ *cipher = &dev_3des_ecb;
+ break;
+ case NID_rc4:
+ *cipher = &dev_rc4;
+ break;
+ case NID_aes_128_cbc:
+ *cipher = &dev_aes_128_cbc;
+ break;
+ case NID_aes_192_cbc:
+ *cipher = &dev_aes_192_cbc;
+ break;
+ case NID_aes_256_cbc:
+ *cipher = &dev_aes_256_cbc;
+ break;
+ case NID_aes_128_ecb:
+ *cipher = &dev_aes_128_ecb;
+ break;
+ case NID_aes_192_ecb:
+ *cipher = &dev_aes_192_ecb;
+ break;
+ case NID_aes_256_ecb:
+ *cipher = &dev_aes_256_ecb;
+ break;
+ case NID_bf_cbc:
+ *cipher = &dev_bf_cbc;
+ break;
+ default:
+ /*
+ * We cannot put the NIDs for AES counter mode in separated
+ * cases as above because they are not constants.
+ */
+ if (nid == NID_aes_128_ctr)
+ *cipher = &dev_aes_128_ctr;
+ else if (nid == NID_aes_192_ctr)
+ *cipher = &dev_aes_192_ctr;
+ else if (nid == NID_aes_256_ctr)
+ *cipher = &dev_aes_256_ctr;
+ else
+ *cipher = NULL;
+ break;
+ }
+
+ return (*cipher != NULL);
+}
+
+
+static int
+get_cipher_id_by_nid(int nid)
+{
+ int i;
+
+ for (i = 0; i < DEV_CIPHER_MAX; i++)
+ if (cipher_table[i].nid == nid)
+ return (cipher_table[i].id);
+ return (-1);
+}
+
+
+static int
+get_slotid_by_mechanism(const char *mech_string, CK_SLOT_ID *slot_id)
+{
+ crypto_get_provider_mechanism_info_t mechanism_info;
+ uint_t rv;
+ int r;
+ int i = 0;
+
+ (void) strlcpy(mechanism_info.mi_mechanism_name, mech_string,
+ CRYPTO_MAX_MECH_NAME);
+ while (i < slot_count) {
+ mechanism_info.mi_provider_id = kernel_provider_id[i];
+ while ((r = ioctl(kernel_fd,
+ CRYPTO_GET_PROVIDER_MECHANISM_INFO,
+ &mechanism_info)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ if (r < 0) {
+ return (0); /* ioctl function failed */
+ }
+ rv = mechanism_info.mi_return_value;
+ if (rv == 0) { /* found it */
+ *slot_id = kernel_provider_id[i];
+ return (1);
+ }
+ i++;
+ }
+
+ return (0);
+}
+
+
+static int
+devcrypto_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+{
+ devcrypto_ctx_t *devc_ctx = ctx->cipher_data;
+ crypto_encrypt_init_t encrypt_init;
+ crypto_decrypt_init_t decrypt_init;
+ crypto_open_session_t session;
+ crypto_get_mechanism_number_t get_number;
+ CK_AES_CTR_PARAMS aes_ctr_params;
+ devcrypto_cipher_t *the_cipher;
+ const char *mech_string;
+ CK_SLOT_ID slot_id;
+ int index;
+ int r;
+ uint_t rv = 0;
+
+
+ if (key == NULL) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_CIPHER_KEY);
+ return (0);
+ }
+
+ /* get the cipher entry index in cipher_table from nid */
+ index = get_cipher_id_by_nid(ctx->cipher->nid);
+ if (index < 0 || index >= DEV_CIPHER_MAX) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_CIPHER_NID);
+ return (0);
+ }
+ the_cipher = &cipher_table[index];
+
+ /* check key size */
+ if (ctx->cipher->iv_len < the_cipher->iv_len ||
+ ctx->key_len < the_cipher->min_key_len ||
+ ctx->key_len > the_cipher->max_key_len) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_KEY_OR_IV_LEN_PROBLEM);
+ return (0);
+ }
+
+ /* get the mechanism string */
+ mech_string = pkcs11_mech2str(the_cipher->mech_type);
+ if (mech_string == NULL) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_MECH_STRING);
+ return (0);
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto: mech_string=%s\n", mech_string);
+#endif
+
+ /* Find the slot that supports this mechanism */
+ if (!get_slotid_by_mechanism(mech_string, &slot_id)) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_FIND_SLOT_BY_MECH);
+#ifdef DEBUG
+ (void) fprintf(stderr,
+ "libdevcrypto: failed to find a slot with %s\n",
+ mech_string);
+#endif
+ return (0);
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto: found a slot with %s, "
+ "slot_id = %d\n", mech_string, slot_id);
+#endif
+
+ /* Open a session on this slot */
+ session.os_provider_id = slot_id;
+ session.os_flags = CKF_RW_SESSION | CKF_SERIAL_SESSION;
+ while ((r = ioctl(kernel_fd, CRYPTO_OPEN_SESSION, &session)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = session.os_return_value;
+ if (r || rv) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_OPEN_SESSION);
+#ifdef DEBUG
+ (void) fprintf(stderr,
+ "libdevcrypto:cipher_init:failed to open a session\n");
+#endif /* DEBUG */
+ goto failed;
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:cipher_init: open session = %d\n",
+ session.os_session);
+#endif /* DEBUG */
+
+ /* save the session_id */
+ devc_ctx->session_id = session.os_session;
+
+ /*
+ * Get the kernel mechanism number for this mechanism, if it has not
+ * been retrieved yet.
+ */
+ if (the_cipher->pn_internal_number == CRYPTO_MECH_INVALID) {
+ get_number.pn_mechanism_string = (char *)mech_string;
+ get_number.pn_mechanism_len = strlen(mech_string) + 1;
+ while ((r = ioctl(kernel_fd, CRYPTO_GET_MECHANISM_NUMBER,
+ &get_number)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = get_number.pn_return_value;
+ if (r || rv) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT,
+ DEVC_R_GET_MECHANISM_NUMBER);
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:cipher_init: "
+ "failed to get the kernel mech number.\n");
+#endif /* DEBUG */
+ goto failed;
+ }
+
+ the_cipher->pn_internal_number = get_number.pn_internal_number;
+ }
+
+ /* Crypto Init */
+ if (ctx->encrypt) {
+ encrypt_init.ei_session = session.os_session;
+ encrypt_init.ei_key.ck_format = CRYPTO_KEY_RAW;
+ encrypt_init.ei_key.ck_obj_id = 0;
+ encrypt_init.ei_key.ck_data = (void *) key;
+ encrypt_init.ei_key.ck_length = ctx->key_len * 8;
+ encrypt_init.ei_mech.cm_type = the_cipher->pn_internal_number;
+
+ if (ctx->cipher->nid == NID_aes_128_ctr ||
+ ctx->cipher->nid == NID_aes_192_ctr ||
+ ctx->cipher->nid == NID_aes_256_ctr) {
+ encrypt_init.ei_mech.cm_param =
+ (void *) (&aes_ctr_params);
+ encrypt_init.ei_mech.cm_param_len =
+ sizeof (aes_ctr_params);
+
+ aes_ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
+ OPENSSL_assert(ctx->cipher->iv_len == AES_BLOCK_SIZE);
+ (void) memcpy(aes_ctr_params.cb, ctx->iv,
+ AES_BLOCK_SIZE);
+ } else {
+ if (the_cipher->iv_len > 0) {
+ encrypt_init.ei_mech.cm_param =
+ (char *)ctx->iv;
+ encrypt_init.ei_mech.cm_param_len =
+ ctx->cipher->iv_len;
+ } else {
+ encrypt_init.ei_mech.cm_param = NULL;
+ encrypt_init.ei_mech.cm_param_len = 0;
+ }
+ }
+
+ while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT,
+ &encrypt_init)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = encrypt_init.ei_return_value;
+
+ } else {
+ decrypt_init.di_session = session.os_session;
+ decrypt_init.di_key.ck_format = CRYPTO_KEY_RAW;
+ decrypt_init.di_key.ck_obj_id = 0;
+ decrypt_init.di_key.ck_data = (void *) key;
+ decrypt_init.di_key.ck_length = ctx->key_len * 8;
+ decrypt_init.di_mech.cm_type = the_cipher->pn_internal_number;
+
+ if (ctx->cipher->nid == NID_aes_128_ctr ||
+ ctx->cipher->nid == NID_aes_192_ctr ||
+ ctx->cipher->nid == NID_aes_256_ctr) {
+ decrypt_init.di_mech.cm_param =
+ (void *)(&aes_ctr_params);
+ decrypt_init.di_mech.cm_param_len =
+ sizeof (aes_ctr_params);
+ aes_ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
+ OPENSSL_assert(ctx->cipher->iv_len == AES_BLOCK_SIZE);
+ (void) memcpy(aes_ctr_params.cb, ctx->iv,
+ AES_BLOCK_SIZE);
+ } else {
+ if (the_cipher->iv_len > 0) {
+ decrypt_init.di_mech.cm_param =
+ (char *)ctx->iv;
+ decrypt_init.di_mech.cm_param_len =
+ ctx->cipher->iv_len;
+ } else {
+ decrypt_init.di_mech.cm_param = NULL;
+ decrypt_init.di_mech.cm_param_len = 0;
+ }
+ }
+
+ while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT,
+ &decrypt_init)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = decrypt_init.di_return_value;
+ }
+
+failed:
+ if (r || rv) {
+ if (ctx->encrypt)
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_ENCRYPT_INIT);
+ else
+ DEVCRYPTOerr(DEVC_F_CIPHER_INIT, DEVC_R_DECRYPT_INIT);
+
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * ENCRYPT_UPDATE or DECRYPT_UPDATE
+ */
+static int
+devcrypto_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int inl)
+{
+ crypto_encrypt_update_t encrypt_update;
+ crypto_decrypt_update_t decrypt_update;
+ devcrypto_ctx_t *devc_ctx = ctx->cipher_data;
+ int r = 0, rv = 0;
+
+ if (ctx->encrypt) {
+ encrypt_update.eu_session = devc_ctx->session_id;
+ encrypt_update.eu_databuf = (char *)in;
+ encrypt_update.eu_datalen = inl;
+ encrypt_update.eu_encrbuf = (char *)out;
+ encrypt_update.eu_encrlen = inl;
+
+ while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE,
+ &encrypt_update)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = encrypt_update.eu_return_value;
+
+ } else { /* decrypt */
+ decrypt_update.du_session = devc_ctx->session_id;
+ decrypt_update.du_encrbuf = (char *)in;
+ decrypt_update.du_encrlen = inl;
+ decrypt_update.du_databuf = (char *)out;
+ decrypt_update.du_datalen = inl;
+
+ while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
+ &decrypt_update)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = decrypt_update.du_return_value;
+ }
+
+ if (r || rv) {
+ if (ctx->encrypt)
+ DEVCRYPTOerr(DEVC_F_CIPHER_DO_CIPHER,
+ DEVC_R_ENCRYPT_UPDATE);
+ else
+ DEVCRYPTOerr(DEVC_F_CIPHER_DO_CIPHER,
+ DEVC_R_DECRYPT_UPDATE);
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:crypto_do ret (r) = 0x%x,"
+ "crypto ret (rv) = 0x%x,", r, rv);
+#endif /* DEBUG */
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * ENCRYPT_FINAL or DECRYPT_FINAL
+ */
+static int
+devcrypto_cipher_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ crypto_encrypt_final_t encrypt_final;
+ crypto_decrypt_final_t decrypt_final;
+ crypto_close_session_t session;
+ devcrypto_ctx_t *devc_ctx = ctx->cipher_data;
+ char buf[EVP_MAX_BLOCK_LENGTH];
+ int r;
+ uint_t rv = 0;
+ int ret = 1;
+
+ if (ctx->encrypt) {
+ encrypt_final.ef_session = devc_ctx->session_id;
+ encrypt_final.ef_encrbuf = buf;
+ encrypt_final.ef_encrlen = sizeof (buf);
+ while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL,
+ &encrypt_final)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = encrypt_final.ef_return_value;
+
+ } else {
+ decrypt_final.df_session = devc_ctx->session_id;
+ decrypt_final.df_databuf = buf;
+ decrypt_final.df_datalen = sizeof (buf);
+ while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
+ &decrypt_final)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+ rv = decrypt_final.df_return_value;
+ }
+
+#ifdef DEBUG
+ if (ctx->encrypt)
+ (void) fprintf(stderr, "libdevcrypto:CRYPTO_ENCRYPT_FINAL "
+ "ret (r) = 0x%x, (rv) = 0x%x\n", r, rv);
+ else
+ (void) fprintf(stderr, "libdevcrypto:CRYPTO_DECRYPT_FINAL "
+ "ret (r) = 0x%x, (rv) = 0x%x\n", r, rv);
+#endif /* DEBUG */
+
+ if (r || rv) {
+ if (ctx->encrypt)
+ DEVCRYPTOerr(DEVC_F_CIPHER_CLEANUP,
+ DEVC_R_ENCRYPT_FINAL);
+ else
+ DEVCRYPTOerr(DEVC_F_CIPHER_CLEANUP,
+ DEVC_R_DECRYPT_FINAL);
+ ret = 0;
+ }
+
+ /* close the session */
+ session.cs_session = devc_ctx->session_id;
+ while ((r = ioctl(kernel_fd, CRYPTO_CLOSE_SESSION, &session)) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto:CRYPTO_CLOSE_SESSION, "
+ "session id = %d ret (r) = 0x%x, crypto ret (rv) = 0x%x\n",
+ devc_ctx->session_id, r, rv);
+#endif /* DEBUG */
+
+ if (r || rv) {
+ DEVCRYPTOerr(DEVC_F_CIPHER_CLEANUP, DEVC_R_CLOSE_SESSION);
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+static void
+devcrypto_cleanup()
+{
+ if (kernel_fd == -1)
+ return;
+
+ (void) pthread_mutex_lock(kernel_fd_lock);
+ kernel_fd_ref--;
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+
+ if (kernel_fd_ref == 0) {
+ (void) pthread_mutex_lock(kernel_fd_lock);
+ (void) close(kernel_fd);
+ kernel_fd = -1;
+ if (kernel_provider_id != NULL) {
+ OPENSSL_free(kernel_provider_id);
+ kernel_provider_id = NULL;
+ }
+ if (cipher_nids != NULL) {
+ OPENSSL_free(cipher_nids);
+ cipher_nids = NULL;
+ }
+ devcrypto_free_aes_ctr_NIDs();
+ (void) pthread_mutex_unlock(kernel_fd_lock);
+ (void) pthread_mutex_destroy(kernel_fd_lock);
+ OPENSSL_free(kernel_fd_lock);
+ kernel_fd_lock = NULL;
+ }
+}
+
+static int
+devcrypto_destroy(ENGINE *e)
+{
+ ERR_unload_devcrypto_strings();
+ return (1);
+}
+
+static int
+devcrypto_finish(ENGINE *e)
+{
+ devcrypto_cleanup();
+ return (1);
+}
+
+/*
+ * Set up the engine info and get the /dev/crypto engine ready.
+ */
+static int
+devcrypto_bind(ENGINE *e)
+{
+#ifdef DEBUG
+ int i;
+#endif
+
+ /* Get the NIDs for AES counter mode algorithms first. */
+ if (devcrypto_add_aes_ctr_NIDs() == 0) {
+ return (0);
+ }
+
+ /* Create a lock for the devcrypto device file descriptor */
+ if (kernel_fd_lock == NULL) {
+ kernel_fd_lock = OPENSSL_malloc(sizeof (pthread_mutex_t));
+ if (kernel_fd_lock == NULL) {
+ devcrypto_free_aes_ctr_NIDs();
+ return (0);
+ }
+
+ if (pthread_mutex_init(kernel_fd_lock, NULL) != 0) {
+ devcrypto_free_aes_ctr_NIDs();
+ OPENSSL_free(kernel_fd_lock);
+ kernel_fd_lock = NULL;
+ return (0);
+ }
+ }
+
+ /* Open the /dev/crypto device */
+ if (devcrypto_open() == 0) {
+ devcrypto_free_aes_ctr_NIDs();
+ pthread_mutex_destroy(kernel_fd_lock);
+ OPENSSL_free(kernel_fd_lock);
+ kernel_fd_lock = NULL;
+ return (0);
+ }
+
+ /* Get all hardware providers' information */
+ if (devcrypto_get_slot_info() == 0) {
+ goto failed;
+ }
+
+ if (devcrypto_get_hw_ciphers() == 0) {
+ goto failed;
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "cipher_count = %d\n", cipher_count);
+ for (i = 0; i < cipher_count; i++) {
+ (void) fprintf(stderr,
+ "cipher_nids[i] = %d\n", cipher_nids[i]);
+ }
+#endif /* DEBUG */
+
+ if (!ENGINE_set_id(e, ENGINE_DEVCRYPTO_ID) ||
+ !ENGINE_set_name(e, ENGINE_DEVCRYPTO_NAME) ||
+ !ENGINE_set_ciphers(e, devcrypto_get_all_ciphers) ||
+ !ENGINE_set_destroy_function(e, devcrypto_destroy) ||
+ !ENGINE_set_finish_function(e, devcrypto_finish)) {
+ goto failed;
+ }
+
+ /* Set up the devcrypto error handling */
+ ERR_load_devcrypto_strings();
+ return (1);
+
+failed:
+ devcrypto_cleanup();
+ return (0);
+}
+
+
+static int
+bind_helper(ENGINE *e, const char *id)
+{
+ if (id != NULL && (strcmp(id, ENGINE_DEVCRYPTO_ID) != 0)) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "libdevcrypto - bad engine id\n");
+#endif /* DEBUG */
+ return (0);
+ }
+ if (!devcrypto_bind(e)) {
+#ifdef DEBUG
+ (void) fprintf(stderr,
+ "libdevcrypto - failed to bind engine\n");
+#endif /* DEBUG */
+ return (0);
+ }
+
+ return (1);
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
diff --git a/openssl0.9.8/engines/devcrypto/e_devcrypto_err.c b/openssl0.9.8/engines/devcrypto/e_devcrypto_err.c
new file mode 100644
index 0000000..07f3986
--- /dev/null
+++ b/openssl0.9.8/engines/devcrypto/e_devcrypto_err.c
@@ -0,0 +1,124 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ *
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#pragma ident "@(#)e_devcrypto_err.c 1.1 10/10/19 SMI"
+
+#include "e_devcrypto_err.h"
+
+/* BEGIN ERROR CODES */
+
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(0, func, 0)
+#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
+
+static ERR_STRING_DATA devcrypto_str_functs[]=
+{
+{ ERR_FUNC(DEVC_F_INIT), "DEVCRYPTO_INIT"},
+{ ERR_FUNC(DEVC_F_DESTROY), "DEVCRYPTO_DESTROY"},
+{ ERR_FUNC(DEVC_F_FINISH), "DEVCRYPTO_FINISH"},
+{ ERR_FUNC(DEVC_F_CIPHER_INIT), "DEVCRYPTO_CIPHER_INIT"},
+{ ERR_FUNC(DEVC_F_CIPHER_DO_CIPHER), "DEVCRYPTO_CIPHER_DO_CIPHER"},
+{ ERR_FUNC(DEVC_F_CIPHER_CLEANUP), "DEVCRYPTO_CIPHER_CLEANUP"},
+{ 0, NULL}
+};
+
+static ERR_STRING_DATA devcrypto_str_reasons[]=
+{
+{ ERR_REASON(DEVC_R_CIPHER_KEY), "invalid cipher key"},
+{ ERR_REASON(DEVC_R_CIPHER_NID), "invalid cipher nid"},
+{ ERR_REASON(DEVC_R_KEY_OR_IV_LEN_PROBLEM), "IV or key length incorrect"},
+{ ERR_REASON(DEVC_R_MECH_STRING), "convert cipher type to string failed"},
+{ ERR_REASON(DEVC_R_FIND_SLOT_BY_MECH),
+ "no hardware providers support this cipher"},
+{ ERR_REASON(DEVC_R_OPEN_SESSION), "CRYPTO_OPEN_SESSION failed"},
+{ ERR_REASON(DEVC_R_GET_MECHANISM_NUMBER),
+ "CRYPTO_GET_MECHANISM_NUMBER failed"},
+{ ERR_REASON(DEVC_R_ENCRYPT_INIT), "CRYPTO_ENCRYPT_INIT failed"},
+{ ERR_REASON(DEVC_R_ENCRYPT_UPDATE), "CRYPTO_ENCRYPT_UPDATE failed"},
+{ ERR_REASON(DEVC_R_ENCRYPT_FINAL), "CRYPTO_ENCRYPT_FINAL failed"},
+{ ERR_REASON(DEVC_R_DECRYPT_INIT), "CRYPTO_DECRYPT_INIT failed"},
+{ ERR_REASON(DEVC_R_DECRYPT_UPDATE), "CRYPTO_DECRYPT_UPDATE failed"},
+{ ERR_REASON(DEVC_R_DECRYPT_FINAL), "CRYPTO_DECRYPT_FINAL failed"},
+{ ERR_REASON(DEVC_R_CLOSE_SESSION), "CRYPTO_CLOSE_SESSION failed"},
+{ 0, NULL}
+};
+#endif /* OPENSSL_NO_ERR */
+
+
+#ifdef DEVCRYPTO_LIB_NAME
+static ERR_STRING_DATA DEVCRYPTO_lib_name[]=
+{
+{0, DEVCRYPTO_LIB_NAME},
+{0, NULL}
+};
+#endif
+
+static int devcrypto_error_code = 0;
+static int devcrypto_error_init = 1;
+
+static void
+ERR_load_devcrypto_strings(void)
+{
+ if (devcrypto_error_code == 0)
+ devcrypto_error_code = ERR_get_next_error_library();
+
+ if (devcrypto_error_init) {
+ devcrypto_error_init = 0;
+
+#ifndef OPENSSL_NO_ERR
+ ERR_load_strings(devcrypto_error_code, devcrypto_str_functs);
+ ERR_load_strings(devcrypto_error_code, devcrypto_str_reasons);
+#endif
+
+#ifdef DEVCRYPTO_LIB_NAME
+ DEVCRYPTO_lib_name->error =
+ ERR_PACK(devcrypto_error_code, 0, 0);
+ ERR_load_strings(0, DEVCRYPTO_lib_name);
+#endif
+ }
+}
+
+static void
+ERR_unload_devcrypto_strings(void)
+{
+ if (devcrypto_error_init == 0) {
+#ifndef OPENSSL_NO_ERR
+ ERR_unload_strings(devcrypto_error_code, devcrypto_str_functs);
+ ERR_unload_strings(devcrypto_error_code, devcrypto_str_reasons);
+#endif
+
+#ifdef DEVCRYPTO_LIB_NAME
+ ERR_unload_strings(0, DEVCRYPTO_lib_name);
+#endif
+ devcrypto_error_init = 1;
+ }
+}
+
+static void
+ERR_devcrypto_error(int function, int reason, char *file, int line)
+{
+ if (devcrypto_error_code == 0)
+ devcrypto_error_code = ERR_get_next_error_library();
+ ERR_PUT_error(devcrypto_error_code, function, reason, file, line);
+}
diff --git a/openssl0.9.8/engines/devcrypto/e_devcrypto_err.h b/openssl0.9.8/engines/devcrypto/e_devcrypto_err.h
new file mode 100644
index 0000000..9abbe95
--- /dev/null
+++ b/openssl0.9.8/engines/devcrypto/e_devcrypto_err.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ *
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#pragma ident "@(#)e_devcrypto_err.h 1.1 10/10/19 SMI"
+
+#ifndef HEADER_DEVCRYPTO_ERR_H
+#define HEADER_DEVCRYPTO_ERR_H
+
+static void ERR_load_devcrypto_strings(void);
+static void ERR_unload_devcrypto_strings(void);
+static void ERR_devcrypto_error(int function, int reason, char *file, int line);
+
+#define DEVCRYPTOerr(f, r) ERR_devcrypto_error((f), (r), __FILE__, __LINE__)
+
+
+/* Function codes */
+#define DEVC_F_INIT 100
+#define DEVC_F_DESTROY 101
+#define DEVC_F_FINISH 102
+#define DEVC_F_CIPHER_INIT 103
+#define DEVC_F_CIPHER_DO_CIPHER 104
+#define DEVC_F_CIPHER_CLEANUP 105
+
+
+/* Reason codes */
+#define DEVC_R_CIPHER_KEY 100
+#define DEVC_R_CIPHER_NID 101
+#define DEVC_R_KEY_OR_IV_LEN_PROBLEM 102
+#define DEVC_R_MECH_STRING 103
+#define DEVC_R_FIND_SLOT_BY_MECH 104
+#define DEVC_R_OPEN_SESSION 105
+#define DEVC_R_GET_MECHANISM_NUMBER 106
+#define DEVC_R_ENCRYPT_INIT 107
+#define DEVC_R_ENCRYPT_UPDATE 108
+#define DEVC_R_ENCRYPT_FINAL 109
+#define DEVC_R_DECRYPT_INIT 110
+#define DEVC_R_DECRYPT_UPDATE 111
+#define DEVC_R_DECRYPT_FINAL 112
+#define DEVC_R_CLOSE_SESSION 113
+
+#endif /* HEADER_DEVCRYPTO_ERR_H */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11.c b/openssl0.9.8/engines/pkcs11/hw_pk11.c
new file mode 100644
index 0000000..6107744
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11.c
@@ -0,0 +1,3837 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* crypto/engine/hw_pk11.c */
+/*
+ * This product includes software developed by the OpenSSL Project for
+ * use in the OpenSSL Toolkit (http://www.openssl.org/).
+ *
+ * This project also referenced hw_pkcs11-0.9.7b.patch written by
+ * Afchine Madjlessi.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * the documentation and/or other materials provided with the
+ * 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).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <openssl/e_os2.h>
+#include <openssl/crypto.h>
+#include <openssl/engine.h>
+#include <openssl/dso.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+#include <openssl/pem.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/aes.h>
+#include <cryptlib.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#ifndef OPENSSL_NO_HW
+#ifndef OPENSSL_NO_HW_PK11
+
+/* label for debug messages printed on stderr */
+#define PK11_DBG "PKCS#11 ENGINE DEBUG"
+/* prints a lot of debug messages on stderr about slot selection process */
+#undef DEBUG_SLOT_SELECTION
+/*
+ * Solaris specific code. See comment at check_hw_mechanisms() for more
+ * information.
+ */
+#if defined(__SVR4) && defined(__sun)
+#define SOLARIS_HW_SLOT_SELECTION
+#endif
+
+/*
+ * AES counter mode is not supported in the OpenSSL EVP API yet and neither
+ * there are official OIDs for mechanisms based on this mode. With our changes,
+ * an application can define its own EVP calls for AES counter mode and then
+ * it can make use of hardware acceleration through this engine. However, it's
+ * better if we keep AES CTR support code under ifdef's.
+ */
+#define SOLARIS_AES_CTR
+
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include "hw_pk11.h"
+#include "hw_pk11_uri.h"
+
+#define PK11_ENGINE_LIB_NAME "PKCS#11 engine"
+#include "hw_pk11_err.c"
+
+#ifdef SOLARIS_AES_CTR
+/*
+ * NIDs for AES counter mode that will be defined during the engine
+ * initialization.
+ */
+int NID_aes_128_ctr = NID_undef;
+int NID_aes_192_ctr = NID_undef;
+int NID_aes_256_ctr = NID_undef;
+#endif /* SOLARIS_AES_CTR */
+
+/*
+ * We use this lock to prevent multiple C_Login()s, guard getpassphrase(),
+ * uri_struct manipulation, and static token info. All of that is used by the
+ * RSA keys by reference feature.
+ */
+pthread_mutex_t *uri_lock;
+
+#ifdef SOLARIS_HW_SLOT_SELECTION
+/*
+ * Tables for symmetric ciphers and digest mechs found in the pkcs11_kernel
+ * library. See comment at check_hw_mechanisms() for more information.
+ */
+int *hw_cnids;
+int *hw_dnids;
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+
+/* PKCS#11 session caches and their locks for all operation types */
+static PK11_CACHE session_cache[OP_MAX];
+
+/*
+ * We cache the flags so that we do not have to run C_GetTokenInfo() again when
+ * logging into the token.
+ */
+CK_FLAGS pubkey_token_flags;
+
+/*
+ * As stated in v2.20, 11.7 Object Management Function, in section for
+ * C_FindObjectsInit(), at most one search operation may be active at a given
+ * time in a given session. Therefore, C_Find{,Init,Final}Objects() should be
+ * grouped together to form one atomic search operation. This is already
+ * ensured by the property of unique PKCS#11 session handle used for each
+ * PK11_SESSION object.
+ *
+ * This is however not the biggest concern - maintaining consistency of the
+ * underlying object store is more important. The same section of the spec also
+ * says that one thread can be in the middle of a search operation while another
+ * thread destroys the object matching the search template which would result in
+ * invalid handle returned from the search operation.
+ *
+ * Hence, the following locks are used for both protection of the object stores.
+ * They are also used for active list protection.
+ */
+pthread_mutex_t *find_lock[OP_MAX] = { NULL };
+
+/*
+ * lists of asymmetric key handles which are active (referenced by at least one
+ * PK11_SESSION structure, either held by a thread or present in free_session
+ * list) for given algorithm type
+ */
+PK11_active *active_list[OP_MAX] = { NULL };
+
+/*
+ * Create all secret key objects in a global session so that they are available
+ * to use for other sessions. These other sessions may be opened or closed
+ * without losing the secret key objects.
+ */
+static CK_SESSION_HANDLE global_session = CK_INVALID_HANDLE;
+
+/* ENGINE level stuff */
+static int pk11_init(ENGINE *e);
+static int pk11_library_init(ENGINE *e);
+static int pk11_finish(ENGINE *e);
+static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
+static int pk11_destroy(ENGINE *e);
+
+/* RAND stuff */
+static void pk11_rand_seed(const void *buf, int num);
+static void pk11_rand_add(const void *buf, int num, double add_entropy);
+static void pk11_rand_cleanup(void);
+static int pk11_rand_bytes(unsigned char *buf, int num);
+static int pk11_rand_status(void);
+
+/* These functions are also used in other files */
+PK11_SESSION *pk11_get_session(PK11_OPTYPE optype);
+void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype);
+
+/* active list manipulation functions used in this file */
+extern int pk11_active_delete(CK_OBJECT_HANDLE h, PK11_OPTYPE type);
+extern void pk11_free_active_list(PK11_OPTYPE type);
+
+#ifndef OPENSSL_NO_RSA
+int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
+int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
+int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
+#endif
+#ifndef OPENSSL_NO_DSA
+int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
+int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
+int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
+#endif
+#ifndef OPENSSL_NO_DH
+int pk11_destroy_dh_key_objects(PK11_SESSION *session);
+int pk11_destroy_dh_object(PK11_SESSION *session, CK_BBOOL uselock);
+#endif
+
+/* Local helper functions */
+static int pk11_free_all_sessions(void);
+static int pk11_free_session_list(PK11_OPTYPE optype);
+static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype);
+static int pk11_destroy_cipher_key_objects(PK11_SESSION *session);
+static int pk11_destroy_object(CK_SESSION_HANDLE handle, CK_OBJECT_HANDLE oh,
+ CK_BBOOL persistent);
+static const char *get_PK11_LIBNAME(void);
+static void free_PK11_LIBNAME(void);
+static long set_PK11_LIBNAME(const char *name);
+
+/* Symmetric cipher and digest support functions */
+static int cipher_nid_to_pk11(int nid);
+#ifdef SOLARIS_AES_CTR
+static int pk11_add_NID(char *sn, char *ln);
+static int pk11_add_aes_ctr_NIDs(void);
+#endif /* SOLARIS_AES_CTR */
+static int pk11_usable_ciphers(const int **nids);
+static int pk11_usable_digests(const int **nids);
+static int pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc);
+static int pk11_cipher_final(PK11_SESSION *sp);
+static int pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int inl);
+static int pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx);
+static int pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+ const int **nids, int nid);
+static int pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
+ const int **nids, int nid);
+static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
+ const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp);
+static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
+ int key_len);
+static int md_nid_to_pk11(int nid);
+static int pk11_digest_init(EVP_MD_CTX *ctx);
+static int pk11_digest_update(EVP_MD_CTX *ctx, const void *data,
+ size_t count);
+static int pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md);
+static int pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from);
+static int pk11_digest_cleanup(EVP_MD_CTX *ctx);
+
+static int pk11_choose_slots(int *any_slot_found);
+static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
+ CK_SLOT_ID current_slot, int *current_slot_n_cipher,
+ int *local_cipher_nids);
+static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
+ CK_SLOT_ID current_slot, int *current_slot_n_digest,
+ int *local_digest_nids);
+static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR, int slot_id,
+ CK_MECHANISM_TYPE mech, int *current_slot_n_cipher, int *local_cipher_nids,
+ int id);
+static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
+ CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
+ int id);
+
+static int pk11_init_all_locks(void);
+static void pk11_free_all_locks(void);
+
+#ifdef SOLARIS_HW_SLOT_SELECTION
+static int check_hw_mechanisms(void);
+static int nid_in_table(int nid, int *nid_table);
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+
+/* Index for the supported ciphers */
+enum pk11_cipher_id {
+ PK11_DES_CBC,
+ PK11_DES3_CBC,
+ PK11_DES_ECB,
+ PK11_DES3_ECB,
+ PK11_RC4,
+ PK11_AES_128_CBC,
+ PK11_AES_192_CBC,
+ PK11_AES_256_CBC,
+ PK11_AES_128_ECB,
+ PK11_AES_192_ECB,
+ PK11_AES_256_ECB,
+ PK11_BLOWFISH_CBC,
+#ifdef SOLARIS_AES_CTR
+ PK11_AES_128_CTR,
+ PK11_AES_192_CTR,
+ PK11_AES_256_CTR,
+#endif /* SOLARIS_AES_CTR */
+ PK11_CIPHER_MAX
+};
+
+/* Index for the supported digests */
+enum pk11_digest_id {
+ PK11_MD5,
+ PK11_SHA1,
+ PK11_SHA224,
+ PK11_SHA256,
+ PK11_SHA384,
+ PK11_SHA512,
+ PK11_DIGEST_MAX
+};
+
+#define TRY_OBJ_DESTROY(sp, obj_hdl, retval, uselock, alg_type) \
+ { \
+ if (uselock) \
+ LOCK_OBJSTORE(alg_type); \
+ if (pk11_active_delete(obj_hdl, alg_type) == 1) \
+ { \
+ retval = pk11_destroy_object(sp->session, obj_hdl, \
+ sp->persistent); \
+ } \
+ if (uselock) \
+ UNLOCK_OBJSTORE(alg_type); \
+ }
+
+static int cipher_nids[PK11_CIPHER_MAX];
+static int digest_nids[PK11_DIGEST_MAX];
+static int cipher_count = 0;
+static int digest_count = 0;
+static CK_BBOOL pk11_have_rsa = CK_FALSE;
+static CK_BBOOL pk11_have_dsa = CK_FALSE;
+static CK_BBOOL pk11_have_dh = CK_FALSE;
+static CK_BBOOL pk11_have_random = CK_FALSE;
+
+typedef struct PK11_CIPHER_st
+ {
+ enum pk11_cipher_id id;
+ int nid;
+ int iv_len;
+ int min_key_len;
+ int max_key_len;
+ CK_KEY_TYPE key_type;
+ CK_MECHANISM_TYPE mech_type;
+ } PK11_CIPHER;
+
+static PK11_CIPHER ciphers[] =
+ {
+ { PK11_DES_CBC, NID_des_cbc, 8, 8, 8,
+ CKK_DES, CKM_DES_CBC, },
+ { PK11_DES3_CBC, NID_des_ede3_cbc, 8, 24, 24,
+ CKK_DES3, CKM_DES3_CBC, },
+ { PK11_DES_ECB, NID_des_ecb, 0, 8, 8,
+ CKK_DES, CKM_DES_ECB, },
+ { PK11_DES3_ECB, NID_des_ede3_ecb, 0, 24, 24,
+ CKK_DES3, CKM_DES3_ECB, },
+ { PK11_RC4, NID_rc4, 0, 16, 256,
+ CKK_RC4, CKM_RC4, },
+ { PK11_AES_128_CBC, NID_aes_128_cbc, 16, 16, 16,
+ CKK_AES, CKM_AES_CBC, },
+ { PK11_AES_192_CBC, NID_aes_192_cbc, 16, 24, 24,
+ CKK_AES, CKM_AES_CBC, },
+ { PK11_AES_256_CBC, NID_aes_256_cbc, 16, 32, 32,
+ CKK_AES, CKM_AES_CBC, },
+ { PK11_AES_128_ECB, NID_aes_128_ecb, 0, 16, 16,
+ CKK_AES, CKM_AES_ECB, },
+ { PK11_AES_192_ECB, NID_aes_192_ecb, 0, 24, 24,
+ CKK_AES, CKM_AES_ECB, },
+ { PK11_AES_256_ECB, NID_aes_256_ecb, 0, 32, 32,
+ CKK_AES, CKM_AES_ECB, },
+ { PK11_BLOWFISH_CBC, NID_bf_cbc, 8, 16, 16,
+ CKK_BLOWFISH, CKM_BLOWFISH_CBC, },
+#ifdef SOLARIS_AES_CTR
+ /* we don't know the correct NIDs until the engine is initialized */
+ { PK11_AES_128_CTR, NID_undef, 16, 16, 16,
+ CKK_AES, CKM_AES_CTR, },
+ { PK11_AES_192_CTR, NID_undef, 16, 24, 24,
+ CKK_AES, CKM_AES_CTR, },
+ { PK11_AES_256_CTR, NID_undef, 16, 32, 32,
+ CKK_AES, CKM_AES_CTR, },
+#endif /* SOLARIS_AES_CTR */
+ };
+
+typedef struct PK11_DIGEST_st
+ {
+ enum pk11_digest_id id;
+ int nid;
+ CK_MECHANISM_TYPE mech_type;
+ } PK11_DIGEST;
+
+static PK11_DIGEST digests[] =
+ {
+ {PK11_MD5, NID_md5, CKM_MD5, },
+ {PK11_SHA1, NID_sha1, CKM_SHA_1, },
+ {PK11_SHA224, NID_sha224, CKM_SHA224, },
+ {PK11_SHA256, NID_sha256, CKM_SHA256, },
+ {PK11_SHA384, NID_sha384, CKM_SHA384, },
+ {PK11_SHA512, NID_sha512, CKM_SHA512, },
+ {0, NID_undef, 0xFFFF, },
+ };
+
+/*
+ * Structure to be used for the cipher_data/md_data in
+ * EVP_CIPHER_CTX/EVP_MD_CTX structures in order to use the same pk11
+ * session in multiple cipher_update calls
+ */
+typedef struct PK11_CIPHER_STATE_st
+ {
+ PK11_SESSION *sp;
+ } PK11_CIPHER_STATE;
+
+
+/*
+ * libcrypto EVP stuff - this is how we get wired to EVP so the engine gets
+ * called when libcrypto requests a cipher NID.
+ *
+ * Note how the PK11_CIPHER_STATE is used here.
+ */
+
+/* DES CBC EVP */
+static const EVP_CIPHER pk11_des_cbc =
+ {
+ NID_des_cbc,
+ 8, 8, 8,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+/* 3DES CBC EVP */
+static const EVP_CIPHER pk11_3des_cbc =
+ {
+ NID_des_ede3_cbc,
+ 8, 24, 8,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+/*
+ * ECB modes don't use an Initial Vector so that's why set_asn1_parameters and
+ * get_asn1_parameters fields are set to NULL.
+ */
+static const EVP_CIPHER pk11_des_ecb =
+ {
+ NID_des_ecb,
+ 8, 8, 8,
+ EVP_CIPH_ECB_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_3des_ecb =
+ {
+ NID_des_ede3_ecb,
+ 8, 24, 8,
+ EVP_CIPH_ECB_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+
+static const EVP_CIPHER pk11_aes_128_cbc =
+ {
+ NID_aes_128_cbc,
+ 16, 16, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_aes_192_cbc =
+ {
+ NID_aes_192_cbc,
+ 16, 24, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_aes_256_cbc =
+ {
+ NID_aes_256_cbc,
+ 16, 32, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+/*
+ * ECB modes don't use IV so that's why set_asn1_parameters and
+ * get_asn1_parameters are set to NULL.
+ */
+static const EVP_CIPHER pk11_aes_128_ecb =
+ {
+ NID_aes_128_ecb,
+ 16, 16, 0,
+ EVP_CIPH_ECB_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_aes_192_ecb =
+ {
+ NID_aes_192_ecb,
+ 16, 24, 0,
+ EVP_CIPH_ECB_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_aes_256_ecb =
+ {
+ NID_aes_256_ecb,
+ 16, 32, 0,
+ EVP_CIPH_ECB_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+#ifdef SOLARIS_AES_CTR
+/*
+ * NID_undef's will be changed to the AES counter mode NIDs as soon they are
+ * created in pk11_library_init(). Note that the need to change these structures
+ * is the reason why we don't define them with the const keyword.
+ */
+static EVP_CIPHER pk11_aes_128_ctr =
+ {
+ NID_undef,
+ 16, 16, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+static EVP_CIPHER pk11_aes_192_ctr =
+ {
+ NID_undef,
+ 16, 24, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+static EVP_CIPHER pk11_aes_256_ctr =
+ {
+ NID_undef,
+ 16, 32, 16,
+ EVP_CIPH_CBC_MODE,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+#endif /* SOLARIS_AES_CTR */
+
+static const EVP_CIPHER pk11_bf_cbc =
+ {
+ NID_bf_cbc,
+ 8, 16, 8,
+ EVP_CIPH_VARIABLE_LENGTH,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ NULL
+ };
+
+static const EVP_CIPHER pk11_rc4 =
+ {
+ NID_rc4,
+ 1, 16, 0,
+ EVP_CIPH_VARIABLE_LENGTH,
+ pk11_cipher_init,
+ pk11_cipher_do_cipher,
+ pk11_cipher_cleanup,
+ sizeof (PK11_CIPHER_STATE),
+ NULL,
+ NULL,
+ NULL
+ };
+
+static const EVP_MD pk11_md5 =
+ {
+ NID_md5,
+ NID_md5WithRSAEncryption,
+ MD5_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ MD5_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+static const EVP_MD pk11_sha1 =
+ {
+ NID_sha1,
+ NID_sha1WithRSAEncryption,
+ SHA_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ SHA_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+static const EVP_MD pk11_sha224 =
+ {
+ NID_sha224,
+ NID_sha224WithRSAEncryption,
+ SHA224_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ /* SHA-224 uses the same cblock size as SHA-256 */
+ SHA256_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+static const EVP_MD pk11_sha256 =
+ {
+ NID_sha256,
+ NID_sha256WithRSAEncryption,
+ SHA256_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ SHA256_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+static const EVP_MD pk11_sha384 =
+ {
+ NID_sha384,
+ NID_sha384WithRSAEncryption,
+ SHA384_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ /* SHA-384 uses the same cblock size as SHA-512 */
+ SHA512_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+static const EVP_MD pk11_sha512 =
+ {
+ NID_sha512,
+ NID_sha512WithRSAEncryption,
+ SHA512_DIGEST_LENGTH,
+ 0,
+ pk11_digest_init,
+ pk11_digest_update,
+ pk11_digest_final,
+ pk11_digest_copy,
+ pk11_digest_cleanup,
+ EVP_PKEY_RSA_method,
+ SHA512_CBLOCK,
+ sizeof (PK11_CIPHER_STATE),
+ };
+
+/*
+ * Initialization function. Sets up various PKCS#11 library components.
+ * The definitions for control commands specific to this engine
+ */
+#define PK11_CMD_SO_PATH ENGINE_CMD_BASE
+static const ENGINE_CMD_DEFN pk11_cmd_defns[] =
+ {
+ {
+ PK11_CMD_SO_PATH,
+ "SO_PATH",
+ "Specifies the path to the 'pkcs#11' shared library",
+ ENGINE_CMD_FLAG_STRING
+ },
+ {0, NULL, NULL, 0}
+ };
+
+
+static RAND_METHOD pk11_random =
+ {
+ pk11_rand_seed,
+ pk11_rand_bytes,
+ pk11_rand_cleanup,
+ pk11_rand_add,
+ pk11_rand_bytes,
+ pk11_rand_status
+ };
+
+
+/* Constants used when creating the ENGINE */
+static const char *engine_pk11_id = "pkcs11";
+static const char *engine_pk11_name = "PKCS #11 engine support";
+
+CK_FUNCTION_LIST_PTR pFuncList = NULL;
+static const char PK11_GET_FUNCTION_LIST[] = "C_GetFunctionList";
+
+/*
+ * This is a static string constant for the DSO file name and the function
+ * symbol names to bind to. We set it in the Configure script based on whether
+ * this is 32 or 64 bit build.
+ */
+static const char def_PK11_LIBNAME[] = PK11_LIB_LOCATION;
+
+static CK_BBOOL pk11_true = CK_TRUE;
+static CK_BBOOL pk11_false = CK_FALSE;
+/* Needed in hw_pk11_pub.c as well so that's why it is not static. */
+CK_SLOT_ID pubkey_SLOTID = 0;
+static CK_SLOT_ID rand_SLOTID = 0;
+static CK_SLOT_ID SLOTID = 0;
+static CK_BBOOL pk11_library_initialized = CK_FALSE;
+static CK_BBOOL pk11_atfork_initialized = CK_FALSE;
+static int pk11_pid = 0;
+
+static DSO *pk11_dso = NULL;
+
+/* allocate and initialize all locks used by the engine itself */
+static int pk11_init_all_locks(void)
+ {
+ int type;
+
+#ifndef OPENSSL_NO_RSA
+ find_lock[OP_RSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
+ if (find_lock[OP_RSA] == NULL)
+ goto malloc_err;
+ (void) pthread_mutex_init(find_lock[OP_RSA], NULL);
+#endif /* OPENSSL_NO_RSA */
+
+ if ((uri_lock = OPENSSL_malloc(sizeof (pthread_mutex_t))) == NULL)
+ goto malloc_err;
+ (void) pthread_mutex_init(uri_lock, NULL);
+
+#ifndef OPENSSL_NO_DSA
+ find_lock[OP_DSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
+ if (find_lock[OP_DSA] == NULL)
+ goto malloc_err;
+ (void) pthread_mutex_init(find_lock[OP_DSA], NULL);
+#endif /* OPENSSL_NO_DSA */
+
+#ifndef OPENSSL_NO_DH
+ find_lock[OP_DH] = OPENSSL_malloc(sizeof (pthread_mutex_t));
+ if (find_lock[OP_DH] == NULL)
+ goto malloc_err;
+ (void) pthread_mutex_init(find_lock[OP_DH], NULL);
+#endif /* OPENSSL_NO_DH */
+
+ for (type = 0; type < OP_MAX; type++)
+ {
+ session_cache[type].lock =
+ OPENSSL_malloc(sizeof (pthread_mutex_t));
+ if (session_cache[type].lock == NULL)
+ goto malloc_err;
+ (void) pthread_mutex_init(session_cache[type].lock, NULL);
+ }
+
+ return (1);
+
+malloc_err:
+ pk11_free_all_locks();
+ PK11err(PK11_F_INIT_ALL_LOCKS, PK11_R_MALLOC_FAILURE);
+ return (0);
+ }
+
+static void pk11_free_all_locks(void)
+ {
+ int type;
+
+#ifndef OPENSSL_NO_RSA
+ if (find_lock[OP_RSA] != NULL)
+ {
+ (void) pthread_mutex_destroy(find_lock[OP_RSA]);
+ OPENSSL_free(find_lock[OP_RSA]);
+ find_lock[OP_RSA] = NULL;
+ }
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+ if (find_lock[OP_DSA] != NULL)
+ {
+ (void) pthread_mutex_destroy(find_lock[OP_DSA]);
+ OPENSSL_free(find_lock[OP_DSA]);
+ find_lock[OP_DSA] = NULL;
+ }
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+ if (find_lock[OP_DH] != NULL)
+ {
+ (void) pthread_mutex_destroy(find_lock[OP_DH]);
+ OPENSSL_free(find_lock[OP_DH]);
+ find_lock[OP_DH] = NULL;
+ }
+#endif /* OPENSSL_NO_DH */
+
+ for (type = 0; type < OP_MAX; type++)
+ {
+ if (session_cache[type].lock != NULL)
+ {
+ (void) pthread_mutex_destroy(session_cache[type].lock);
+ OPENSSL_free(session_cache[type].lock);
+ session_cache[type].lock = NULL;
+ }
+ }
+ }
+
+/*
+ * This internal function is used by ENGINE_pk11() and "dynamic" ENGINE support.
+ */
+static int bind_pk11(ENGINE *e)
+ {
+#ifndef OPENSSL_NO_RSA
+ const RSA_METHOD *rsa = NULL;
+ RSA_METHOD *pk11_rsa = PK11_RSA();
+#endif /* OPENSSL_NO_RSA */
+ if (!pk11_library_initialized)
+ if (!pk11_library_init(e))
+ return (0);
+
+ if (!ENGINE_set_id(e, engine_pk11_id) ||
+ !ENGINE_set_name(e, engine_pk11_name) ||
+ !ENGINE_set_ciphers(e, pk11_engine_ciphers) ||
+ !ENGINE_set_digests(e, pk11_engine_digests))
+ return (0);
+#ifndef OPENSSL_NO_RSA
+ if (pk11_have_rsa == CK_TRUE)
+ {
+ if (!ENGINE_set_RSA(e, PK11_RSA()) ||
+ !ENGINE_set_load_privkey_function(e, pk11_load_privkey) ||
+ !ENGINE_set_load_pubkey_function(e, pk11_load_pubkey))
+ return (0);
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: registered RSA\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ }
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+ if (pk11_have_dsa == CK_TRUE)
+ {
+ if (!ENGINE_set_DSA(e, PK11_DSA()))
+ return (0);
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: registered DSA\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ }
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+ if (pk11_have_dh == CK_TRUE)
+ {
+ if (!ENGINE_set_DH(e, PK11_DH()))
+ return (0);
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: registered DH\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ }
+#endif /* OPENSSL_NO_DH */
+ if (pk11_have_random)
+ {
+ if (!ENGINE_set_RAND(e, &pk11_random))
+ return (0);
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: registered random\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ }
+ if (!ENGINE_set_init_function(e, pk11_init) ||
+ !ENGINE_set_destroy_function(e, pk11_destroy) ||
+ !ENGINE_set_finish_function(e, pk11_finish) ||
+ !ENGINE_set_ctrl_function(e, pk11_ctrl) ||
+ !ENGINE_set_cmd_defns(e, pk11_cmd_defns))
+ return (0);
+
+/*
+ * Apache calls OpenSSL function RSA_blinding_on() once during startup
+ * which in turn calls bn_mod_exp. Since we do not implement bn_mod_exp
+ * here, we wire it back to the OpenSSL software implementation.
+ * Since it is used only once, performance is not a concern.
+ */
+#ifndef OPENSSL_NO_RSA
+ rsa = RSA_PKCS1_SSLeay();
+ pk11_rsa->rsa_mod_exp = rsa->rsa_mod_exp;
+ pk11_rsa->bn_mod_exp = rsa->bn_mod_exp;
+#endif /* OPENSSL_NO_RSA */
+
+ /* Ensure the pk11 error handling is set up */
+ ERR_load_pk11_strings();
+
+ return (1);
+ }
+
+/* Dynamic engine support is disabled at a higher level for Solaris */
+#ifdef ENGINE_DYNAMIC_SUPPORT
+static int bind_helper(ENGINE *e, const char *id)
+ {
+ if (id && (strcmp(id, engine_pk11_id) != 0))
+ return (0);
+
+ if (!bind_pk11(e))
+ return (0);
+
+ return (1);
+ }
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+
+#else
+static ENGINE *engine_pk11(void)
+ {
+ ENGINE *ret = ENGINE_new();
+
+ if (!ret)
+ return (NULL);
+
+ if (!bind_pk11(ret))
+ {
+ ENGINE_free(ret);
+ return (NULL);
+ }
+
+ return (ret);
+ }
+
+void
+ENGINE_load_pk11(void)
+ {
+ ENGINE *e_pk11 = NULL;
+
+ /*
+ * Do not use dynamic PKCS#11 library on Solaris due to
+ * security reasons. We will link it in statically.
+ */
+ /* Attempt to load PKCS#11 library */
+ if (!pk11_dso)
+ pk11_dso = DSO_load(NULL, get_PK11_LIBNAME(), NULL, 0);
+
+ if (pk11_dso == NULL)
+ {
+ PK11err(PK11_F_LOAD, PK11_R_DSO_FAILURE);
+ return;
+ }
+
+ e_pk11 = engine_pk11();
+ if (!e_pk11)
+ {
+ DSO_free(pk11_dso);
+ pk11_dso = NULL;
+ return;
+ }
+
+ /*
+ * At this point, the pk11 shared library is either dynamically
+ * loaded or statically linked in. So, initialize the pk11
+ * library before calling ENGINE_set_default since the latter
+ * needs cipher and digest algorithm information
+ */
+ if (!pk11_library_init(e_pk11))
+ {
+ DSO_free(pk11_dso);
+ pk11_dso = NULL;
+ ENGINE_free(e_pk11);
+ return;
+ }
+
+ ENGINE_add(e_pk11);
+
+ ENGINE_free(e_pk11);
+ ERR_clear_error();
+ }
+#endif /* ENGINE_DYNAMIC_SUPPORT */
+
+/*
+ * These are the static string constants for the DSO file name and
+ * the function symbol names to bind to.
+ */
+static const char *PK11_LIBNAME = NULL;
+
+static const char *get_PK11_LIBNAME(void)
+ {
+ if (PK11_LIBNAME)
+ return (PK11_LIBNAME);
+
+ return (def_PK11_LIBNAME);
+ }
+
+static void free_PK11_LIBNAME(void)
+ {
+ if (PK11_LIBNAME)
+ OPENSSL_free((void*)PK11_LIBNAME);
+
+ PK11_LIBNAME = NULL;
+ }
+
+static long set_PK11_LIBNAME(const char *name)
+ {
+ free_PK11_LIBNAME();
+
+ return ((PK11_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
+ }
+
+/* acquire all engine specific mutexes before fork */
+static void pk11_fork_prepare(void)
+ {
+ int i;
+
+ if (!pk11_library_initialized)
+ return;
+
+ LOCK_OBJSTORE(OP_RSA);
+ LOCK_OBJSTORE(OP_DSA);
+ LOCK_OBJSTORE(OP_DH);
+ (void) pthread_mutex_lock(uri_lock);
+ for (i = 0; i < OP_MAX; i++)
+ {
+ (void) pthread_mutex_lock(session_cache[i].lock);
+ }
+ }
+
+/* release all engine specific mutexes */
+static void pk11_fork_parent(void)
+ {
+ int i;
+
+ if (!pk11_library_initialized)
+ return;
+
+ for (i = OP_MAX - 1; i >= 0; i--)
+ {
+ (void) pthread_mutex_unlock(session_cache[i].lock);
+ }
+ UNLOCK_OBJSTORE(OP_DH);
+ UNLOCK_OBJSTORE(OP_DSA);
+ UNLOCK_OBJSTORE(OP_RSA);
+ (void) pthread_mutex_unlock(uri_lock);
+ }
+
+/*
+ * same situation as in parent - we need to unlock all locks to make them
+ * accessible to all threads.
+ */
+static void pk11_fork_child(void)
+ {
+ int i;
+
+ if (!pk11_library_initialized)
+ return;
+
+ for (i = OP_MAX - 1; i >= 0; i--)
+ {
+ (void) pthread_mutex_unlock(session_cache[i].lock);
+ }
+ UNLOCK_OBJSTORE(OP_DH);
+ UNLOCK_OBJSTORE(OP_DSA);
+ UNLOCK_OBJSTORE(OP_RSA);
+ (void) pthread_mutex_unlock(uri_lock);
+ }
+
+/* Initialization function for the pk11 engine */
+static int pk11_init(ENGINE *e)
+{
+ return (pk11_library_init(e));
+}
+
+/*
+ * Initialization function. Sets up various PKCS#11 library components.
+ * It selects a slot based on predefined critiera. In the process, it also
+ * count how many ciphers and digests to support. Since the cipher and
+ * digest information is needed when setting default engine, this function
+ * needs to be called before calling ENGINE_set_default.
+ */
+/* ARGSUSED */
+static int pk11_library_init(ENGINE *e)
+ {
+ CK_C_GetFunctionList p;
+ CK_RV rv = CKR_OK;
+ CK_INFO info;
+ CK_ULONG ul_state_len;
+ int any_slot_found;
+ int i;
+
+ /*
+ * pk11_library_initialized is set to 0 in pk11_finish() which is called
+ * from ENGINE_finish(). However, if there is still at least one
+ * existing functional reference to the engine (see engine(3) for more
+ * information), pk11_finish() is skipped. For example, this can happen
+ * if an application forgets to clear one cipher context. In case of a
+ * fork() when the application is finishing the engine so that it can be
+ * reinitialized in the child, forgotten functional reference causes
+ * pk11_library_initialized to stay 1. In that case we need the PID
+ * check so that we properly initialize the engine again.
+ */
+ if (pk11_library_initialized)
+ {
+ if (pk11_pid == getpid())
+ {
+ return (1);
+ }
+ else
+ {
+ global_session = CK_INVALID_HANDLE;
+ /*
+ * free the locks first to prevent memory leak in case
+ * the application calls fork() without finishing the
+ * engine first.
+ */
+ pk11_free_all_locks();
+ }
+ }
+
+ if (pk11_dso == NULL)
+ {
+ PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+
+#ifdef SOLARIS_AES_CTR
+ /*
+ * We must do this before we start working with slots since we need all
+ * NIDs there.
+ */
+ if (pk11_add_aes_ctr_NIDs() == 0)
+ goto err;
+#endif /* SOLARIS_AES_CTR */
+
+#ifdef SOLARIS_HW_SLOT_SELECTION
+ if (check_hw_mechanisms() == 0)
+ goto err;
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+
+ /* get the C_GetFunctionList function from the loaded library */
+ p = (CK_C_GetFunctionList)DSO_bind_func(pk11_dso,
+ PK11_GET_FUNCTION_LIST);
+ if (!p)
+ {
+ PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+
+ /* get the full function list from the loaded library */
+ rv = p(&pFuncList);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_Initialize(NULL_PTR);
+ if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
+ {
+ PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_INITIALIZE, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_GetInfo(&info);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_GETINFO, rv);
+ goto err;
+ }
+
+ if (pk11_choose_slots(&any_slot_found) == 0)
+ goto err;
+
+ /*
+ * The library we use, set in def_PK11_LIBNAME, may not offer any
+ * slot(s). In that case, we must not proceed but we must not return an
+ * error. The reason is that applications that try to set up the PKCS#11
+ * engine don't exit on error during the engine initialization just
+ * because no slot was present.
+ */
+ if (any_slot_found == 0)
+ return (1);
+
+ if (global_session == CK_INVALID_HANDLE)
+ {
+ /* Open the global_session for the new process */
+ rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL_PTR, &global_session);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_LIBRARY_INIT,
+ PK11_R_OPENSESSION, rv);
+ goto err;
+ }
+ }
+
+ /*
+ * Disable digest if C_GetOperationState is not supported since
+ * this function is required by OpenSSL digest copy function
+ */
+ if (pFuncList->C_GetOperationState(global_session, NULL, &ul_state_len)
+ == CKR_FUNCTION_NOT_SUPPORTED) {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: C_GetOperationState() not supported, "
+ "setting digest_count to 0\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ digest_count = 0;
+ }
+
+ pk11_library_initialized = CK_TRUE;
+ pk11_pid = getpid();
+ /*
+ * if initialization of the locks fails pk11_init_all_locks()
+ * will do the cleanup.
+ */
+ if (!pk11_init_all_locks())
+ goto err;
+ for (i = 0; i < OP_MAX; i++)
+ session_cache[i].head = NULL;
+ /*
+ * initialize active lists. We only use active lists
+ * for asymmetric ciphers.
+ */
+ for (i = 0; i < OP_MAX; i++)
+ active_list[i] = NULL;
+
+ if (!pk11_atfork_initialized)
+ {
+ if (pthread_atfork(pk11_fork_prepare, pk11_fork_parent,
+ pk11_fork_child) != 0)
+ {
+ PK11err(PK11_F_LIBRARY_INIT, PK11_R_ATFORK_FAILED);
+ goto err;
+ }
+ pk11_atfork_initialized = CK_TRUE;
+ }
+
+ return (1);
+
+err:
+ return (0);
+ }
+
+/* Destructor (complements the "ENGINE_pk11()" constructor) */
+/* ARGSUSED */
+static int pk11_destroy(ENGINE *e)
+ {
+ free_PK11_LIBNAME();
+ ERR_unload_pk11_strings();
+ return (1);
+ }
+
+/*
+ * Termination function to clean up the session, the token, and the pk11
+ * library.
+ */
+/* ARGSUSED */
+static int pk11_finish(ENGINE *e)
+ {
+ int i;
+
+ if (pk11_dso == NULL)
+ {
+ PK11err(PK11_F_FINISH, PK11_R_NOT_LOADED);
+ goto err;
+ }
+
+ OPENSSL_assert(pFuncList != NULL);
+
+ if (pk11_free_all_sessions() == 0)
+ goto err;
+
+ /* free all active lists */
+ for (i = 0; i < OP_MAX; i++)
+ pk11_free_active_list(i);
+
+ pFuncList->C_CloseSession(global_session);
+ global_session = CK_INVALID_HANDLE;
+
+ /*
+ * Since we are part of a library (libcrypto.so), calling this function
+ * may have side-effects.
+ */
+#if 0
+ pFuncList->C_Finalize(NULL);
+#endif
+#ifdef SOLARIS_AES_CTR
+ {
+ ASN1_OBJECT *ob = NULL;
+ if (NID_aes_128_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_128_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+ if (NID_aes_192_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_192_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+ if (NID_aes_256_ctr != NID_undef) {
+ ob = OBJ_nid2obj(NID_aes_256_ctr);
+ if (ob != NULL)
+ ASN1_OBJECT_free(ob);
+ }
+ }
+#endif
+
+ if (!DSO_free(pk11_dso))
+ {
+ PK11err(PK11_F_FINISH, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+ pk11_dso = NULL;
+ pFuncList = NULL;
+ pk11_library_initialized = CK_FALSE;
+ pk11_pid = 0;
+ /*
+ * There is no way how to unregister atfork handlers (other than
+ * unloading the library) so we just free the locks. For this reason
+ * the atfork handlers check if the engine is initialized and bail out
+ * immediately if not. This is necessary in case a process finishes
+ * the engine before calling fork().
+ */
+ pk11_free_all_locks();
+
+ return (1);
+
+err:
+ return (0);
+ }
+
+/* Standard engine interface function to set the dynamic library path */
+/* ARGSUSED */
+static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
+ {
+ int initialized = ((pk11_dso == NULL) ? 0 : 1);
+
+ switch (cmd)
+ {
+ case PK11_CMD_SO_PATH:
+ if (p == NULL)
+ {
+ PK11err(PK11_F_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+ return (0);
+ }
+
+ if (initialized)
+ {
+ PK11err(PK11_F_CTRL, PK11_R_ALREADY_LOADED);
+ return (0);
+ }
+
+ return (set_PK11_LIBNAME((const char *)p));
+ default:
+ break;
+ }
+
+ PK11err(PK11_F_CTRL, PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED);
+
+ return (0);
+ }
+
+
+/* Required function by the engine random interface. It does nothing here */
+static void pk11_rand_cleanup(void)
+ {
+ return;
+ }
+
+/* ARGSUSED */
+static void pk11_rand_add(const void *buf, int num, double add)
+ {
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RAND)) == NULL)
+ return;
+
+ /*
+ * Ignore any errors (e.g. CKR_RANDOM_SEED_NOT_SUPPORTED) since
+ * the calling functions do not care anyway
+ */
+ pFuncList->C_SeedRandom(sp->session, (unsigned char *) buf, num);
+ pk11_return_session(sp, OP_RAND);
+
+ return;
+ }
+
+static void pk11_rand_seed(const void *buf, int num)
+ {
+ pk11_rand_add(buf, num, 0);
+ }
+
+static int pk11_rand_bytes(unsigned char *buf, int num)
+ {
+ CK_RV rv;
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RAND)) == NULL)
+ return (0);
+
+ rv = pFuncList->C_GenerateRandom(sp->session, buf, num);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RAND_BYTES, PK11_R_GENERATERANDOM, rv);
+ pk11_return_session(sp, OP_RAND);
+ return (0);
+ }
+
+ pk11_return_session(sp, OP_RAND);
+ return (1);
+ }
+
+/* Required function by the engine random interface. It does nothing here */
+static int pk11_rand_status(void)
+ {
+ return (1);
+ }
+
+/* Free all BIGNUM structures from PK11_SESSION. */
+static void pk11_free_nums(PK11_SESSION *sp, PK11_OPTYPE optype)
+ {
+ switch (optype)
+ {
+#ifndef OPENSSL_NO_RSA
+ case OP_RSA:
+ if (sp->opdata_rsa_n_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_n_num);
+ sp->opdata_rsa_n_num = NULL;
+ }
+ if (sp->opdata_rsa_e_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_e_num);
+ sp->opdata_rsa_e_num = NULL;
+ }
+ if (sp->opdata_rsa_d_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_d_num);
+ sp->opdata_rsa_d_num = NULL;
+ }
+ break;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case OP_DSA:
+ if (sp->opdata_dsa_pub_num != NULL)
+ {
+ BN_free(sp->opdata_dsa_pub_num);
+ sp->opdata_dsa_pub_num = NULL;
+ }
+ if (sp->opdata_dsa_priv_num != NULL)
+ {
+ BN_free(sp->opdata_dsa_priv_num);
+ sp->opdata_dsa_priv_num = NULL;
+ }
+ break;
+#endif
+#ifndef OPENSSL_NO_DH
+ case OP_DH:
+ if (sp->opdata_dh_priv_num != NULL)
+ {
+ BN_free(sp->opdata_dh_priv_num);
+ sp->opdata_dh_priv_num = NULL;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+/*
+ * Get new PK11_SESSION structure ready for use. Every process must have
+ * its own freelist of PK11_SESSION structures so handle fork() here
+ * by destroying the old and creating new freelist.
+ * The returned PK11_SESSION structure is disconnected from the freelist.
+ */
+PK11_SESSION *
+pk11_get_session(PK11_OPTYPE optype)
+ {
+ PK11_SESSION *sp = NULL, *sp1, *freelist;
+ pthread_mutex_t *freelist_lock;
+ static pid_t pid = 0;
+ pid_t new_pid;
+ CK_RV rv;
+
+ switch (optype)
+ {
+ case OP_RSA:
+ case OP_DSA:
+ case OP_DH:
+ case OP_RAND:
+ case OP_DIGEST:
+ case OP_CIPHER:
+ freelist_lock = session_cache[optype].lock;
+ break;
+ default:
+ PK11err(PK11_F_GET_SESSION,
+ PK11_R_INVALID_OPERATION_TYPE);
+ return (NULL);
+ }
+ (void) pthread_mutex_lock(freelist_lock);
+
+ /*
+ * Will use it to find out if we forked. We cannot use the PID field in
+ * the session structure because we could get a newly allocated session
+ * here, with no PID information.
+ */
+ if (pid == 0)
+ pid = getpid();
+
+ freelist = session_cache[optype].head;
+ sp = freelist;
+
+ /*
+ * If the free list is empty, allocate new unitialized (filled
+ * with zeroes) PK11_SESSION structure otherwise return first
+ * structure from the freelist.
+ */
+ if (sp == NULL)
+ {
+ if ((sp = OPENSSL_malloc(sizeof (PK11_SESSION))) == NULL)
+ {
+ PK11err(PK11_F_GET_SESSION,
+ PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ (void) memset(sp, 0, sizeof (PK11_SESSION));
+
+ /*
+ * It is a new session so it will look like a cache miss to the
+ * code below. So, we must not try to to destroy its members so
+ * mark them as unused.
+ */
+ sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
+ sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
+ }
+ else
+ freelist = sp->next;
+
+ /*
+ * Check whether we have forked. In that case, we must get rid of all
+ * inherited sessions and start allocating new ones.
+ */
+ if (pid != (new_pid = getpid()))
+ {
+ pid = new_pid;
+
+ /*
+ * We are a new process and thus need to free any inherited
+ * PK11_SESSION objects aside from the first session (sp) which
+ * is the only PK11_SESSION structure we will reuse (for the
+ * head of the list).
+ */
+ while ((sp1 = freelist) != NULL)
+ {
+ freelist = sp1->next;
+ /*
+ * NOTE: we do not want to call pk11_free_all_sessions()
+ * here because it would close underlying PKCS#11
+ * sessions and destroy all objects.
+ */
+ pk11_free_nums(sp1, optype);
+ OPENSSL_free(sp1);
+ }
+
+ /* we have to free the active list as well. */
+ pk11_free_active_list(optype);
+
+ /* Initialize the process */
+ rv = pFuncList->C_Initialize(NULL_PTR);
+ if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
+ {
+ PK11err_add_data(PK11_F_GET_SESSION, PK11_R_INITIALIZE,
+ rv);
+ OPENSSL_free(sp);
+ sp = NULL;
+ goto err;
+ }
+
+ /*
+ * Choose slot here since the slot table is different on this
+ * process. If we are here then we must have found at least one
+ * usable slot before so we don't need to check any_slot_found.
+ * See pk11_library_init()'s usage of this function for more
+ * information.
+ */
+#ifdef SOLARIS_HW_SLOT_SELECTION
+ if (check_hw_mechanisms() == 0)
+ goto err;
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+ if (pk11_choose_slots(NULL) == 0)
+ goto err;
+
+ /* Open the global_session for the new process */
+ rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL_PTR, &global_session);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_SESSION, PK11_R_OPENSESSION,
+ rv);
+ OPENSSL_free(sp);
+ sp = NULL;
+ goto err;
+ }
+
+ /*
+ * It is an inherited session from our parent so it needs
+ * re-initialization.
+ */
+ if (pk11_setup_session(sp, optype) == 0)
+ {
+ OPENSSL_free(sp);
+ sp = NULL;
+ goto err;
+ }
+ if (pk11_token_relogin(sp->session) == 0)
+ {
+ /*
+ * We will keep the session in the cache list and let
+ * the caller cope with the situation.
+ */
+ freelist = sp;
+ sp = NULL;
+ goto err;
+ }
+ }
+
+ if (sp->pid == 0)
+ {
+ /* It is a new session and needs initialization. */
+ if (pk11_setup_session(sp, optype) == 0)
+ {
+ OPENSSL_free(sp);
+ sp = NULL;
+ }
+ }
+
+ /* set new head for the list of PK11_SESSION objects */
+ session_cache[optype].head = freelist;
+
+err:
+ if (sp != NULL)
+ sp->next = NULL;
+
+ (void) pthread_mutex_unlock(freelist_lock);
+
+ return (sp);
+ }
+
+
+void
+pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype)
+ {
+ pthread_mutex_t *freelist_lock;
+ PK11_SESSION *freelist;
+
+ /*
+ * If this is a session from the parent it will be taken care of and
+ * freed in pk11_get_session() as part of the post-fork clean up the
+ * next time we will ask for a new session.
+ */
+ if (sp == NULL || sp->pid != getpid())
+ return;
+
+ switch (optype)
+ {
+ case OP_RSA:
+ case OP_DSA:
+ case OP_DH:
+ case OP_RAND:
+ case OP_DIGEST:
+ case OP_CIPHER:
+ freelist_lock = session_cache[optype].lock;
+ break;
+ default:
+ PK11err(PK11_F_RETURN_SESSION,
+ PK11_R_INVALID_OPERATION_TYPE);
+ return;
+ }
+
+ (void) pthread_mutex_lock(freelist_lock);
+ freelist = session_cache[optype].head;
+ sp->next = freelist;
+ session_cache[optype].head = sp;
+ (void) pthread_mutex_unlock(freelist_lock);
+ }
+
+
+/* Destroy all objects. This function is called when the engine is finished */
+static int pk11_free_all_sessions()
+ {
+ int ret = 1;
+ int type;
+
+#ifndef OPENSSL_NO_RSA
+ (void) pk11_destroy_rsa_key_objects(NULL);
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+ (void) pk11_destroy_dsa_key_objects(NULL);
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+ (void) pk11_destroy_dh_key_objects(NULL);
+#endif /* OPENSSL_NO_DH */
+ (void) pk11_destroy_cipher_key_objects(NULL);
+
+ /*
+ * We try to release as much as we can but any error means that we will
+ * return 0 on exit.
+ */
+ for (type = 0; type < OP_MAX; type++)
+ {
+ if (pk11_free_session_list(type) == 0)
+ ret = 0;
+ }
+
+ return (ret);
+ }
+
+/*
+ * Destroy session structures from the linked list specified. Free as many
+ * sessions as possible but any failure in C_CloseSession() means that we
+ * return an error on return.
+ */
+static int pk11_free_session_list(PK11_OPTYPE optype)
+ {
+ CK_RV rv;
+ PK11_SESSION *sp = NULL;
+ PK11_SESSION *freelist = NULL;
+ pid_t mypid = getpid();
+ pthread_mutex_t *freelist_lock;
+ int ret = 1;
+
+ switch (optype)
+ {
+ case OP_RSA:
+ case OP_DSA:
+ case OP_DH:
+ case OP_RAND:
+ case OP_DIGEST:
+ case OP_CIPHER:
+ freelist_lock = session_cache[optype].lock;
+ break;
+ default:
+ PK11err(PK11_F_FREE_ALL_SESSIONS,
+ PK11_R_INVALID_OPERATION_TYPE);
+ return (0);
+ }
+
+ (void) pthread_mutex_lock(freelist_lock);
+ freelist = session_cache[optype].head;
+ while ((sp = freelist) != NULL)
+ {
+ if (sp->session != CK_INVALID_HANDLE && sp->pid == mypid)
+ {
+ rv = pFuncList->C_CloseSession(sp->session);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_FREE_ALL_SESSIONS,
+ PK11_R_CLOSESESSION, rv);
+ ret = 0;
+ }
+ }
+ freelist = sp->next;
+ pk11_free_nums(sp, optype);
+ OPENSSL_free(sp);
+ }
+
+ (void) pthread_mutex_unlock(freelist_lock);
+ return (ret);
+ }
+
+
+static int
+pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype)
+ {
+ CK_RV rv;
+ CK_SLOT_ID myslot;
+
+ switch (optype)
+ {
+ case OP_RSA:
+ case OP_DSA:
+ case OP_DH:
+ myslot = pubkey_SLOTID;
+ break;
+ case OP_RAND:
+ myslot = rand_SLOTID;
+ break;
+ case OP_DIGEST:
+ case OP_CIPHER:
+ myslot = SLOTID;
+ break;
+ default:
+ PK11err(PK11_F_SETUP_SESSION,
+ PK11_R_INVALID_OPERATION_TYPE);
+ return (0);
+ }
+
+ sp->session = CK_INVALID_HANDLE;
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: myslot=%d optype=%d\n", PK11_DBG, myslot, optype);
+#endif /* DEBUG_SLOT_SELECTION */
+ rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL_PTR, &sp->session);
+ if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
+ {
+ /*
+ * We are probably a child process so force the
+ * reinitialize of the session
+ */
+ pk11_library_initialized = CK_FALSE;
+ if (!pk11_library_init(NULL))
+ return (0);
+ rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL_PTR, &sp->session);
+ }
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION, rv);
+ return (0);
+ }
+
+ sp->pid = getpid();
+
+ switch (optype)
+ {
+#ifndef OPENSSL_NO_RSA
+ case OP_RSA:
+ sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
+ sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
+ sp->opdata_rsa_pub = NULL;
+ sp->opdata_rsa_n_num = NULL;
+ sp->opdata_rsa_e_num = NULL;
+ sp->opdata_rsa_priv = NULL;
+ sp->opdata_rsa_d_num = NULL;
+ break;
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+ case OP_DSA:
+ sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
+ sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
+ sp->opdata_dsa_pub = NULL;
+ sp->opdata_dsa_pub_num = NULL;
+ sp->opdata_dsa_priv = NULL;
+ sp->opdata_dsa_priv_num = NULL;
+ break;
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+ case OP_DH:
+ sp->opdata_dh_key = CK_INVALID_HANDLE;
+ sp->opdata_dh = NULL;
+ sp->opdata_dh_priv_num = NULL;
+ break;
+#endif /* OPENSSL_NO_DH */
+ case OP_CIPHER:
+ sp->opdata_cipher_key = CK_INVALID_HANDLE;
+ sp->opdata_encrypt = -1;
+ break;
+ }
+
+ /*
+ * We always initialize the session as containing a non-persistent
+ * object. The key load functions set it to persistent if that is so.
+ */
+ sp->persistent = CK_FALSE;
+ return (1);
+ }
+
+#ifndef OPENSSL_NO_RSA
+/*
+ * Destroy all non-NULL RSA parameters. For the RSA keys by reference code,
+ * public components 'n'/'e' are the key components we use to check for the
+ * cache hit even for the private keys. So, no matter whether we are destroying
+ * a public or a private key, we always free what we can.
+ */
+static void
+destroy_all_rsa_params(PK11_SESSION *sp)
+ {
+ if (sp->opdata_rsa_n_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_n_num);
+ sp->opdata_rsa_n_num = NULL;
+ }
+ if (sp->opdata_rsa_e_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_e_num);
+ sp->opdata_rsa_e_num = NULL;
+ }
+ if (sp->opdata_rsa_d_num != NULL)
+ {
+ BN_free(sp->opdata_rsa_d_num);
+ sp->opdata_rsa_d_num = NULL;
+ }
+ }
+
+/* Destroy RSA public key from single session. */
+int
+pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
+ {
+ int ret = 0;
+
+ if (sp->opdata_rsa_pub_key != CK_INVALID_HANDLE)
+ {
+ TRY_OBJ_DESTROY(sp, sp->opdata_rsa_pub_key,
+ ret, uselock, OP_RSA);
+ sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
+ sp->opdata_rsa_pub = NULL;
+ destroy_all_rsa_params(sp);
+ }
+
+ return (ret);
+ }
+
+/* Destroy RSA private key from single session. */
+int
+pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
+ {
+ int ret = 0;
+
+ if (sp->opdata_rsa_priv_key != CK_INVALID_HANDLE)
+ {
+ TRY_OBJ_DESTROY(sp, sp->opdata_rsa_priv_key,
+ ret, uselock, OP_RSA);
+ sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
+ sp->opdata_rsa_priv = NULL;
+ destroy_all_rsa_params(sp);
+ }
+
+ return (ret);
+ }
+
+/*
+ * Destroy RSA key object wrapper. If session is NULL, try to destroy all
+ * objects in the free list.
+ */
+int
+pk11_destroy_rsa_key_objects(PK11_SESSION *session)
+ {
+ int ret = 1;
+ PK11_SESSION *sp = NULL;
+ PK11_SESSION *local_free_session;
+ CK_BBOOL uselock = CK_TRUE;
+
+ if (session != NULL)
+ local_free_session = session;
+ else
+ {
+ (void) pthread_mutex_lock(session_cache[OP_RSA].lock);
+ local_free_session = session_cache[OP_RSA].head;
+ uselock = CK_FALSE;
+ }
+
+ /*
+ * go through the list of sessions and delete key objects
+ */
+ while ((sp = local_free_session) != NULL)
+ {
+ local_free_session = sp->next;
+
+ /*
+ * Do not terminate list traversal if one of the
+ * destroy operations fails.
+ */
+ if (pk11_destroy_rsa_object_pub(sp, uselock) == 0)
+ {
+ ret = 0;
+ continue;
+ }
+ if (pk11_destroy_rsa_object_priv(sp, uselock) == 0)
+ {
+ ret = 0;
+ continue;
+ }
+ }
+
+ if (session == NULL)
+ (void) pthread_mutex_unlock(session_cache[OP_RSA].lock);
+
+ return (ret);
+ }
+#endif /* OPENSSL_NO_RSA */
+
+#ifndef OPENSSL_NO_DSA
+/* Destroy DSA public key from single session. */
+int
+pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
+ {
+ int ret = 0;
+
+ if (sp->opdata_dsa_pub_key != CK_INVALID_HANDLE)
+ {
+ TRY_OBJ_DESTROY(sp, sp->opdata_dsa_pub_key,
+ ret, uselock, OP_DSA);
+ sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
+ sp->opdata_dsa_pub = NULL;
+ if (sp->opdata_dsa_pub_num != NULL)
+ {
+ BN_free(sp->opdata_dsa_pub_num);
+ sp->opdata_dsa_pub_num = NULL;
+ }
+ }
+
+ return (ret);
+ }
+
+/* Destroy DSA private key from single session. */
+int
+pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
+ {
+ int ret = 0;
+
+ if (sp->opdata_dsa_priv_key != CK_INVALID_HANDLE)
+ {
+ TRY_OBJ_DESTROY(sp, sp->opdata_dsa_priv_key,
+ ret, uselock, OP_DSA);
+ sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
+ sp->opdata_dsa_priv = NULL;
+ if (sp->opdata_dsa_priv_num != NULL)
+ {
+ BN_free(sp->opdata_dsa_priv_num);
+ sp->opdata_dsa_priv_num = NULL;
+ }
+ }
+
+ return (ret);
+ }
+
+/*
+ * Destroy DSA key object wrapper. If session is NULL, try to destroy all
+ * objects in the free list.
+ */
+int
+pk11_destroy_dsa_key_objects(PK11_SESSION *session)
+ {
+ int ret = 1;
+ PK11_SESSION *sp = NULL;
+ PK11_SESSION *local_free_session;
+ CK_BBOOL uselock = CK_TRUE;
+
+ if (session != NULL)
+ local_free_session = session;
+ else
+ {
+ (void) pthread_mutex_lock(session_cache[OP_DSA].lock);
+ local_free_session = session_cache[OP_DSA].head;
+ uselock = CK_FALSE;
+ }
+
+ /*
+ * go through the list of sessions and delete key objects
+ */
+ while ((sp = local_free_session) != NULL)
+ {
+ local_free_session = sp->next;
+
+ /*
+ * Do not terminate list traversal if one of the
+ * destroy operations fails.
+ */
+ if (pk11_destroy_dsa_object_pub(sp, uselock) == 0)
+ {
+ ret = 0;
+ continue;
+ }
+ if (pk11_destroy_dsa_object_priv(sp, uselock) == 0)
+ {
+ ret = 0;
+ continue;
+ }
+ }
+
+ if (session == NULL)
+ (void) pthread_mutex_unlock(session_cache[OP_DSA].lock);
+
+ return (ret);
+ }
+#endif /* OPENSSL_NO_DSA */
+
+#ifndef OPENSSL_NO_DH
+/* Destroy DH key from single session. */
+int
+pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock)
+ {
+ int ret = 0;
+
+ if (sp->opdata_dh_key != CK_INVALID_HANDLE)
+ {
+ TRY_OBJ_DESTROY(sp, sp->opdata_dh_key,
+ ret, uselock, OP_DH);
+ sp->opdata_dh_key = CK_INVALID_HANDLE;
+ sp->opdata_dh = NULL;
+ if (sp->opdata_dh_priv_num != NULL)
+ {
+ BN_free(sp->opdata_dh_priv_num);
+ sp->opdata_dh_priv_num = NULL;
+ }
+ }
+
+ return (ret);
+ }
+
+/*
+ * Destroy DH key object wrapper.
+ *
+ * arg0: pointer to PKCS#11 engine session structure
+ * if session is NULL, try to destroy all objects in the free list
+ */
+int
+pk11_destroy_dh_key_objects(PK11_SESSION *session)
+ {
+ int ret = 1;
+ PK11_SESSION *sp = NULL;
+ PK11_SESSION *local_free_session;
+ CK_BBOOL uselock = CK_TRUE;
+
+ if (session != NULL)
+ local_free_session = session;
+ else
+ {
+ (void) pthread_mutex_lock(session_cache[OP_DH].lock);
+ local_free_session = session_cache[OP_DH].head;
+ uselock = CK_FALSE;
+ }
+
+ while ((sp = local_free_session) != NULL)
+ {
+ local_free_session = sp->next;
+
+ /*
+ * Do not terminate list traversal if one of the
+ * destroy operations fails.
+ */
+ if (pk11_destroy_dh_object(sp, uselock) == 0)
+ {
+ ret = 0;
+ continue;
+ }
+ }
+err:
+ if (session == NULL)
+ (void) pthread_mutex_unlock(session_cache[OP_DH].lock);
+
+ return (ret);
+ }
+#endif /* OPENSSL_NO_DH */
+
+static int
+pk11_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE oh,
+ CK_BBOOL persistent)
+ {
+ CK_RV rv;
+
+ /*
+ * We never try to destroy persistent objects which are the objects
+ * stored in the keystore. Also, we always use read-only sessions so
+ * C_DestroyObject() would be returning CKR_SESSION_READ_ONLY here.
+ */
+ if (persistent == CK_TRUE)
+ return (1);
+
+ rv = pFuncList->C_DestroyObject(session, oh);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DESTROY_OBJECT, PK11_R_DESTROYOBJECT,
+ rv);
+ return (0);
+ }
+
+ return (1);
+ }
+
+
+/* Symmetric ciphers and digests support functions */
+
+static int
+cipher_nid_to_pk11(int nid)
+ {
+ int i;
+
+ for (i = 0; i < PK11_CIPHER_MAX; i++)
+ if (ciphers[i].nid == nid)
+ return (ciphers[i].id);
+ return (-1);
+ }
+
+static int
+pk11_usable_ciphers(const int **nids)
+ {
+ if (cipher_count > 0)
+ *nids = cipher_nids;
+ else
+ *nids = NULL;
+ return (cipher_count);
+ }
+
+static int
+pk11_usable_digests(const int **nids)
+ {
+ if (digest_count > 0)
+ *nids = digest_nids;
+ else
+ *nids = NULL;
+ return (digest_count);
+ }
+
+/*
+ * Init context for encryption or decryption using a symmetric key.
+ */
+static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_CIPHER *pcipher,
+ PK11_SESSION *sp, CK_MECHANISM_PTR pmech)
+ {
+ CK_RV rv;
+#ifdef SOLARIS_AES_CTR
+ CK_AES_CTR_PARAMS ctr_params;
+#endif /* SOLARIS_AES_CTR */
+
+ /*
+ * We expect pmech->mechanism to be already set and
+ * pParameter/ulParameterLen initialized to NULL/0 before
+ * pk11_init_symetric() is called.
+ */
+ OPENSSL_assert(pmech->mechanism != NULL);
+ OPENSSL_assert(pmech->pParameter == NULL);
+ OPENSSL_assert(pmech->ulParameterLen == 0);
+
+#ifdef SOLARIS_AES_CTR
+ if (ctx->cipher->nid == NID_aes_128_ctr ||
+ ctx->cipher->nid == NID_aes_192_ctr ||
+ ctx->cipher->nid == NID_aes_256_ctr)
+ {
+ pmech->pParameter = (void *)(&ctr_params);
+ pmech->ulParameterLen = sizeof (ctr_params);
+ /*
+ * For now, we are limited to the fixed length of the counter,
+ * it covers the whole counter block. That's what RFC 4344
+ * needs. For more information on internal structure of the
+ * counter block, see RFC 3686. If needed in the future, we can
+ * add code so that the counter length can be set via
+ * ENGINE_ctrl() function.
+ */
+ ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
+ OPENSSL_assert(pcipher->iv_len == AES_BLOCK_SIZE);
+ (void) memcpy(ctr_params.cb, ctx->iv, AES_BLOCK_SIZE);
+ }
+ else
+#endif /* SOLARIS_AES_CTR */
+ {
+ if (pcipher->iv_len > 0)
+ {
+ pmech->pParameter = (void *)ctx->iv;
+ pmech->ulParameterLen = pcipher->iv_len;
+ }
+ }
+
+ /* if we get here, the encryption needs to be reinitialized */
+ if (ctx->encrypt)
+ rv = pFuncList->C_EncryptInit(sp->session, pmech,
+ sp->opdata_cipher_key);
+ else
+ rv = pFuncList->C_DecryptInit(sp->session, pmech,
+ sp->opdata_cipher_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_INIT, ctx->encrypt ?
+ PK11_R_ENCRYPTINIT : PK11_R_DECRYPTINIT, rv);
+ pk11_return_session(sp, OP_CIPHER);
+ return (0);
+ }
+
+ return (1);
+ }
+
+/* ARGSUSED */
+static int
+pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+ {
+ CK_MECHANISM mech;
+ int index;
+ PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
+ PK11_SESSION *sp;
+ PK11_CIPHER *p_ciph_table_row;
+
+ state->sp = NULL;
+
+ index = cipher_nid_to_pk11(ctx->cipher->nid);
+ if (index < 0 || index >= PK11_CIPHER_MAX)
+ return (0);
+
+ p_ciph_table_row = &ciphers[index];
+ /*
+ * iv_len in the ctx->cipher structure is the maximum IV length for the
+ * current cipher and it must be less or equal to the IV length in our
+ * ciphers table. The key length must be in the allowed interval. From
+ * all cipher modes that the PKCS#11 engine supports only RC4 allows a
+ * key length to be in some range, all other NIDs have a precise key
+ * length. Every application can define its own EVP functions so this
+ * code serves as a sanity check.
+ *
+ * Note that the reason why the IV length in ctx->cipher might be
+ * greater than the actual length is that OpenSSL uses BLOCK_CIPHER_defs
+ * macro to define functions that return EVP structures for all DES
+ * modes. So, even ECB modes get 8 byte IV.
+ */
+ if (ctx->cipher->iv_len < p_ciph_table_row->iv_len ||
+ ctx->key_len < p_ciph_table_row->min_key_len ||
+ ctx->key_len > p_ciph_table_row->max_key_len) {
+ PK11err(PK11_F_CIPHER_INIT, PK11_R_KEY_OR_IV_LEN_PROBLEM);
+ return (0);
+ }
+
+ if ((sp = pk11_get_session(OP_CIPHER)) == NULL)
+ return (0);
+
+ /* if applicable, the mechanism parameter is used for IV */
+ mech.mechanism = p_ciph_table_row->mech_type;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ /* The key object is destroyed here if it is not the current key. */
+ (void) check_new_cipher_key(sp, key, ctx->key_len);
+
+ /*
+ * If the key is the same and the encryption is also the same, then
+ * just reuse it. However, we must not forget to reinitialize the
+ * context that was finalized in pk11_cipher_cleanup().
+ */
+ if (sp->opdata_cipher_key != CK_INVALID_HANDLE &&
+ sp->opdata_encrypt == ctx->encrypt)
+ {
+ state->sp = sp;
+ if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
+ return (0);
+
+ return (1);
+ }
+
+ /*
+ * Check if the key has been invalidated. If so, a new key object
+ * needs to be created.
+ */
+ if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
+ {
+ sp->opdata_cipher_key = pk11_get_cipher_key(
+ ctx, key, p_ciph_table_row->key_type, sp);
+ }
+
+ if (sp->opdata_encrypt != ctx->encrypt && sp->opdata_encrypt != -1)
+ {
+ /*
+ * The previous encryption/decryption is different. Need to
+ * terminate the previous * active encryption/decryption here.
+ */
+ if (!pk11_cipher_final(sp))
+ {
+ pk11_return_session(sp, OP_CIPHER);
+ return (0);
+ }
+ }
+
+ if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
+ {
+ pk11_return_session(sp, OP_CIPHER);
+ return (0);
+ }
+
+ /* now initialize the context with a new key */
+ if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
+ return (0);
+
+ sp->opdata_encrypt = ctx->encrypt;
+ state->sp = sp;
+
+ return (1);
+ }
+
+/*
+ * When reusing the same key in an encryption/decryption session for a
+ * decryption/encryption session, we need to close the active session
+ * and recreate a new one. Note that the key is in the global session so
+ * that it needs not be recreated.
+ *
+ * It is more appropriate to use C_En/DecryptFinish here. At the time of this
+ * development, these two functions in the PKCS#11 libraries used return
+ * unexpected errors when passing in 0 length output. It may be a good
+ * idea to try them again if performance is a problem here and fix
+ * C_En/DecryptFinial if there are bugs there causing the problem.
+ */
+static int
+pk11_cipher_final(PK11_SESSION *sp)
+ {
+ CK_RV rv;
+
+ rv = pFuncList->C_CloseSession(sp->session);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_CLOSESESSION, rv);
+ return (0);
+ }
+
+ rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL_PTR, &sp->session);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_OPENSESSION, rv);
+ return (0);
+ }
+
+ return (1);
+ }
+
+/*
+ * An engine interface function. The calling function allocates sufficient
+ * memory for the output buffer "out" to hold the results.
+ */
+static int
+pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int inl)
+ {
+ PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
+ PK11_SESSION *sp;
+ CK_RV rv;
+ unsigned long outl = inl;
+
+ if (state == NULL || state->sp == NULL)
+ return (0);
+
+ sp = (PK11_SESSION *) state->sp;
+
+ if (!inl)
+ return (1);
+
+ /* RC4 is the only stream cipher we support */
+ if (ctx->cipher->nid != NID_rc4 && (inl % ctx->cipher->block_size) != 0)
+ return (0);
+
+ if (ctx->encrypt)
+ {
+ rv = pFuncList->C_EncryptUpdate(sp->session,
+ (unsigned char *)in, inl, out, &outl);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
+ PK11_R_ENCRYPTUPDATE, rv);
+ return (0);
+ }
+ }
+ else
+ {
+ rv = pFuncList->C_DecryptUpdate(sp->session,
+ (unsigned char *)in, inl, out, &outl);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
+ PK11_R_DECRYPTUPDATE, rv);
+ return (0);
+ }
+ }
+
+ /*
+ * For DES_CBC, DES3_CBC, AES_CBC, and RC4, the output size is always
+ * the same size of input.
+ * The application has guaranteed to call the block ciphers with
+ * correctly aligned buffers.
+ */
+ if (inl != outl)
+ return (0);
+
+ return (1);
+ }
+
+/*
+ * Return the session to the pool. Calling C_EncryptFinal() and C_DecryptFinal()
+ * here is the right thing because in EVP_DecryptFinal_ex(), engine's
+ * do_cipher() is not even called, and in EVP_EncryptFinal_ex() it is called but
+ * the engine can't find out that it's the finalizing call. We wouldn't
+ * necessarily have to finalize the context here since reinitializing it with
+ * C_(Encrypt|Decrypt)Init() should be fine but for the sake of correctness,
+ * let's do it. Some implementations might leak memory if the previously used
+ * context is initialized without finalizing it first.
+ */
+static int
+pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx)
+ {
+ CK_RV rv;
+ CK_ULONG len = EVP_MAX_BLOCK_LENGTH;
+ CK_BYTE buf[EVP_MAX_BLOCK_LENGTH];
+ PK11_CIPHER_STATE *state = ctx->cipher_data;
+
+ if (state != NULL && state->sp != NULL)
+ {
+ /*
+ * We are not interested in the data here, we just need to get
+ * rid of the context.
+ */
+ if (ctx->encrypt)
+ rv = pFuncList->C_EncryptFinal(
+ state->sp->session, buf, &len);
+ else
+ rv = pFuncList->C_DecryptFinal(
+ state->sp->session, buf, &len);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CIPHER_CLEANUP, ctx->encrypt ?
+ PK11_R_ENCRYPTFINAL : PK11_R_DECRYPTFINAL, rv);
+ pk11_return_session(state->sp, OP_CIPHER);
+ return (0);
+ }
+
+ pk11_return_session(state->sp, OP_CIPHER);
+ state->sp = NULL;
+ }
+
+ return (1);
+ }
+
+/*
+ * Registered by the ENGINE when used to find out how to deal with
+ * a particular NID in the ENGINE. This says what we'll do at the
+ * top level - note, that list is restricted by what we answer with
+ */
+/* ARGSUSED */
+static int
+pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+ const int **nids, int nid)
+ {
+ if (!cipher)
+ return (pk11_usable_ciphers(nids));
+
+ switch (nid)
+ {
+ case NID_des_ede3_cbc:
+ *cipher = &pk11_3des_cbc;
+ break;
+ case NID_des_cbc:
+ *cipher = &pk11_des_cbc;
+ break;
+ case NID_des_ede3_ecb:
+ *cipher = &pk11_3des_ecb;
+ break;
+ case NID_des_ecb:
+ *cipher = &pk11_des_ecb;
+ break;
+ case NID_aes_128_cbc:
+ *cipher = &pk11_aes_128_cbc;
+ break;
+ case NID_aes_192_cbc:
+ *cipher = &pk11_aes_192_cbc;
+ break;
+ case NID_aes_256_cbc:
+ *cipher = &pk11_aes_256_cbc;
+ break;
+ case NID_aes_128_ecb:
+ *cipher = &pk11_aes_128_ecb;
+ break;
+ case NID_aes_192_ecb:
+ *cipher = &pk11_aes_192_ecb;
+ break;
+ case NID_aes_256_ecb:
+ *cipher = &pk11_aes_256_ecb;
+ break;
+ case NID_bf_cbc:
+ *cipher = &pk11_bf_cbc;
+ break;
+ case NID_rc4:
+ *cipher = &pk11_rc4;
+ break;
+ default:
+#ifdef SOLARIS_AES_CTR
+ /*
+ * These can't be in separated cases because the NIDs
+ * here are not constants.
+ */
+ if (nid == NID_aes_128_ctr)
+ *cipher = &pk11_aes_128_ctr;
+ else if (nid == NID_aes_192_ctr)
+ *cipher = &pk11_aes_192_ctr;
+ else if (nid == NID_aes_256_ctr)
+ *cipher = &pk11_aes_256_ctr;
+ else
+#endif /* SOLARIS_AES_CTR */
+ *cipher = NULL;
+ break;
+ }
+ return (*cipher != NULL);
+ }
+
+/* ARGSUSED */
+static int
+pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
+ const int **nids, int nid)
+ {
+ if (!digest)
+ return (pk11_usable_digests(nids));
+
+ switch (nid)
+ {
+ case NID_md5:
+ *digest = &pk11_md5;
+ break;
+ case NID_sha1:
+ *digest = &pk11_sha1;
+ break;
+ case NID_sha224:
+ *digest = &pk11_sha224;
+ break;
+ case NID_sha256:
+ *digest = &pk11_sha256;
+ break;
+ case NID_sha384:
+ *digest = &pk11_sha384;
+ break;
+ case NID_sha512:
+ *digest = &pk11_sha512;
+ break;
+ default:
+ *digest = NULL;
+ break;
+ }
+ return (*digest != NULL);
+ }
+
+
+/* Create a secret key object in a PKCS#11 session */
+static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
+ const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp)
+ {
+ CK_RV rv;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS obj_key = CKO_SECRET_KEY;
+ CK_ULONG ul_key_attr_count = 6;
+
+ CK_ATTRIBUTE a_key_template[] =
+ {
+ {CKA_CLASS, (void*) NULL, sizeof (CK_OBJECT_CLASS)},
+ {CKA_KEY_TYPE, (void*) NULL, sizeof (CK_KEY_TYPE)},
+ {CKA_TOKEN, &pk11_false, sizeof (pk11_false)},
+ {CKA_ENCRYPT, &pk11_true, sizeof (pk11_true)},
+ {CKA_DECRYPT, &pk11_true, sizeof (pk11_true)},
+ {CKA_VALUE, (void*) NULL, 0},
+ };
+
+ /*
+ * Create secret key object in global_session. All other sessions
+ * can use the key handles. Here is why:
+ * OpenSSL will call EncryptInit and EncryptUpdate using a secret key.
+ * It may then call DecryptInit and DecryptUpdate using the same key.
+ * To use the same key object, we need to call EncryptFinal with
+ * a 0 length message. Currently, this does not work for 3DES
+ * mechanism. To get around this problem, we close the session and
+ * then create a new session to use the same key object. When a session
+ * is closed, all the object handles will be invalid. Thus, create key
+ * objects in a global session, an individual session may be closed to
+ * terminate the active operation.
+ */
+ CK_SESSION_HANDLE session = global_session;
+ a_key_template[0].pValue = &obj_key;
+ a_key_template[1].pValue = &key_type;
+ a_key_template[5].pValue = (void *) key;
+ a_key_template[5].ulValueLen = (unsigned long) ctx->key_len;
+
+ rv = pFuncList->C_CreateObject(session,
+ a_key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_CIPHER_KEY, PK11_R_CREATEOBJECT,
+ rv);
+ goto err;
+ }
+
+ /*
+ * Save the key information used in this session.
+ * The max can be saved is PK11_KEY_LEN_MAX.
+ */
+ sp->opdata_key_len = ctx->key_len > PK11_KEY_LEN_MAX ?
+ PK11_KEY_LEN_MAX : ctx->key_len;
+ (void) memcpy(sp->opdata_key, key, sp->opdata_key_len);
+err:
+
+ return (h_key);
+ }
+
+static int
+md_nid_to_pk11(int nid)
+ {
+ int i;
+
+ for (i = 0; i < PK11_DIGEST_MAX; i++)
+ if (digests[i].nid == nid)
+ return (digests[i].id);
+ return (-1);
+ }
+
+static int
+pk11_digest_init(EVP_MD_CTX *ctx)
+ {
+ CK_RV rv;
+ CK_MECHANISM mech;
+ int index;
+ PK11_SESSION *sp;
+ PK11_DIGEST *pdp;
+ PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
+
+ state->sp = NULL;
+
+ index = md_nid_to_pk11(ctx->digest->type);
+ if (index < 0 || index >= PK11_DIGEST_MAX)
+ return (0);
+
+ pdp = &digests[index];
+ if ((sp = pk11_get_session(OP_DIGEST)) == NULL)
+ return (0);
+
+ /* at present, no parameter is needed for supported digests */
+ mech.mechanism = pdp->mech_type;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ rv = pFuncList->C_DigestInit(sp->session, &mech);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_INIT, PK11_R_DIGESTINIT, rv);
+ pk11_return_session(sp, OP_DIGEST);
+ return (0);
+ }
+
+ state->sp = sp;
+
+ return (1);
+ }
+
+static int
+pk11_digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
+ {
+ CK_RV rv;
+ PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
+
+ /* 0 length message will cause a failure in C_DigestFinal */
+ if (count == 0)
+ return (1);
+
+ if (state == NULL || state->sp == NULL)
+ return (0);
+
+ rv = pFuncList->C_DigestUpdate(state->sp->session, (CK_BYTE *) data,
+ count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_UPDATE, PK11_R_DIGESTUPDATE, rv);
+ pk11_return_session(state->sp, OP_DIGEST);
+ state->sp = NULL;
+ return (0);
+ }
+
+ return (1);
+ }
+
+static int
+pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
+ {
+ CK_RV rv;
+ unsigned long len;
+ PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
+ len = ctx->digest->md_size;
+
+ if (state == NULL || state->sp == NULL)
+ return (0);
+
+ rv = pFuncList->C_DigestFinal(state->sp->session, md, &len);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_FINAL, PK11_R_DIGESTFINAL, rv);
+ pk11_return_session(state->sp, OP_DIGEST);
+ state->sp = NULL;
+ return (0);
+ }
+
+ if (ctx->digest->md_size != len)
+ return (0);
+
+ /*
+ * Final is called and digest is returned, so return the session
+ * to the pool
+ */
+ pk11_return_session(state->sp, OP_DIGEST);
+ state->sp = NULL;
+
+ return (1);
+ }
+
+static int
+pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
+ {
+ CK_RV rv;
+ int ret = 0;
+ PK11_CIPHER_STATE *state, *state_to;
+ CK_BYTE_PTR pstate = NULL;
+ CK_ULONG ul_state_len;
+
+ /* The copy-from state */
+ state = (PK11_CIPHER_STATE *) from->md_data;
+ if (state == NULL || state->sp == NULL)
+ goto err;
+
+ /* Initialize the copy-to state */
+ if (!pk11_digest_init(to))
+ goto err;
+ state_to = (PK11_CIPHER_STATE *) to->md_data;
+
+ /* Get the size of the operation state of the copy-from session */
+ rv = pFuncList->C_GetOperationState(state->sp->session, NULL,
+ &ul_state_len);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
+ rv);
+ goto err;
+ }
+ if (ul_state_len == 0)
+ {
+ goto err;
+ }
+
+ pstate = OPENSSL_malloc(ul_state_len);
+ if (pstate == NULL)
+ {
+ PK11err(PK11_F_DIGEST_COPY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Get the operation state of the copy-from session */
+ rv = pFuncList->C_GetOperationState(state->sp->session, pstate,
+ &ul_state_len);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
+ rv);
+ goto err;
+ }
+
+ /* Set the operation state of the copy-to session */
+ rv = pFuncList->C_SetOperationState(state_to->sp->session, pstate,
+ ul_state_len, 0, 0);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DIGEST_COPY,
+ PK11_R_SET_OPERATION_STATE, rv);
+ goto err;
+ }
+
+ ret = 1;
+err:
+ if (pstate != NULL)
+ OPENSSL_free(pstate);
+
+ return (ret);
+ }
+
+/* Return any pending session state to the pool */
+static int
+pk11_digest_cleanup(EVP_MD_CTX *ctx)
+ {
+ PK11_CIPHER_STATE *state = ctx->md_data;
+ unsigned char buf[EVP_MAX_MD_SIZE];
+
+ if (state != NULL && state->sp != NULL)
+ {
+ /*
+ * If state->sp is not NULL then pk11_digest_final() has not
+ * been called yet. We must call it now to free any memory
+ * that might have been allocated in the token when
+ * pk11_digest_init() was called. pk11_digest_final()
+ * will return the session to the cache.
+ */
+ if (!pk11_digest_final(ctx, buf))
+ return (0);
+ }
+
+ return (1);
+ }
+
+/*
+ * Check if the new key is the same as the key object in the session. If the key
+ * is the same, no need to create a new key object. Otherwise, the old key
+ * object needs to be destroyed and a new one will be created. Return 1 for
+ * cache hit, 0 for cache miss. Note that we must check the key length first
+ * otherwise we could end up reusing a different, longer key with the same
+ * prefix.
+ */
+static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
+ int key_len)
+ {
+ if (sp->opdata_key_len != key_len ||
+ memcmp(sp->opdata_key, key, key_len) != 0)
+ {
+ (void) pk11_destroy_cipher_key_objects(sp);
+ return (0);
+ }
+ return (1);
+ }
+
+/* Destroy one or more secret key objects. */
+static int pk11_destroy_cipher_key_objects(PK11_SESSION *session)
+ {
+ int ret = 0;
+ PK11_SESSION *sp = NULL;
+ PK11_SESSION *local_free_session;
+
+ if (session != NULL)
+ local_free_session = session;
+ else
+ {
+ (void) pthread_mutex_lock(session_cache[OP_CIPHER].lock);
+ local_free_session = session_cache[OP_CIPHER].head;
+ }
+
+ while ((sp = local_free_session) != NULL)
+ {
+ local_free_session = sp->next;
+
+ if (sp->opdata_cipher_key != CK_INVALID_HANDLE)
+ {
+ /*
+ * The secret key object is created in the
+ * global_session. See pk11_get_cipher_key().
+ */
+ if (pk11_destroy_object(global_session,
+ sp->opdata_cipher_key, CK_FALSE) == 0)
+ goto err;
+ sp->opdata_cipher_key = CK_INVALID_HANDLE;
+ }
+ }
+ ret = 1;
+err:
+
+ if (session == NULL)
+ (void) pthread_mutex_unlock(session_cache[OP_CIPHER].lock);
+
+ return (ret);
+ }
+
+
+/*
+ * Public key mechanisms optionally supported
+ *
+ * CKM_RSA_X_509
+ * CKM_RSA_PKCS
+ * CKM_DSA
+ *
+ * The first slot that supports at least one of those mechanisms is chosen as a
+ * public key slot.
+ *
+ * Symmetric ciphers optionally supported
+ *
+ * CKM_DES3_CBC
+ * CKM_DES_CBC
+ * CKM_AES_CBC
+ * CKM_DES3_ECB
+ * CKM_DES_ECB
+ * CKM_AES_ECB
+ * CKM_AES_CTR
+ * CKM_RC4
+ * CKM_BLOWFISH_CBC
+ *
+ * Digests optionally supported
+ *
+ * CKM_MD5
+ * CKM_SHA_1
+ * CKM_SHA224
+ * CKM_SHA256
+ * CKM_SHA384
+ * CKM_SHA512
+ *
+ * The output of this function is a set of global variables indicating which
+ * mechanisms from RSA, DSA, DH and RAND are present, and also two arrays of
+ * mechanisms, one for symmetric ciphers and one for digests. Also, 3 global
+ * variables carry information about which slot was chosen for (a) public key
+ * mechanisms, (b) random operations, and (c) symmetric ciphers and digests.
+ */
+static int
+pk11_choose_slots(int *any_slot_found)
+ {
+ CK_SLOT_ID_PTR pSlotList = NULL_PTR;
+ CK_ULONG ulSlotCount = 0;
+ CK_MECHANISM_INFO mech_info;
+ CK_TOKEN_INFO token_info;
+ int i;
+ CK_RV rv;
+ CK_SLOT_ID best_slot_sofar;
+ CK_BBOOL found_candidate_slot = CK_FALSE;
+ int slot_n_cipher = 0;
+ int slot_n_digest = 0;
+ CK_SLOT_ID current_slot = 0;
+ int current_slot_n_cipher = 0;
+ int current_slot_n_digest = 0;
+
+ int local_cipher_nids[PK11_CIPHER_MAX];
+ int local_digest_nids[PK11_DIGEST_MAX];
+
+ /* let's initialize the output parameter */
+ if (any_slot_found != NULL)
+ *any_slot_found = 0;
+
+ /* Get slot list for memory allocation */
+ rv = pFuncList->C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
+ return (0);
+ }
+
+ /* it's not an error if we didn't find any providers */
+ if (ulSlotCount == 0)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: no crypto providers found\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ return (1);
+ }
+
+ pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
+
+ if (pSlotList == NULL)
+ {
+ PK11err(PK11_F_CHOOSE_SLOT, PK11_R_MALLOC_FAILURE);
+ return (0);
+ }
+
+ /* Get the slot list for processing */
+ rv = pFuncList->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
+ OPENSSL_free(pSlotList);
+ return (0);
+ }
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: provider: %s\n", PK11_DBG, def_PK11_LIBNAME);
+ fprintf(stderr, "%s: number of slots: %d\n", PK11_DBG, ulSlotCount);
+
+ fprintf(stderr, "%s: == checking rand slots ==\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ for (i = 0; i < ulSlotCount; i++)
+ {
+ current_slot = pSlotList[i];
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
+#endif /* DEBUG_SLOT_SELECTION */
+ /* Check if slot has random support. */
+ rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
+ if (rv != CKR_OK)
+ continue;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ if (token_info.flags & CKF_RNG)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: this token has CKF_RNG flag\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ pk11_have_random = CK_TRUE;
+ rand_SLOTID = current_slot;
+ break;
+ }
+ }
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: == checking pubkey slots ==\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ pubkey_SLOTID = pSlotList[0];
+ for (i = 0; i < ulSlotCount; i++)
+ {
+ CK_BBOOL slot_has_rsa = CK_FALSE;
+ CK_BBOOL slot_has_dsa = CK_FALSE;
+ CK_BBOOL slot_has_dh = CK_FALSE;
+ current_slot = pSlotList[i];
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
+#endif /* DEBUG_SLOT_SELECTION */
+ rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
+ if (rv != CKR_OK)
+ continue;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
+#endif /* DEBUG_SLOT_SELECTION */
+
+#ifndef OPENSSL_NO_RSA
+ /*
+ * Check if this slot is capable of signing and
+ * verifying with CKM_RSA_PKCS.
+ */
+ rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_RSA_PKCS,
+ &mech_info);
+
+ if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
+ (mech_info.flags & CKF_VERIFY)))
+ {
+ /*
+ * Check if this slot is capable of encryption,
+ * decryption, sign, and verify with CKM_RSA_X_509.
+ */
+ rv = pFuncList->C_GetMechanismInfo(current_slot,
+ CKM_RSA_X_509, &mech_info);
+
+ if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
+ (mech_info.flags & CKF_VERIFY) &&
+ (mech_info.flags & CKF_ENCRYPT) &&
+ (mech_info.flags & CKF_VERIFY_RECOVER) &&
+ (mech_info.flags & CKF_DECRYPT)))
+ {
+ slot_has_rsa = CK_TRUE;
+ }
+ }
+#endif /* OPENSSL_NO_RSA */
+
+#ifndef OPENSSL_NO_DSA
+ /*
+ * Check if this slot is capable of signing and
+ * verifying with CKM_DSA.
+ */
+ rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_DSA,
+ &mech_info);
+ if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
+ (mech_info.flags & CKF_VERIFY)))
+ {
+ slot_has_dsa = CK_TRUE;
+ }
+
+#endif /* OPENSSL_NO_DSA */
+
+#ifndef OPENSSL_NO_DH
+ /*
+ * Check if this slot is capable of DH key generataion and
+ * derivation.
+ */
+ rv = pFuncList->C_GetMechanismInfo(current_slot,
+ CKM_DH_PKCS_KEY_PAIR_GEN, &mech_info);
+
+ if (rv == CKR_OK && (mech_info.flags & CKF_GENERATE_KEY_PAIR))
+ {
+ rv = pFuncList->C_GetMechanismInfo(current_slot,
+ CKM_DH_PKCS_DERIVE, &mech_info);
+ if (rv == CKR_OK && (mech_info.flags & CKF_DERIVE))
+ {
+ slot_has_dh = CK_TRUE;
+ }
+ }
+#endif /* OPENSSL_NO_DH */
+
+ if (!found_candidate_slot &&
+ (slot_has_rsa || slot_has_dsa || slot_has_dh))
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr,
+ "%s: potential slot: %d\n", PK11_DBG, current_slot);
+#endif /* DEBUG_SLOT_SELECTION */
+ best_slot_sofar = current_slot;
+ pk11_have_rsa = slot_has_rsa;
+ pk11_have_dsa = slot_has_dsa;
+ pk11_have_dh = slot_has_dh;
+ found_candidate_slot = CK_TRUE;
+ /*
+ * Cache the flags for later use. We might need those if
+ * RSA keys by reference feature is used.
+ */
+ pubkey_token_flags = token_info.flags;
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr,
+ "%s: setting found_candidate_slot to CK_TRUE\n",
+ PK11_DBG);
+ fprintf(stderr,
+ "%s: best so far slot: %d\n", PK11_DBG,
+ best_slot_sofar);
+ fprintf(stderr, "%s: pubkey flags changed to "
+ "%lu.\n", PK11_DBG, pubkey_token_flags);
+ }
+ else
+ {
+ fprintf(stderr,
+ "%s: no rsa/dsa/dh\n", PK11_DBG);
+ }
+#else
+ } /* if */
+#endif /* DEBUG_SLOT_SELECTION */
+ } /* for */
+
+ if (found_candidate_slot == CK_TRUE)
+ {
+ pubkey_SLOTID = best_slot_sofar;
+ }
+
+ found_candidate_slot = CK_FALSE;
+ best_slot_sofar = 0;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: == checking cipher/digest ==\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ SLOTID = pSlotList[0];
+ for (i = 0; i < ulSlotCount; i++)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ current_slot = pSlotList[i];
+ current_slot_n_cipher = 0;
+ current_slot_n_digest = 0;
+ (void) memset(local_cipher_nids, 0, sizeof (local_cipher_nids));
+ (void) memset(local_digest_nids, 0, sizeof (local_digest_nids));
+
+ pk11_find_symmetric_ciphers(pFuncList, current_slot,
+ &current_slot_n_cipher, local_cipher_nids);
+
+ pk11_find_digests(pFuncList, current_slot,
+ &current_slot_n_digest, local_digest_nids);
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: current_slot_n_cipher %d\n", PK11_DBG,
+ current_slot_n_cipher);
+ fprintf(stderr, "%s: current_slot_n_digest %d\n", PK11_DBG,
+ current_slot_n_digest);
+ fprintf(stderr, "%s: best so far cipher/digest slot: %d\n",
+ PK11_DBG, best_slot_sofar);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ /*
+ * If the current slot supports more ciphers/digests than
+ * the previous best one we change the current best to this one,
+ * otherwise leave it where it is.
+ */
+ if ((current_slot_n_cipher + current_slot_n_digest) >
+ (slot_n_cipher + slot_n_digest))
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr,
+ "%s: changing best so far slot to %d\n",
+ PK11_DBG, current_slot);
+#endif /* DEBUG_SLOT_SELECTION */
+ best_slot_sofar = SLOTID = current_slot;
+ cipher_count = slot_n_cipher = current_slot_n_cipher;
+ digest_count = slot_n_digest = current_slot_n_digest;
+ (void) memcpy(cipher_nids, local_cipher_nids,
+ sizeof (local_cipher_nids));
+ (void) memcpy(digest_nids, local_digest_nids,
+ sizeof (local_digest_nids));
+ }
+ }
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr,
+ "%s: chosen pubkey slot: %d\n", PK11_DBG, pubkey_SLOTID);
+ fprintf(stderr,
+ "%s: chosen rand slot: %d\n", PK11_DBG, rand_SLOTID);
+ fprintf(stderr,
+ "%s: chosen cipher/digest slot: %d\n", PK11_DBG, SLOTID);
+ fprintf(stderr,
+ "%s: pk11_have_rsa %d\n", PK11_DBG, pk11_have_rsa);
+ fprintf(stderr,
+ "%s: pk11_have_dsa %d\n", PK11_DBG, pk11_have_dsa);
+ fprintf(stderr,
+ "%s: pk11_have_dh %d\n", PK11_DBG, pk11_have_dh);
+ fprintf(stderr,
+ "%s: pk11_have_random %d\n", PK11_DBG, pk11_have_random);
+ fprintf(stderr,
+ "%s: cipher_count %d\n", PK11_DBG, cipher_count);
+ fprintf(stderr,
+ "%s: digest_count %d\n", PK11_DBG, digest_count);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ if (pSlotList != NULL)
+ OPENSSL_free(pSlotList);
+
+#ifdef SOLARIS_HW_SLOT_SELECTION
+ OPENSSL_free(hw_cnids);
+ OPENSSL_free(hw_dnids);
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+
+ if (any_slot_found != NULL)
+ *any_slot_found = 1;
+ return (1);
+ }
+
+static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR pflist,
+ int slot_id, CK_MECHANISM_TYPE mech, int *current_slot_n_cipher,
+ int *local_cipher_nids, int id)
+ {
+ CK_MECHANISM_INFO mech_info;
+ CK_RV rv;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
+#endif /* DEBUG_SLOT_SELECTION */
+ rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
+
+ if (rv != CKR_OK)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, " not found\n");
+#endif /* DEBUG_SLOT_SELECTION */
+ return;
+ }
+
+ if ((mech_info.flags & CKF_ENCRYPT) &&
+ (mech_info.flags & CKF_DECRYPT))
+ {
+#ifdef SOLARIS_HW_SLOT_SELECTION
+ if (nid_in_table(ciphers[id].nid, hw_cnids))
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, " usable\n");
+#endif /* DEBUG_SLOT_SELECTION */
+ local_cipher_nids[(*current_slot_n_cipher)++] =
+ ciphers[id].nid;
+ }
+#ifdef SOLARIS_HW_SLOT_SELECTION
+#ifdef DEBUG_SLOT_SELECTION
+ else
+ {
+ fprintf(stderr, " rejected, software implementation only\n");
+ }
+#endif /* DEBUG_SLOT_SELECTION */
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+ }
+#ifdef DEBUG_SLOT_SELECTION
+ else
+ {
+ fprintf(stderr, " unusable\n");
+ }
+#endif /* DEBUG_SLOT_SELECTION */
+
+ return;
+ }
+
+static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
+ CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
+ int id)
+ {
+ CK_MECHANISM_INFO mech_info;
+ CK_RV rv;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
+#endif /* DEBUG_SLOT_SELECTION */
+ rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
+
+ if (rv != CKR_OK)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, " not found\n");
+#endif /* DEBUG_SLOT_SELECTION */
+ return;
+ }
+
+ if (mech_info.flags & CKF_DIGEST)
+ {
+#ifdef SOLARIS_HW_SLOT_SELECTION
+ if (nid_in_table(digests[id].nid, hw_dnids))
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, " usable\n");
+#endif /* DEBUG_SLOT_SELECTION */
+ local_digest_nids[(*current_slot_n_digest)++] =
+ digests[id].nid;
+ }
+#ifdef SOLARIS_HW_SLOT_SELECTION
+#ifdef DEBUG_SLOT_SELECTION
+ else
+ {
+ fprintf(stderr, " rejected, software implementation only\n");
+ }
+#endif /* DEBUG_SLOT_SELECTION */
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+ }
+#ifdef DEBUG_SLOT_SELECTION
+ else
+ {
+ fprintf(stderr, " unusable\n");
+ }
+#endif /* DEBUG_SLOT_SELECTION */
+
+ return;
+ }
+
+#ifdef SOLARIS_AES_CTR
+/* create a new NID when we have no OID for that mechanism */
+static int pk11_add_NID(char *sn, char *ln)
+ {
+ ASN1_OBJECT *o;
+ int nid;
+
+ if ((o = ASN1_OBJECT_create(OBJ_new_nid(1), (unsigned char *)"",
+ 1, sn, ln)) == NULL)
+ {
+ return (0);
+ }
+
+ /* will return NID_undef on error */
+ nid = OBJ_add_object(o);
+ ASN1_OBJECT_free(o);
+
+ return (nid);
+ }
+
+/*
+ * Create new NIDs for AES counter mode. OpenSSL doesn't support them now so we
+ * have to help ourselves here.
+ */
+static int pk11_add_aes_ctr_NIDs(void)
+ {
+ /* are we already set? */
+ if (NID_aes_256_ctr != NID_undef)
+ return (1);
+
+ /*
+ * There are no official names for AES counter modes yet so we just
+ * follow the format of those that exist.
+ */
+ if ((NID_aes_128_ctr = pk11_add_NID("AES-128-CTR", "aes-128-ctr")) ==
+ NID_undef)
+ goto err;
+ ciphers[PK11_AES_128_CTR].nid = pk11_aes_128_ctr.nid = NID_aes_128_ctr;
+ if ((NID_aes_192_ctr = pk11_add_NID("AES-192-CTR", "aes-192-ctr")) ==
+ NID_undef)
+ goto err;
+ ciphers[PK11_AES_192_CTR].nid = pk11_aes_192_ctr.nid = NID_aes_192_ctr;
+ if ((NID_aes_256_ctr = pk11_add_NID("AES-256-CTR", "aes-256-ctr")) ==
+ NID_undef)
+ goto err;
+ ciphers[PK11_AES_256_CTR].nid = pk11_aes_256_ctr.nid = NID_aes_256_ctr;
+ return (1);
+
+err:
+ PK11err(PK11_F_ADD_AES_CTR_NIDS, PK11_R_ADD_NID_FAILED);
+ return (0);
+ }
+#endif /* SOLARIS_AES_CTR */
+
+/* Find what symmetric ciphers this slot supports. */
+static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
+ CK_SLOT_ID current_slot, int *current_slot_n_cipher, int *local_cipher_nids)
+ {
+ int i;
+
+ for (i = 0; i < PK11_CIPHER_MAX; ++i)
+ {
+ pk11_get_symmetric_cipher(pflist, current_slot,
+ ciphers[i].mech_type, current_slot_n_cipher,
+ local_cipher_nids, ciphers[i].id);
+ }
+ }
+
+/* Find what digest algorithms this slot supports. */
+static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
+ CK_SLOT_ID current_slot, int *current_slot_n_digest, int *local_digest_nids)
+ {
+ int i;
+
+ for (i = 0; i < PK11_DIGEST_MAX; ++i)
+ {
+ pk11_get_digest(pflist, current_slot, digests[i].mech_type,
+ current_slot_n_digest, local_digest_nids, digests[i].id);
+ }
+ }
+
+#ifdef SOLARIS_HW_SLOT_SELECTION
+/*
+ * It would be great if we could use pkcs11_kernel directly since this library
+ * offers hardware slots only. That's the easiest way to achieve the situation
+ * where we use the hardware accelerators when present and OpenSSL native code
+ * otherwise. That presumes the fact that OpenSSL native code is faster than the
+ * code in the soft token. It's a logical assumption - Crypto Framework has some
+ * inherent overhead so going there for the software implementation of a
+ * mechanism should be logically slower in contrast to the OpenSSL native code,
+ * presuming that both implementations are of similar speed. For example, the
+ * soft token for AES is roughly three times slower than OpenSSL for 64 byte
+ * blocks and still 20% slower for 8KB blocks. So, if we want to ship products
+ * that use the PKCS#11 engine by default, we must somehow avoid that regression
+ * on machines without hardware acceleration. That's why switching to the
+ * pkcs11_kernel library seems like a very good idea.
+ *
+ * The problem is that OpenSSL built with SunStudio is roughly 2x slower for
+ * asymmetric operations (RSA/DSA/DH) than the soft token built with the same
+ * compiler. That means that if we switched to pkcs11_kernel from the libpkcs11
+ * library, we would have had a performance regression on machines without
+ * hardware acceleration for asymmetric operations for all applications that use
+ * the PKCS#11 engine. There is one such application - Apache web server since
+ * it's shipped configured to use the PKCS#11 engine by default. Having said
+ * that, we can't switch to the pkcs11_kernel library now and have to come with
+ * a solution that, on non-accelerated machines, uses the OpenSSL native code
+ * for all symmetric ciphers and digests while it uses the soft token for
+ * asymmetric operations.
+ *
+ * This is the idea: dlopen() pkcs11_kernel directly and find out what
+ * mechanisms are there. We don't care about duplications (more slots can
+ * support the same mechanism), we just want to know what mechanisms can be
+ * possibly supported in hardware on that particular machine. As said before,
+ * pkcs11_kernel will show you hardware providers only.
+ *
+ * Then, we rely on the fact that since we use libpkcs11 library we will find
+ * the metaslot. When we go through the metaslot's mechanisms for symmetric
+ * ciphers and digests, we check that any found mechanism is in the table
+ * created using the pkcs11_kernel library. So, as a result we have two arrays
+ * of mechanisms that were advertised as supported in hardware which was the
+ * goal of that whole excercise. Thus, we can use libpkcs11 but avoid soft token
+ * code for symmetric ciphers and digests. See pk11_choose_slots() for more
+ * information.
+ *
+ * This is Solaris specific code, if SOLARIS_HW_SLOT_SELECTION is not defined
+ * the code won't be used.
+ */
+#if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
+static const char pkcs11_kernel[] = "/usr/lib/security/64/pkcs11_kernel.so.1";
+#else
+static const char pkcs11_kernel[] = "/usr/lib/security/pkcs11_kernel.so.1";
+#endif
+
+/*
+ * Check hardware capabilities of the machines. The output are two lists,
+ * hw_cnids and hw_dnids, that contain hardware mechanisms found in all hardware
+ * providers together. They are not sorted and may contain duplicate mechanisms.
+ */
+static int check_hw_mechanisms(void)
+ {
+ int i;
+ CK_RV rv;
+ void *handle;
+ CK_C_GetFunctionList p;
+ CK_TOKEN_INFO token_info;
+ CK_ULONG ulSlotCount = 0;
+ int n_cipher = 0, n_digest = 0;
+ CK_FUNCTION_LIST_PTR pflist = NULL;
+ CK_SLOT_ID_PTR pSlotList = NULL_PTR;
+ int *tmp_hw_cnids = NULL, *tmp_hw_dnids = NULL;
+ int hw_ctable_size, hw_dtable_size;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: SOLARIS_HW_SLOT_SELECTION code running\n",
+ PK11_DBG);
+#endif
+ /*
+ * Use RTLD_GROUP to limit the pkcs11_kernel provider to its own
+ * symbols, which prevents it from mistakenly accessing C_* functions
+ * from the top-level PKCS#11 library.
+ */
+ if ((handle = dlopen(pkcs11_kernel, RTLD_LAZY | RTLD_GROUP)) == NULL)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+
+ if ((p = (CK_C_GetFunctionList)dlsym(handle,
+ PK11_GET_FUNCTION_LIST)) == NULL)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+
+ /* get the full function list from the loaded library */
+ if (p(&pflist) != CKR_OK)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
+ goto err;
+ }
+
+ rv = pflist->C_Initialize(NULL_PTR);
+ if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
+ {
+ PK11err_add_data(PK11_F_CHECK_HW_MECHANISMS,
+ PK11_R_INITIALIZE, rv);
+ goto err;
+ }
+
+ if (pflist->C_GetSlotList(0, NULL_PTR, &ulSlotCount) != CKR_OK)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
+ goto err;
+ }
+
+ /* no slots, set the hw mechanism tables as empty */
+ if (ulSlotCount == 0)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: no hardware mechanisms found\n", PK11_DBG);
+#endif
+ hw_cnids = OPENSSL_malloc(sizeof (int));
+ hw_dnids = OPENSSL_malloc(sizeof (int));
+ if (hw_cnids == NULL || hw_dnids == NULL)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS,
+ PK11_R_MALLOC_FAILURE);
+ return (0);
+ }
+ /* this means empty tables */
+ hw_cnids[0] = NID_undef;
+ hw_dnids[0] = NID_undef;
+ return (1);
+ }
+
+ pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
+ if (pSlotList == NULL)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Get the slot list for processing */
+ if (pflist->C_GetSlotList(0, pSlotList, &ulSlotCount) != CKR_OK)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
+ goto err;
+ }
+
+ /*
+ * We don't care about duplicit mechanisms in multiple slots and also
+ * reserve one slot for the terminal NID_undef which we use to stop the
+ * search.
+ */
+ hw_ctable_size = ulSlotCount * PK11_CIPHER_MAX + 1;
+ hw_dtable_size = ulSlotCount * PK11_DIGEST_MAX + 1;
+ tmp_hw_cnids = OPENSSL_malloc(hw_ctable_size * sizeof (int));
+ tmp_hw_dnids = OPENSSL_malloc(hw_dtable_size * sizeof (int));
+ if (tmp_hw_cnids == NULL || tmp_hw_dnids == NULL)
+ {
+ PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /*
+ * Do not use memset since we should not rely on the fact that NID_undef
+ * is zero now.
+ */
+ for (i = 0; i < hw_ctable_size; ++i)
+ tmp_hw_cnids[i] = NID_undef;
+ for (i = 0; i < hw_dtable_size; ++i)
+ tmp_hw_dnids[i] = NID_undef;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: provider: %s\n", PK11_DBG, pkcs11_kernel);
+ fprintf(stderr, "%s: found %d hardware slots\n", PK11_DBG, ulSlotCount);
+ fprintf(stderr, "%s: now looking for mechs supported in hw\n",
+ PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ for (i = 0; i < ulSlotCount; i++)
+ {
+ if (pflist->C_GetTokenInfo(pSlotList[i], &token_info) != CKR_OK)
+ continue;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
+#endif /* DEBUG_SLOT_SELECTION */
+
+ /*
+ * We are filling the hw mech tables here. Global tables are
+ * still NULL so all mechanisms are put into tmp tables.
+ */
+ pk11_find_symmetric_ciphers(pflist, pSlotList[i],
+ &n_cipher, tmp_hw_cnids);
+ pk11_find_digests(pflist, pSlotList[i],
+ &n_digest, tmp_hw_dnids);
+ }
+
+ /*
+ * Since we are part of a library (libcrypto.so), calling this function
+ * may have side-effects. Also, C_Finalize() is triggered by
+ * dlclose(3C).
+ */
+#if 0
+ pflist->C_Finalize(NULL);
+#endif
+ OPENSSL_free(pSlotList);
+ (void) dlclose(handle);
+ hw_cnids = tmp_hw_cnids;
+ hw_dnids = tmp_hw_dnids;
+
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, "%s: hw mechs check complete\n", PK11_DBG);
+#endif /* DEBUG_SLOT_SELECTION */
+ return (1);
+
+err:
+ if (pSlotList != NULL)
+ OPENSSL_free(pSlotList);
+ if (tmp_hw_cnids != NULL)
+ OPENSSL_free(tmp_hw_cnids);
+ if (tmp_hw_dnids != NULL)
+ OPENSSL_free(tmp_hw_dnids);
+
+ return (0);
+ }
+
+/*
+ * Check presence of a NID in the table of NIDs. The table may be NULL (i.e.,
+ * non-existent).
+ */
+static int nid_in_table(int nid, int *nid_table)
+ {
+ int i = 0;
+
+ /*
+ * a special case. NULL means that we are initializing a new
+ * table.
+ */
+ if (nid_table == NULL)
+ return (1);
+
+ /*
+ * the table is never full, there is always at least one
+ * NID_undef.
+ */
+ while (nid_table[i] != NID_undef)
+ {
+ if (nid_table[i++] == nid)
+ {
+#ifdef DEBUG_SLOT_SELECTION
+ fprintf(stderr, " (NID %d in hw table, idx %d)", nid, i);
+#endif /* DEBUG_SLOT_SELECTION */
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+#endif /* SOLARIS_HW_SLOT_SELECTION */
+
+#endif /* OPENSSL_NO_HW_PK11 */
+#endif /* OPENSSL_NO_HW */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11.h b/openssl0.9.8/engines/pkcs11/hw_pk11.h
new file mode 100644
index 0000000..4c753a1
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* crypto/engine/hw_pk11.h */
+/*
+ * This product includes software developed by the OpenSSL Project for
+ * use in the OpenSSL Toolkit (http://www.openssl.org/).
+ *
+ * This project also referenced hw_pkcs11-0.9.7b.patch written by
+ * Afchine Madjlessi.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * the documentation and/or other materials provided with the
+ * 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).
+ *
+ */
+
+#ifndef HW_PK11_H
+#define HW_PK11_H
+
+#include "hw_pk11_err.h"
+
+/* max byte length of a symetric key we support */
+#define PK11_KEY_LEN_MAX 32
+
+/*
+ * This structure encapsulates all reusable information for a PKCS#11
+ * session. A list of these objects is created on behalf of the
+ * calling application using an on-demand method. Each operation
+ * type (see PK11_OPTYPE below) has its own per-process list.
+ * Each of the lists is basically a cache for faster PKCS#11 object
+ * access to avoid expensive C_Find{,Init,Final}Object() calls.
+ *
+ * When a new request comes in, an object will be taken from the list
+ * (if there is one) or a new one is created to handle the request
+ * (if the list is empty). See pk11_get_session() on how it is done.
+ */
+typedef struct PK11_st_SESSION
+ {
+ struct PK11_st_SESSION *next;
+ CK_SESSION_HANDLE session; /* PK11 session handle */
+ pid_t pid; /* Current process ID */
+ CK_BBOOL persistent; /* is that a keystore object? */
+ union
+ {
+#ifndef OPENSSL_NO_RSA
+ struct
+ {
+ CK_OBJECT_HANDLE rsa_pub_key; /* pub handle */
+ CK_OBJECT_HANDLE rsa_priv_key; /* priv handle */
+ RSA *rsa_pub; /* pub key addr */
+ BIGNUM *rsa_n_num; /* pub modulus */
+ BIGNUM *rsa_e_num; /* pub exponent */
+ RSA *rsa_priv; /* priv key addr */
+ BIGNUM *rsa_d_num; /* priv exponent */
+ } u_RSA;
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+ struct
+ {
+ CK_OBJECT_HANDLE dsa_pub_key; /* pub handle */
+ CK_OBJECT_HANDLE dsa_priv_key; /* priv handle */
+ DSA *dsa_pub; /* pub key addr */
+ BIGNUM *dsa_pub_num; /* pub key */
+ DSA *dsa_priv; /* priv key addr */
+ BIGNUM *dsa_priv_num; /* priv key */
+ } u_DSA;
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+ struct
+ {
+ CK_OBJECT_HANDLE dh_key; /* key handle */
+ DH *dh; /* dh key addr */
+ BIGNUM *dh_priv_num; /* priv dh key */
+ } u_DH;
+#endif /* OPENSSL_NO_DH */
+ struct
+ {
+ CK_OBJECT_HANDLE cipher_key; /* key handle */
+ unsigned char key[PK11_KEY_LEN_MAX];
+ int key_len; /* priv key len */
+ int encrypt; /* 1/0 enc/decr */
+ } u_cipher;
+ } opdata_u;
+ } PK11_SESSION;
+
+#define opdata_rsa_pub_key opdata_u.u_RSA.rsa_pub_key
+#define opdata_rsa_priv_key opdata_u.u_RSA.rsa_priv_key
+#define opdata_rsa_pub opdata_u.u_RSA.rsa_pub
+#define opdata_rsa_priv opdata_u.u_RSA.rsa_priv
+#define opdata_rsa_n_num opdata_u.u_RSA.rsa_n_num
+#define opdata_rsa_e_num opdata_u.u_RSA.rsa_e_num
+#define opdata_rsa_d_num opdata_u.u_RSA.rsa_d_num
+#define opdata_dsa_pub_key opdata_u.u_DSA.dsa_pub_key
+#define opdata_dsa_priv_key opdata_u.u_DSA.dsa_priv_key
+#define opdata_dsa_pub opdata_u.u_DSA.dsa_pub
+#define opdata_dsa_pub_num opdata_u.u_DSA.dsa_pub_num
+#define opdata_dsa_priv opdata_u.u_DSA.dsa_priv
+#define opdata_dsa_priv_num opdata_u.u_DSA.dsa_priv_num
+#define opdata_dh_key opdata_u.u_DH.dh_key
+#define opdata_dh opdata_u.u_DH.dh
+#define opdata_dh_priv_num opdata_u.u_DH.dh_priv_num
+#define opdata_cipher_key opdata_u.u_cipher.cipher_key
+#define opdata_key opdata_u.u_cipher.key
+#define opdata_key_len opdata_u.u_cipher.key_len
+#define opdata_encrypt opdata_u.u_cipher.encrypt
+
+/*
+ * We have 3 different groups of operation types:
+ * 1) asymmetric operations
+ * 2) random operations
+ * 3) symmetric and digest operations
+ *
+ * This division into groups stems from the fact that it's common that hardware
+ * providers may support operations from one group only. For example, hardware
+ * providers on UltraSPARC T2, n2rng(7d), ncp(7d), and n2cp(7d), each support
+ * only a single group of operations.
+ *
+ * For every group a different slot can be chosen. That means that we must have
+ * at least 3 different lists of cached PKCS#11 sessions since sessions from
+ * different groups may be initialized in different slots.
+ *
+ * To provide locking granularity in multithreaded environment, the groups are
+ * further splitted into types with each type having a separate session cache.
+ */
+typedef enum PK11_OPTYPE_ENUM
+ {
+ OP_RAND,
+ OP_RSA,
+ OP_DSA,
+ OP_DH,
+ OP_CIPHER,
+ OP_DIGEST,
+ OP_MAX
+ } PK11_OPTYPE;
+
+/*
+ * This structure contains the heads of the lists forming the object caches
+ * and locks associated with the lists.
+ */
+typedef struct PK11_st_CACHE
+ {
+ PK11_SESSION *head;
+ pthread_mutex_t *lock;
+ } PK11_CACHE;
+
+/* structure for tracking handles of asymmetric key objects */
+typedef struct PK11_active_st
+ {
+ CK_OBJECT_HANDLE h;
+ unsigned int refcnt;
+ struct PK11_active_st *prev;
+ struct PK11_active_st *next;
+ } PK11_active;
+
+extern pthread_mutex_t *find_lock[];
+extern PK11_active *active_list[];
+/*
+ * These variables are specific for the RSA keys by reference code. See
+ * hw_pk11_pub.c for explanation.
+ */
+extern char *passphrasedialog;
+extern CK_FLAGS pubkey_token_flags;
+
+#define LOCK_OBJSTORE(alg_type) \
+ (void) pthread_mutex_lock(find_lock[alg_type])
+#define UNLOCK_OBJSTORE(alg_type) \
+ (void) pthread_mutex_unlock(find_lock[alg_type])
+
+extern PK11_SESSION *pk11_get_session(PK11_OPTYPE optype);
+extern void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype);
+
+#ifndef OPENSSL_NO_RSA
+extern int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
+extern int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
+extern int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
+extern EVP_PKEY *pk11_load_privkey(ENGINE *e, const char *pubkey_file,
+ UI_METHOD *ui_method, void *callback_data);
+extern EVP_PKEY *pk11_load_pubkey(ENGINE *e, const char *pubkey_file,
+ UI_METHOD *ui_method, void *callback_data);
+extern RSA_METHOD *PK11_RSA(void);
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+extern int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
+extern int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
+extern int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
+extern DSA_METHOD *PK11_DSA(void);
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+extern int pk11_destroy_dh_key_objects(PK11_SESSION *session);
+extern int pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock);
+extern DH_METHOD *PK11_DH(void);
+#endif /* OPENSSL_NO_DH */
+
+extern CK_FUNCTION_LIST_PTR pFuncList;
+
+#endif /* HW_PK11_H */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11_err.c b/openssl0.9.8/engines/pkcs11/hw_pk11_err.c
new file mode 100644
index 0000000..70b4143
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11_err.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* crypto/engine/hw_pk11_err.c */
+/*
+ * This product includes software developed by the OpenSSL Project for
+ * use in the OpenSSL Toolkit (http://www.openssl.org/).
+ *
+ * This project also referenced hw_pkcs11-0.9.7b.patch written by
+ * Afchine Madjlessi.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * the documentation and/or other materials provided with the
+ * 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).
+ *
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include "hw_pk11_err.h"
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+static ERR_STRING_DATA pk11_str_functs[]=
+{
+{ ERR_PACK(0, PK11_F_INIT, 0), "PK11_INIT"},
+{ ERR_PACK(0, PK11_F_FINISH, 0), "PK11_FINISH"},
+{ ERR_PACK(0, PK11_F_DESTROY, 0), "PK11_DESTROY"},
+{ ERR_PACK(0, PK11_F_CTRL, 0), "PK11_CTRL"},
+{ ERR_PACK(0, PK11_F_RSA_INIT, 0), "PK11_RSA_INIT"},
+{ ERR_PACK(0, PK11_F_RSA_FINISH, 0), "PK11_RSA_FINISH"},
+{ ERR_PACK(0, PK11_F_GET_PUB_RSA_KEY, 0), "PK11_GET_PUB_RSA_KEY"},
+{ ERR_PACK(0, PK11_F_GET_PRIV_RSA_KEY, 0), "PK11_GET_PRIV_RSA_KEY"},
+{ ERR_PACK(0, PK11_F_RSA_GEN_KEY, 0), "PK11_RSA_GEN_KEY"},
+{ ERR_PACK(0, PK11_F_RSA_PUB_ENC, 0), "PK11_RSA_PUB_ENC"},
+{ ERR_PACK(0, PK11_F_RSA_PRIV_ENC, 0), "PK11_RSA_PRIV_ENC"},
+{ ERR_PACK(0, PK11_F_RSA_PUB_DEC, 0), "PK11_RSA_PUB_DEC"},
+{ ERR_PACK(0, PK11_F_RSA_PRIV_DEC, 0), "PK11_RSA_PRIV_DEC"},
+{ ERR_PACK(0, PK11_F_RSA_SIGN, 0), "PK11_RSA_SIGN"},
+{ ERR_PACK(0, PK11_F_RSA_VERIFY, 0), "PK11_RSA_VERIFY"},
+{ ERR_PACK(0, PK11_F_RAND_ADD, 0), "PK11_RAND_ADD"},
+{ ERR_PACK(0, PK11_F_RAND_BYTES, 0), "PK11_RAND_BYTES"},
+{ ERR_PACK(0, PK11_F_GET_SESSION, 0), "PK11_GET_SESSION"},
+{ ERR_PACK(0, PK11_F_FREE_SESSION, 0), "PK11_FREE_SESSION"},
+{ ERR_PACK(0, PK11_F_LOAD_PUBKEY, 0), "PK11_LOAD_PUBKEY"},
+{ ERR_PACK(0, PK11_F_LOAD_PRIVKEY, 0), "PK11_LOAD_PRIV_KEY"},
+{ ERR_PACK(0, PK11_F_RSA_PUB_ENC_LOW, 0), "PK11_RSA_PUB_ENC_LOW"},
+{ ERR_PACK(0, PK11_F_RSA_PRIV_ENC_LOW, 0), "PK11_RSA_PRIV_ENC_LOW"},
+{ ERR_PACK(0, PK11_F_RSA_PUB_DEC_LOW, 0), "PK11_RSA_PUB_DEC_LOW"},
+{ ERR_PACK(0, PK11_F_RSA_PRIV_DEC_LOW, 0), "PK11_RSA_PRIV_DEC_LOW"},
+{ ERR_PACK(0, PK11_F_DSA_SIGN, 0), "PK11_DSA_SIGN"},
+{ ERR_PACK(0, PK11_F_DSA_VERIFY, 0), "PK11_DSA_VERIFY"},
+{ ERR_PACK(0, PK11_F_DSA_INIT, 0), "PK11_DSA_INIT"},
+{ ERR_PACK(0, PK11_F_DSA_FINISH, 0), "PK11_DSA_FINISH"},
+{ ERR_PACK(0, PK11_F_GET_PUB_DSA_KEY, 0), "PK11_GET_PUB_DSA_KEY"},
+{ ERR_PACK(0, PK11_F_GET_PRIV_DSA_KEY, 0), "PK11_GET_PRIV_DSA_KEY"},
+{ ERR_PACK(0, PK11_F_DH_INIT, 0), "PK11_DH_INIT"},
+{ ERR_PACK(0, PK11_F_DH_FINISH, 0), "PK11_DH_FINISH"},
+{ ERR_PACK(0, PK11_F_MOD_EXP_DH, 0), "PK11_MOD_EXP_DH"},
+{ ERR_PACK(0, PK11_F_GET_DH_KEY, 0), "PK11_GET_DH_KEY"},
+{ ERR_PACK(0, PK11_F_FREE_ALL_SESSIONS, 0), "PK11_FREE_ALL_SESSIONS"},
+{ ERR_PACK(0, PK11_F_SETUP_SESSION, 0), "PK11_SETUP_SESSION"},
+{ ERR_PACK(0, PK11_F_DESTROY_OBJECT, 0), "PK11_DESTROY_OBJECT"},
+{ ERR_PACK(0, PK11_F_CIPHER_INIT, 0), "PK11_CIPHER_INIT"},
+{ ERR_PACK(0, PK11_F_CIPHER_DO_CIPHER, 0), "PK11_CIPHER_DO_CIPHER"},
+{ ERR_PACK(0, PK11_F_GET_CIPHER_KEY, 0), "PK11_GET_CIPHER_KEY"},
+{ ERR_PACK(0, PK11_F_DIGEST_INIT, 0), "PK11_DIGEST_INIT"},
+{ ERR_PACK(0, PK11_F_DIGEST_UPDATE, 0), "PK11_DIGEST_UPDATE"},
+{ ERR_PACK(0, PK11_F_DIGEST_FINAL, 0), "PK11_DIGEST_FINAL"},
+{ ERR_PACK(0, PK11_F_CHOOSE_SLOT, 0), "PK11_CHOOSE_SLOT"},
+{ ERR_PACK(0, PK11_F_CIPHER_FINAL, 0), "PK11_CIPHER_FINAL"},
+{ ERR_PACK(0, PK11_F_LIBRARY_INIT, 0), "PK11_LIBRARY_INIT"},
+{ ERR_PACK(0, PK11_F_LOAD, 0), "ENGINE_LOAD_PK11"},
+{ ERR_PACK(0, PK11_F_DH_GEN_KEY, 0), "PK11_DH_GEN_KEY"},
+{ ERR_PACK(0, PK11_F_DH_COMP_KEY, 0), "PK11_DH_COMP_KEY"},
+{ ERR_PACK(0, PK11_F_DIGEST_COPY, 0), "PK11_DIGEST_COPY"},
+{ ERR_PACK(0, PK11_F_CIPHER_CLEANUP, 0), "PK11_CIPHER_CLEANUP"},
+{ ERR_PACK(0, PK11_F_ACTIVE_ADD, 0), "PK11_ACTIVE_ADD"},
+{ ERR_PACK(0, PK11_F_ACTIVE_DELETE, 0), "PK11_ACTIVE_DELETE"},
+{ ERR_PACK(0, PK11_F_CHECK_HW_MECHANISMS, 0), "PK11_CHECK_HW_MECHANISMS"},
+{ ERR_PACK(0, PK11_F_INIT_SYMMETRIC, 0), "PK11_INIT_SYMMETRIC"},
+{ ERR_PACK(0, PK11_F_ADD_AES_CTR_NIDS, 0), "PK11_ADD_AES_CTR_NIDS"},
+{ ERR_PACK(0, PK11_F_INIT_ALL_LOCKS, 0), "PK11_INIT_ALL_LOCKS"},
+{ ERR_PACK(0, PK11_F_RETURN_SESSION, 0), "PK11_RETURN_SESSION"},
+{ ERR_PACK(0, PK11_F_GET_PIN, 0), "PK11_GET_PIN"},
+{ ERR_PACK(0, PK11_F_FIND_ONE_OBJECT, 0), "PK11_FIND_ONE_OBJECT"},
+{ ERR_PACK(0, PK11_F_CHECK_TOKEN_ATTRS, 0), "PK11_CHECK_TOKEN_ATTRS"},
+{ ERR_PACK(0, PK11_F_CACHE_PIN, 0), "PK11_CACHE_PIN"},
+{ ERR_PACK(0, PK11_F_MLOCK_PIN_IN_MEMORY, 0), "PK11_MLOCK_PIN_IN_MEMORY"},
+{ ERR_PACK(0, PK11_F_TOKEN_LOGIN, 0), "PK11_TOKEN_LOGIN"},
+{ ERR_PACK(0, PK11_F_TOKEN_RELOGIN, 0), "PK11_TOKEN_RELOGIN"},
+{ ERR_PACK(0, PK11_F_RUN_ASKPASS, 0), "PK11_F_RUN_ASKPASS"},
+{ 0, NULL}
+};
+
+static ERR_STRING_DATA pk11_str_reasons[]=
+{
+{ PK11_R_ALREADY_LOADED, "PKCS#11 DSO already loaded"},
+{ PK11_R_DSO_FAILURE, "unable to load PKCS#11 DSO"},
+{ PK11_R_NOT_LOADED, "PKCS#11 DSO not loaded"},
+{ PK11_R_PASSED_NULL_PARAMETER, "null parameter passed"},
+{ PK11_R_COMMAND_NOT_IMPLEMENTED, "command not implemented"},
+{ PK11_R_INITIALIZE, "C_Initialize failed"},
+{ PK11_R_FINALIZE, "C_Finalize failed"},
+{ PK11_R_GETINFO, "C_GetInfo faile"},
+{ PK11_R_GETSLOTLIST, "C_GetSlotList failed"},
+{ PK11_R_NO_MODULUS_OR_NO_EXPONENT, "no modulus or no exponent"},
+{ PK11_R_ATTRIBUT_SENSITIVE_OR_INVALID, "attr sensitive or invalid"},
+{ PK11_R_GETATTRIBUTVALUE, "C_GetAttributeValue failed"},
+{ PK11_R_NO_MODULUS, "no modulus"},
+{ PK11_R_NO_EXPONENT, "no exponent"},
+{ PK11_R_FINDOBJECTSINIT, "C_FindObjectsInit failed"},
+{ PK11_R_FINDOBJECTS, "C_FindObjects failed"},
+{ PK11_R_FINDOBJECTSFINAL, "C_FindObjectsFinal failed"},
+{ PK11_R_CREATEOBJECT, "C_CreateObject failed"},
+{ PK11_R_DESTROYOBJECT, "C_DestroyObject failed"},
+{ PK11_R_OPENSESSION, "C_OpenSession failed"},
+{ PK11_R_CLOSESESSION, "C_CloseSession failed"},
+{ PK11_R_ENCRYPTINIT, "C_EncryptInit failed"},
+{ PK11_R_ENCRYPT, "C_Encrypt failed"},
+{ PK11_R_SIGNINIT, "C_SignInit failed"},
+{ PK11_R_SIGN, "C_Sign failed"},
+{ PK11_R_DECRYPTINIT, "C_DecryptInit failed"},
+{ PK11_R_DECRYPT, "C_Decrypt failed"},
+{ PK11_R_VERIFYINIT, "C_VerifyRecover failed"},
+{ PK11_R_VERIFY, "C_Verify failed"},
+{ PK11_R_VERIFYRECOVERINIT, "C_VerifyRecoverInit failed"},
+{ PK11_R_VERIFYRECOVER, "C_VerifyRecover failed"},
+{ PK11_R_GEN_KEY, "C_GenerateKeyPair failed"},
+{ PK11_R_SEEDRANDOM, "C_SeedRandom failed"},
+{ PK11_R_GENERATERANDOM, "C_GenerateRandom failed"},
+{ PK11_R_INVALID_MESSAGE_LENGTH, "invalid message length"},
+{ PK11_R_UNKNOWN_ALGORITHM_TYPE, "unknown algorithm type"},
+{ PK11_R_UNKNOWN_ASN1_OBJECT_ID, "unknown asn1 onject id"},
+{ PK11_R_UNKNOWN_PADDING_TYPE, "unknown padding type"},
+{ PK11_R_PADDING_CHECK_FAILED, "padding check failed"},
+{ PK11_R_DIGEST_TOO_BIG, "digest too big"},
+{ PK11_R_MALLOC_FAILURE, "malloc failure"},
+{ PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED, "ctl command not implemented"},
+{ PK11_R_DATA_GREATER_THAN_MOD_LEN, "data is bigger than mod"},
+{ PK11_R_DATA_TOO_LARGE_FOR_MODULUS, "data is too larger for mod"},
+{ PK11_R_MISSING_KEY_COMPONENT, "a dsa component is missing"},
+{ PK11_R_INVALID_SIGNATURE_LENGTH, "invalid signature length"},
+{ PK11_R_INVALID_DSA_SIGNATURE_R, "missing r in dsa verify"},
+{ PK11_R_INVALID_DSA_SIGNATURE_S, "missing s in dsa verify"},
+{ PK11_R_INCONSISTENT_KEY, "inconsistent key type"},
+{ PK11_R_ENCRYPTUPDATE, "C_EncryptUpdate failed"},
+{ PK11_R_DECRYPTUPDATE, "C_DecryptUpdate failed"},
+{ PK11_R_DIGESTINIT, "C_DigestInit failed"},
+{ PK11_R_DIGESTUPDATE, "C_DigestUpdate failed"},
+{ PK11_R_DIGESTFINAL, "C_DigestFinal failed"},
+{ PK11_R_ENCRYPTFINAL, "C_EncryptFinal failed"},
+{ PK11_R_DECRYPTFINAL, "C_DecryptFinal failed"},
+{ PK11_R_NO_PRNG_SUPPORT, "Slot does not support PRNG"},
+{ PK11_R_GETTOKENINFO, "C_GetTokenInfo failed"},
+{ PK11_R_DERIVEKEY, "C_DeriveKey failed"},
+{ PK11_R_GET_OPERATION_STATE, "C_GetOperationState failed"},
+{ PK11_R_SET_OPERATION_STATE, "C_SetOperationState failed"},
+{ PK11_R_INVALID_HANDLE, "invalid PKCS#11 object handle"},
+{ PK11_R_KEY_OR_IV_LEN_PROBLEM, "IV or key length incorrect"},
+{ PK11_R_INVALID_OPERATION_TYPE, "invalid operation type"},
+{ PK11_R_ADD_NID_FAILED, "failed to add NID" },
+{ PK11_R_ATFORK_FAILED, "atfork failed" },
+{ PK11_R_TOKEN_LOGIN_FAILED, "C_Login failed on token" },
+{ PK11_R_MORE_THAN_ONE_OBJECT_FOUND, "more than one object found" },
+{ PK11_R_INVALID_PKCS11_URI, "pkcs11 URI provided is invalid" },
+{ PK11_R_COULD_NOT_READ_PIN, "could not read PIN from terminal" },
+{ PK11_R_PIN_NOT_READ_FROM_COMMAND, "PIN not read from external command" },
+{ PK11_R_COULD_NOT_OPEN_COMMAND, "could not popen dialog command" },
+{ PK11_R_PIPE_FAILED, "pipe failed" },
+{ PK11_R_BAD_PASSPHRASE_SPEC, "bad passphrasedialog specification" },
+{ PK11_R_TOKEN_NOT_INITIALIZED, "token not initialized" },
+{ PK11_R_TOKEN_PIN_NOT_SET, "token PIN required but not set" },
+{ PK11_R_TOKEN_PIN_NOT_PROVIDED, "token PIN required but not provided" },
+{ PK11_R_MISSING_OBJECT_LABEL, "missing mandatory 'object' keyword" },
+{ PK11_R_TOKEN_ATTRS_DO_NOT_MATCH, "token attrs provided do not match" },
+{ PK11_R_PRIV_KEY_NOT_FOUND, "private key not found in keystore" },
+{ PK11_R_NO_OBJECT_FOUND, "specified object not found" },
+{ PK11_R_PIN_CACHING_POLICY_INVALID, "PIN set but caching policy invalid" },
+{ PK11_R_SYSCONF_FAILED, "sysconf failed" },
+{ PK11_R_MMAP_FAILED, "mmap failed" },
+{ PK11_R_PRIV_PROC_LOCK_MEMORY_MISSING, "PROC_LOCK_MEMORY privilege missing" },
+{ PK11_R_MLOCK_FAILED, "mlock failed" },
+{ PK11_R_FORK_FAILED, "fork failed" },
+{ 0, NULL}
+};
+#endif /* OPENSSL_NO_ERR */
+
+static int pk11_lib_error_code = 0;
+static int pk11_error_init = 1;
+
+#ifdef PK11_ENGINE_LIB_NAME
+static ERR_STRING_DATA pk11_engine_lib_name[] =
+{
+{0, PK11_ENGINE_LIB_NAME},
+{0, NULL}
+};
+#endif
+
+static void
+ERR_load_pk11_strings(void)
+ {
+ if (pk11_lib_error_code == 0)
+ pk11_lib_error_code = ERR_get_next_error_library();
+
+ if (pk11_error_init)
+ {
+ pk11_error_init = 0;
+#ifndef OPENSSL_NO_ERR
+ ERR_load_strings(pk11_lib_error_code, pk11_str_functs);
+ ERR_load_strings(pk11_lib_error_code, pk11_str_reasons);
+#endif
+
+#ifdef PK11_ENGINE_LIB_NAME
+ pk11_engine_lib_name->error =
+ ERR_PACK(pk11_lib_error_code, 0, 0);
+ ERR_load_strings(0, pk11_engine_lib_name);
+#endif
+ }
+}
+
+static void
+ERR_unload_pk11_strings(void)
+ {
+ if (pk11_error_init == 0)
+ {
+#ifndef OPENSSL_NO_ERR
+ ERR_unload_strings(pk11_lib_error_code, pk11_str_functs);
+ ERR_unload_strings(pk11_lib_error_code, pk11_str_reasons);
+#endif
+
+#ifdef PK11_ENGINE_LIB_NAME
+ ERR_unload_strings(0, pk11_engine_lib_name);
+#endif
+
+ pk11_error_init = 1;
+ }
+}
+
+void
+ERR_pk11_error(int function, int reason, char *file, int line)
+{
+ if (pk11_lib_error_code == 0)
+ pk11_lib_error_code = ERR_get_next_error_library();
+ ERR_PUT_error(pk11_lib_error_code, function, reason, file, line);
+}
+
+void
+PK11err_add_data(int function, int reason, CK_RV rv)
+{
+ char tmp_buf[20];
+
+ PK11err(function, reason);
+ (void) snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
+ ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
+}
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11_err.h b/openssl0.9.8/engines/pkcs11/hw_pk11_err.h
new file mode 100644
index 0000000..391acd9
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11_err.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/*
+ * This product includes software developed by the OpenSSL Project for
+ * use in the OpenSSL Toolkit (http://www.openssl.org/).
+ *
+ * This project also referenced hw_pkcs11-0.9.7b.patch written by
+ * Afchine Madjlessi.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * the documentation and/or other materials provided with the
+ * 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).
+ *
+ */
+
+#ifndef HW_PK11_ERR_H
+#define HW_PK11_ERR_H
+
+void ERR_pk11_error(int function, int reason, char *file, int line);
+void PK11err_add_data(int function, int reason, CK_RV rv);
+#define PK11err(f, r) ERR_pk11_error((f), (r), __FILE__, __LINE__)
+
+/* Error codes for the PK11 functions. */
+
+/* Function codes. */
+
+#define PK11_F_INIT 100
+#define PK11_F_FINISH 101
+#define PK11_F_DESTROY 102
+#define PK11_F_CTRL 103
+#define PK11_F_RSA_INIT 104
+#define PK11_F_RSA_FINISH 105
+#define PK11_F_GET_PUB_RSA_KEY 106
+#define PK11_F_GET_PRIV_RSA_KEY 107
+#define PK11_F_RSA_GEN_KEY 108
+#define PK11_F_RSA_PUB_ENC 109
+#define PK11_F_RSA_PRIV_ENC 110
+#define PK11_F_RSA_PUB_DEC 111
+#define PK11_F_RSA_PRIV_DEC 112
+#define PK11_F_RSA_SIGN 113
+#define PK11_F_RSA_VERIFY 114
+#define PK11_F_RAND_ADD 115
+#define PK11_F_RAND_BYTES 116
+#define PK11_F_GET_SESSION 117
+#define PK11_F_FREE_SESSION 118
+#define PK11_F_LOAD_PUBKEY 119
+#define PK11_F_LOAD_PRIVKEY 120
+#define PK11_F_RSA_PUB_ENC_LOW 121
+#define PK11_F_RSA_PRIV_ENC_LOW 122
+#define PK11_F_RSA_PUB_DEC_LOW 123
+#define PK11_F_RSA_PRIV_DEC_LOW 124
+#define PK11_F_DSA_SIGN 125
+#define PK11_F_DSA_VERIFY 126
+#define PK11_F_DSA_INIT 127
+#define PK11_F_DSA_FINISH 128
+#define PK11_F_GET_PUB_DSA_KEY 129
+#define PK11_F_GET_PRIV_DSA_KEY 130
+#define PK11_F_DH_INIT 131
+#define PK11_F_DH_FINISH 132
+#define PK11_F_MOD_EXP_DH 133
+#define PK11_F_GET_DH_KEY 134
+#define PK11_F_FREE_ALL_SESSIONS 135
+#define PK11_F_SETUP_SESSION 136
+#define PK11_F_DESTROY_OBJECT 137
+#define PK11_F_CIPHER_INIT 138
+#define PK11_F_CIPHER_DO_CIPHER 139
+#define PK11_F_GET_CIPHER_KEY 140
+#define PK11_F_DIGEST_INIT 141
+#define PK11_F_DIGEST_UPDATE 142
+#define PK11_F_DIGEST_FINAL 143
+#define PK11_F_CHOOSE_SLOT 144
+#define PK11_F_CIPHER_FINAL 145
+#define PK11_F_LIBRARY_INIT 146
+#define PK11_F_LOAD 147
+#define PK11_F_DH_GEN_KEY 148
+#define PK11_F_DH_COMP_KEY 149
+#define PK11_F_DIGEST_COPY 150
+#define PK11_F_CIPHER_CLEANUP 151
+#define PK11_F_ACTIVE_ADD 152
+#define PK11_F_ACTIVE_DELETE 153
+#define PK11_F_CHECK_HW_MECHANISMS 154
+#define PK11_F_INIT_SYMMETRIC 155
+#define PK11_F_ADD_AES_CTR_NIDS 156
+#define PK11_F_INIT_ALL_LOCKS 157
+#define PK11_F_RETURN_SESSION 158
+#define PK11_F_GET_PIN 159
+#define PK11_F_FIND_ONE_OBJECT 160
+#define PK11_F_CHECK_TOKEN_ATTRS 161
+#define PK11_F_CACHE_PIN 162
+#define PK11_F_MLOCK_PIN_IN_MEMORY 163
+#define PK11_F_TOKEN_LOGIN 164
+#define PK11_F_TOKEN_RELOGIN 165
+#define PK11_F_RUN_ASKPASS 166
+
+/* Reason codes. */
+#define PK11_R_ALREADY_LOADED 100
+#define PK11_R_DSO_FAILURE 101
+#define PK11_R_NOT_LOADED 102
+#define PK11_R_PASSED_NULL_PARAMETER 103
+#define PK11_R_COMMAND_NOT_IMPLEMENTED 104
+#define PK11_R_INITIALIZE 105
+#define PK11_R_FINALIZE 106
+#define PK11_R_GETINFO 107
+#define PK11_R_GETSLOTLIST 108
+#define PK11_R_NO_MODULUS_OR_NO_EXPONENT 109
+#define PK11_R_ATTRIBUT_SENSITIVE_OR_INVALID 110
+#define PK11_R_GETATTRIBUTVALUE 111
+#define PK11_R_NO_MODULUS 112
+#define PK11_R_NO_EXPONENT 113
+#define PK11_R_FINDOBJECTSINIT 114
+#define PK11_R_FINDOBJECTS 115
+#define PK11_R_FINDOBJECTSFINAL 116
+#define PK11_R_CREATEOBJECT 118
+#define PK11_R_DESTROYOBJECT 119
+#define PK11_R_OPENSESSION 120
+#define PK11_R_CLOSESESSION 121
+#define PK11_R_ENCRYPTINIT 122
+#define PK11_R_ENCRYPT 123
+#define PK11_R_SIGNINIT 124
+#define PK11_R_SIGN 125
+#define PK11_R_DECRYPTINIT 126
+#define PK11_R_DECRYPT 127
+#define PK11_R_VERIFYINIT 128
+#define PK11_R_VERIFY 129
+#define PK11_R_VERIFYRECOVERINIT 130
+#define PK11_R_VERIFYRECOVER 131
+#define PK11_R_GEN_KEY 132
+#define PK11_R_SEEDRANDOM 133
+#define PK11_R_GENERATERANDOM 134
+#define PK11_R_INVALID_MESSAGE_LENGTH 135
+#define PK11_R_UNKNOWN_ALGORITHM_TYPE 136
+#define PK11_R_UNKNOWN_ASN1_OBJECT_ID 137
+#define PK11_R_UNKNOWN_PADDING_TYPE 138
+#define PK11_R_PADDING_CHECK_FAILED 139
+#define PK11_R_DIGEST_TOO_BIG 140
+#define PK11_R_MALLOC_FAILURE 141
+#define PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED 142
+#define PK11_R_DATA_GREATER_THAN_MOD_LEN 143
+#define PK11_R_DATA_TOO_LARGE_FOR_MODULUS 144
+#define PK11_R_MISSING_KEY_COMPONENT 145
+#define PK11_R_INVALID_SIGNATURE_LENGTH 146
+#define PK11_R_INVALID_DSA_SIGNATURE_R 147
+#define PK11_R_INVALID_DSA_SIGNATURE_S 148
+#define PK11_R_INCONSISTENT_KEY 149
+#define PK11_R_ENCRYPTUPDATE 150
+#define PK11_R_DECRYPTUPDATE 151
+#define PK11_R_DIGESTINIT 152
+#define PK11_R_DIGESTUPDATE 153
+#define PK11_R_DIGESTFINAL 154
+#define PK11_R_ENCRYPTFINAL 155
+#define PK11_R_DECRYPTFINAL 156
+#define PK11_R_NO_PRNG_SUPPORT 157
+#define PK11_R_GETTOKENINFO 158
+#define PK11_R_DERIVEKEY 159
+#define PK11_R_GET_OPERATION_STATE 160
+#define PK11_R_SET_OPERATION_STATE 161
+#define PK11_R_INVALID_HANDLE 162
+#define PK11_R_KEY_OR_IV_LEN_PROBLEM 163
+#define PK11_R_INVALID_OPERATION_TYPE 164
+#define PK11_R_ADD_NID_FAILED 165
+#define PK11_R_ATFORK_FAILED 166
+#define PK11_R_TOKEN_LOGIN_FAILED 167
+#define PK11_R_MORE_THAN_ONE_OBJECT_FOUND 168
+#define PK11_R_INVALID_PKCS11_URI 169
+#define PK11_R_COULD_NOT_READ_PIN 170
+#define PK11_R_COULD_NOT_OPEN_COMMAND 171
+#define PK11_R_PIPE_FAILED 172
+#define PK11_R_PIN_NOT_READ_FROM_COMMAND 173
+#define PK11_R_BAD_PASSPHRASE_SPEC 174
+#define PK11_R_TOKEN_NOT_INITIALIZED 175
+#define PK11_R_TOKEN_PIN_NOT_SET 176
+#define PK11_R_TOKEN_PIN_NOT_PROVIDED 177
+#define PK11_R_MISSING_OBJECT_LABEL 178
+#define PK11_R_TOKEN_ATTRS_DO_NOT_MATCH 179
+#define PK11_R_PRIV_KEY_NOT_FOUND 180
+#define PK11_R_NO_OBJECT_FOUND 181
+#define PK11_R_PIN_CACHING_POLICY_INVALID 182
+#define PK11_R_SYSCONF_FAILED 183
+#define PK11_R_MMAP_FAILED 183
+#define PK11_R_PRIV_PROC_LOCK_MEMORY_MISSING 184
+#define PK11_R_MLOCK_FAILED 185
+#define PK11_R_FORK_FAILED 186
+
+#endif /* HW_PK11_ERR_H */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11_pub.c b/openssl0.9.8/engines/pkcs11/hw_pk11_pub.c
new file mode 100644
index 0000000..41c93fd
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11_pub.c
@@ -0,0 +1,3236 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* crypto/engine/hw_pk11_pub.c */
+/*
+ * This product includes software developed by the OpenSSL Project for
+ * use in the OpenSSL Toolkit (http://www.openssl.org/).
+ *
+ * This project also referenced hw_pkcs11-0.9.7b.patch written by
+ * Afchine Madjlessi.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * the documentation and/or other materials provided with the
+ * 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).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <openssl/e_os2.h>
+#include <openssl/crypto.h>
+#include <openssl/engine.h>
+#include <openssl/dso.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif /* OPENSSL_NO_RSA */
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif /* OPENSSL_NO_DH */
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <cryptlib.h>
+#include <pthread.h>
+#include <libgen.h>
+
+#ifndef OPENSSL_NO_HW
+#ifndef OPENSSL_NO_HW_PK11
+
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include "hw_pk11.h"
+#include "hw_pk11_uri.h"
+
+static CK_BBOOL pk11_login_done = CK_FALSE;
+extern CK_SLOT_ID pubkey_SLOTID;
+
+/*
+ * During the reinitialization after a detected fork we will try to login to the
+ * token using the passphrasedialog keyword that we inherit from the parent.
+ */
+char *passphrasedialog;
+
+#ifndef OPENSSL_NO_RSA
+/* RSA stuff */
+static int pk11_RSA_public_encrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding);
+static int pk11_RSA_private_encrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding);
+static int pk11_RSA_public_decrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding);
+static int pk11_RSA_private_decrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding);
+static int pk11_RSA_init(RSA *rsa);
+static int pk11_RSA_finish(RSA *rsa);
+static int pk11_RSA_sign(int type, const unsigned char *m, unsigned int m_len,
+ unsigned char *sigret, unsigned int *siglen, const RSA *rsa);
+static int pk11_RSA_verify(int dtype, const unsigned char *m,
+ unsigned int m_len, unsigned char *sigbuf, unsigned int siglen,
+ const RSA *rsa);
+EVP_PKEY *pk11_load_privkey(ENGINE*, const char *privkey_id,
+ UI_METHOD *ui_method, void *callback_data);
+EVP_PKEY *pk11_load_pubkey(ENGINE*, const char *pubkey_id,
+ UI_METHOD *ui_method, void *callback_data);
+
+static int pk11_RSA_public_encrypt_low(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa);
+static int pk11_RSA_private_encrypt_low(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa);
+static int pk11_RSA_public_decrypt_low(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa);
+static int pk11_RSA_private_decrypt_low(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa);
+
+static CK_OBJECT_HANDLE pk11_get_public_rsa_key(RSA* rsa, PK11_SESSION *sp);
+static CK_OBJECT_HANDLE pk11_get_private_rsa_key(RSA* rsa, PK11_SESSION *sp);
+
+static int pk11_check_new_rsa_key_pub(PK11_SESSION *sp, const RSA *rsa);
+static int pk11_check_new_rsa_key_priv(PK11_SESSION *sp, const RSA *rsa);
+#endif
+
+/* DSA stuff */
+#ifndef OPENSSL_NO_DSA
+static int pk11_DSA_init(DSA *dsa);
+static int pk11_DSA_finish(DSA *dsa);
+static DSA_SIG *pk11_dsa_do_sign(const unsigned char *dgst, int dlen,
+ DSA *dsa);
+static int pk11_dsa_do_verify(const unsigned char *dgst, int dgst_len,
+ DSA_SIG *sig, DSA *dsa);
+
+static CK_OBJECT_HANDLE pk11_get_public_dsa_key(DSA* dsa, DSA **key_ptr,
+ BIGNUM **dsa_pub_num, CK_SESSION_HANDLE session);
+static CK_OBJECT_HANDLE pk11_get_private_dsa_key(DSA* dsa, DSA **key_ptr,
+ BIGNUM **dsa_priv_num, CK_SESSION_HANDLE session);
+
+static int check_new_dsa_key_pub(PK11_SESSION *sp, DSA *dsa);
+static int check_new_dsa_key_priv(PK11_SESSION *sp, DSA *dsa);
+#endif
+
+/* DH stuff */
+#ifndef OPENSSL_NO_DH
+static int pk11_DH_init(DH *dh);
+static int pk11_DH_finish(DH *dh);
+static int pk11_DH_generate_key(DH *dh);
+static int pk11_DH_compute_key(unsigned char *key,
+ const BIGNUM *pub_key, DH *dh);
+
+static CK_OBJECT_HANDLE pk11_get_dh_key(DH* dh, DH **key_ptr,
+ BIGNUM **priv_key, CK_SESSION_HANDLE session);
+
+static int check_new_dh_key(PK11_SESSION *sp, DH *dh);
+#endif
+
+static int find_one_object(PK11_OPTYPE op, CK_SESSION_HANDLE s,
+ CK_ATTRIBUTE_PTR ptempl, CK_ULONG nattr, CK_OBJECT_HANDLE_PTR pkey);
+static int init_template_value(BIGNUM *bn, CK_VOID_PTR *pValue,
+ CK_ULONG *ulValueLen);
+static void attr_to_BN(CK_ATTRIBUTE_PTR attr, CK_BYTE attr_data[], BIGNUM **bn);
+
+/* Read mode string to be used for fopen() */
+#if SOLARIS_OPENSSL
+static char *read_mode_flags = "rF";
+#else
+static char *read_mode_flags = "r";
+#endif
+
+/*
+ * Increment existing or create a new reference for an asymmetric key PKCS#11
+ * object handle in the active object list. If the operation fails, unlock (if
+ * locked), set error variable and jump to the specified label. We use this list
+ * so that we can track how many references to the PKCS#11 objects are used from
+ * all our sessions structures. If we are replacing an object reference in the
+ * session structure and the ref count for the reference being replaced gets to
+ * 0 we know that we can safely free the object itself via C_ObjectDestroy().
+ * See also TRY_OBJ_DESTROY.
+ */
+#define KEY_HANDLE_REFHOLD(key_handle, alg_type, unlock, var, label) \
+ { \
+ if (pk11_active_add(key_handle, alg_type) < 0) \
+ { \
+ var = CK_TRUE; \
+ if (unlock) \
+ UNLOCK_OBJSTORE(alg_type); \
+ goto label; \
+ } \
+ }
+
+/*
+ * Find active list entry according to object handle and return pointer to the
+ * entry otherwise return NULL.
+ *
+ * This function presumes it is called with lock protecting the active list
+ * held.
+ */
+static PK11_active *pk11_active_find(CK_OBJECT_HANDLE h, PK11_OPTYPE type)
+ {
+ PK11_active *entry;
+
+ for (entry = active_list[type]; entry != NULL; entry = entry->next)
+ if (entry->h == h)
+ return (entry);
+
+ return (NULL);
+ }
+
+/*
+ * Search for an entry in the active list using PKCS#11 object handle as a
+ * search key and return refcnt of the found/created entry or -1 in case of
+ * failure.
+ *
+ * This function presumes it is called with lock protecting the active list
+ * held.
+ */
+int
+pk11_active_add(CK_OBJECT_HANDLE h, PK11_OPTYPE type)
+ {
+ PK11_active *entry = NULL;
+
+ if (h == CK_INVALID_HANDLE)
+ {
+ PK11err(PK11_F_ACTIVE_ADD, PK11_R_INVALID_HANDLE);
+ return (-1);
+ }
+
+ /* search for entry in the active list */
+ if ((entry = pk11_active_find(h, type)) != NULL)
+ entry->refcnt++;
+ else
+ {
+ /* not found, create new entry and add it to the list */
+ entry = OPENSSL_malloc(sizeof (PK11_active));
+ if (entry == NULL)
+ {
+ PK11err(PK11_F_ACTIVE_ADD, PK11_R_MALLOC_FAILURE);
+ return (-1);
+ }
+ entry->h = h;
+ entry->refcnt = 1;
+ entry->prev = NULL;
+ entry->next = NULL;
+ /* connect the newly created entry to the list */
+ if (active_list[type] == NULL)
+ active_list[type] = entry;
+ else /* make the entry first in the list */
+ {
+ entry->next = active_list[type];
+ active_list[type]->prev = entry;
+ active_list[type] = entry;
+ }
+ }
+
+ return (entry->refcnt);
+ }
+
+/*
+ * Remove active list entry from the list and free it.
+ *
+ * This function presumes it is called with lock protecting the active list
+ * held.
+ */
+void
+pk11_active_remove(PK11_active *entry, PK11_OPTYPE type)
+ {
+ PK11_active *prev_entry;
+
+ /* remove the entry from the list and free it */
+ if ((prev_entry = entry->prev) != NULL)
+ {
+ prev_entry->next = entry->next;
+ if (entry->next != NULL)
+ entry->next->prev = prev_entry;
+ }
+ else
+ {
+ active_list[type] = entry->next;
+ /* we were the first but not the only one */
+ if (entry->next != NULL)
+ entry->next->prev = NULL;
+ }
+
+ /* sanitization */
+ entry->h = CK_INVALID_HANDLE;
+ entry->prev = NULL;
+ entry->next = NULL;
+ OPENSSL_free(entry);
+ }
+
+/* Free all entries from the active list. */
+void
+pk11_free_active_list(PK11_OPTYPE type)
+ {
+ PK11_active *entry;
+
+ /* only for asymmetric types since only they have C_Find* locks. */
+ switch (type)
+ {
+ case OP_RSA:
+ case OP_DSA:
+ case OP_DH:
+ break;
+ default:
+ return;
+ }
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(type);
+ while ((entry = active_list[type]) != NULL)
+ pk11_active_remove(entry, type);
+ UNLOCK_OBJSTORE(type);
+ }
+
+/*
+ * Search for active list entry associated with given PKCS#11 object handle,
+ * decrement its refcnt and if it drops to 0, disconnect the entry and free it.
+ *
+ * Return 1 if the PKCS#11 object associated with the entry has no references,
+ * return 0 if there is at least one reference, -1 on error.
+ *
+ * This function presumes it is called with lock protecting the active list
+ * held.
+ */
+int
+pk11_active_delete(CK_OBJECT_HANDLE h, PK11_OPTYPE type)
+ {
+ PK11_active *entry = NULL;
+
+ if ((entry = pk11_active_find(h, type)) == NULL)
+ {
+ PK11err(PK11_F_ACTIVE_DELETE, PK11_R_INVALID_HANDLE);
+ return (-1);
+ }
+
+ OPENSSL_assert(entry->refcnt > 0);
+ entry->refcnt--;
+ if (entry->refcnt == 0)
+ {
+ pk11_active_remove(entry, type);
+ return (1);
+ }
+
+ return (0);
+ }
+
+#ifndef OPENSSL_NO_RSA
+/* Our internal RSA_METHOD that we provide pointers to */
+static RSA_METHOD pk11_rsa =
+ {
+ "PKCS#11 RSA method",
+ pk11_RSA_public_encrypt, /* rsa_pub_encrypt */
+ pk11_RSA_public_decrypt, /* rsa_pub_decrypt */
+ pk11_RSA_private_encrypt, /* rsa_priv_encrypt */
+ pk11_RSA_private_decrypt, /* rsa_priv_decrypt */
+ NULL, /* rsa_mod_exp */
+ NULL, /* bn_mod_exp */
+ pk11_RSA_init, /* init */
+ pk11_RSA_finish, /* finish */
+ RSA_FLAG_SIGN_VER, /* flags */
+ NULL, /* app_data */
+ pk11_RSA_sign, /* rsa_sign */
+ pk11_RSA_verify /* rsa_verify */
+ };
+
+RSA_METHOD *
+PK11_RSA(void)
+ {
+ return (&pk11_rsa);
+ }
+#endif
+
+#ifndef OPENSSL_NO_DSA
+/* Our internal DSA_METHOD that we provide pointers to */
+static DSA_METHOD pk11_dsa =
+ {
+ "PKCS#11 DSA method",
+ pk11_dsa_do_sign, /* dsa_do_sign */
+ NULL, /* dsa_sign_setup */
+ pk11_dsa_do_verify, /* dsa_do_verify */
+ NULL, /* dsa_mod_exp */
+ NULL, /* bn_mod_exp */
+ pk11_DSA_init, /* init */
+ pk11_DSA_finish, /* finish */
+ 0, /* flags */
+ NULL /* app_data */
+ };
+
+DSA_METHOD *
+PK11_DSA(void)
+ {
+ return (&pk11_dsa);
+ }
+#endif
+
+#ifndef OPENSSL_NO_DH
+/*
+ * PKCS #11 V2.20, section 11.2 specifies that the number of bytes needed for
+ * output buffer may somewhat exceed the precise number of bytes needed, but
+ * should not exceed it by a large amount. That may be caused, for example, by
+ * rounding it up to multiple of X in the underlying bignum library. 8 should be
+ * enough.
+ */
+#define DH_BUF_RESERVE 8
+
+/* Our internal DH_METHOD that we provide pointers to */
+static DH_METHOD pk11_dh =
+ {
+ "PKCS#11 DH method",
+ pk11_DH_generate_key, /* generate_key */
+ pk11_DH_compute_key, /* compute_key */
+ NULL, /* bn_mod_exp */
+ pk11_DH_init, /* init */
+ pk11_DH_finish, /* finish */
+ 0, /* flags */
+ NULL, /* app_data */
+ NULL /* generate_params */
+ };
+
+DH_METHOD *
+PK11_DH(void)
+ {
+ return (&pk11_dh);
+ }
+#endif
+
+/* Size of an SSL signature: MD5+SHA1 */
+#define SSL_SIG_LENGTH 36
+
+/* Lengths of DSA data and signature */
+#define DSA_DATA_LEN 20
+#define DSA_SIGNATURE_LEN 40
+
+static CK_BBOOL pk11_true = CK_TRUE;
+static CK_BBOOL pk11_false = CK_FALSE;
+
+#ifndef OPENSSL_NO_RSA
+/*
+ * Similiar to OpenSSL to take advantage of the paddings. The goal is to
+ * support all paddings in this engine although PK11 library does not
+ * support all the paddings used in OpenSSL.
+ * The input errors should have been checked in the padding functions.
+ */
+static int pk11_RSA_public_encrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+ {
+ int i, num = 0, r = -1;
+ unsigned char *buf = NULL;
+
+ num = BN_num_bytes(rsa->n);
+ if ((buf = (unsigned char *)OPENSSL_malloc(num)) == NULL)
+ {
+ PK11err(PK11_F_RSA_PUB_ENC, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ switch (padding)
+ {
+ case RSA_PKCS1_PADDING:
+ i = RSA_padding_add_PKCS1_type_2(buf, num, from, flen);
+ break;
+#ifndef OPENSSL_NO_SHA
+ case RSA_PKCS1_OAEP_PADDING:
+ i = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0);
+ break;
+#endif
+ case RSA_SSLV23_PADDING:
+ i = RSA_padding_add_SSLv23(buf, num, from, flen);
+ break;
+ case RSA_NO_PADDING:
+ i = RSA_padding_add_none(buf, num, from, flen);
+ break;
+ default:
+ PK11err(PK11_F_RSA_PUB_ENC, PK11_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+ if (i <= 0) goto err;
+
+ /* PK11 functions are called here */
+ r = pk11_RSA_public_encrypt_low(num, buf, to, rsa);
+err:
+ if (buf != NULL)
+ {
+ OPENSSL_cleanse(buf, num);
+ OPENSSL_free(buf);
+ }
+ return (r);
+ }
+
+
+/*
+ * Similar to Openssl to take advantage of the paddings. The input errors
+ * should be catched in the padding functions
+ */
+static int pk11_RSA_private_encrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+ {
+ int i, num = 0, r = -1;
+ unsigned char *buf = NULL;
+
+ num = BN_num_bytes(rsa->n);
+ if ((buf = (unsigned char *)OPENSSL_malloc(num)) == NULL)
+ {
+ PK11err(PK11_F_RSA_PRIV_ENC, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ switch (padding)
+ {
+ case RSA_PKCS1_PADDING:
+ i = RSA_padding_add_PKCS1_type_1(buf, num, from, flen);
+ break;
+ case RSA_NO_PADDING:
+ i = RSA_padding_add_none(buf, num, from, flen);
+ break;
+ case RSA_SSLV23_PADDING:
+ default:
+ PK11err(PK11_F_RSA_PRIV_ENC, PK11_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+ if (i <= 0) goto err;
+
+ /* PK11 functions are called here */
+ r = pk11_RSA_private_encrypt_low(num, buf, to, rsa);
+err:
+ if (buf != NULL)
+ {
+ OPENSSL_cleanse(buf, num);
+ OPENSSL_free(buf);
+ }
+ return (r);
+ }
+
+/* Similar to OpenSSL code. Input errors are also checked here */
+static int pk11_RSA_private_decrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+ {
+ BIGNUM f;
+ int j, num = 0, r = -1;
+ unsigned char *p;
+ unsigned char *buf = NULL;
+
+ BN_init(&f);
+
+ num = BN_num_bytes(rsa->n);
+
+ if ((buf = (unsigned char *)OPENSSL_malloc(num)) == NULL)
+ {
+ PK11err(PK11_F_RSA_PRIV_DEC, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /*
+ * This check was for equality but PGP does evil things
+ * and chops off the top '0' bytes
+ */
+ if (flen > num)
+ {
+ PK11err(PK11_F_RSA_PRIV_DEC,
+ PK11_R_DATA_GREATER_THAN_MOD_LEN);
+ goto err;
+ }
+
+ /* make data into a big number */
+ if (BN_bin2bn(from, (int)flen, &f) == NULL)
+ goto err;
+
+ if (BN_ucmp(&f, rsa->n) >= 0)
+ {
+ PK11err(PK11_F_RSA_PRIV_DEC,
+ PK11_R_DATA_TOO_LARGE_FOR_MODULUS);
+ goto err;
+ }
+
+ /* PK11 functions are called here */
+ r = pk11_RSA_private_decrypt_low(flen, from, buf, rsa);
+
+ /*
+ * PK11 CKM_RSA_X_509 mechanism pads 0's at the beginning.
+ * Needs to skip these 0's paddings here.
+ */
+ for (j = 0; j < r; j++)
+ if (buf[j] != 0)
+ break;
+
+ p = buf + j;
+ j = r - j; /* j is only used with no-padding mode */
+
+ switch (padding)
+ {
+ case RSA_PKCS1_PADDING:
+ r = RSA_padding_check_PKCS1_type_2(to, num, p, j, num);
+ break;
+#ifndef OPENSSL_NO_SHA
+ case RSA_PKCS1_OAEP_PADDING:
+ r = RSA_padding_check_PKCS1_OAEP(to, num, p, j, num, NULL, 0);
+ break;
+#endif
+ case RSA_SSLV23_PADDING:
+ r = RSA_padding_check_SSLv23(to, num, p, j, num);
+ break;
+ case RSA_NO_PADDING:
+ r = RSA_padding_check_none(to, num, p, j, num);
+ break;
+ default:
+ PK11err(PK11_F_RSA_PRIV_DEC, PK11_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+ if (r < 0)
+ PK11err(PK11_F_RSA_PRIV_DEC, PK11_R_PADDING_CHECK_FAILED);
+
+err:
+ BN_clear_free(&f);
+ if (buf != NULL)
+ {
+ OPENSSL_cleanse(buf, num);
+ OPENSSL_free(buf);
+ }
+ return (r);
+ }
+
+/* Similar to OpenSSL code. Input errors are also checked here */
+static int pk11_RSA_public_decrypt(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+ {
+ BIGNUM f;
+ int i, num = 0, r = -1;
+ unsigned char *p;
+ unsigned char *buf = NULL;
+
+ BN_init(&f);
+ num = BN_num_bytes(rsa->n);
+ buf = (unsigned char *)OPENSSL_malloc(num);
+ if (buf == NULL)
+ {
+ PK11err(PK11_F_RSA_PUB_DEC, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /*
+ * This check was for equality but PGP does evil things
+ * and chops off the top '0' bytes
+ */
+ if (flen > num)
+ {
+ PK11err(PK11_F_RSA_PUB_DEC, PK11_R_DATA_GREATER_THAN_MOD_LEN);
+ goto err;
+ }
+
+ if (BN_bin2bn(from, flen, &f) == NULL)
+ goto err;
+
+ if (BN_ucmp(&f, rsa->n) >= 0)
+ {
+ PK11err(PK11_F_RSA_PUB_DEC,
+ PK11_R_DATA_TOO_LARGE_FOR_MODULUS);
+ goto err;
+ }
+
+ /* PK11 functions are called here */
+ r = pk11_RSA_public_decrypt_low(flen, from, buf, rsa);
+
+ /*
+ * PK11 CKM_RSA_X_509 mechanism pads 0's at the beginning.
+ * Needs to skip these 0's here
+ */
+ for (i = 0; i < r; i++)
+ if (buf[i] != 0)
+ break;
+
+ p = buf + i;
+ i = r - i; /* i is only used with no-padding mode */
+
+ switch (padding)
+ {
+ case RSA_PKCS1_PADDING:
+ r = RSA_padding_check_PKCS1_type_1(to, num, p, i, num);
+ break;
+ case RSA_NO_PADDING:
+ r = RSA_padding_check_none(to, num, p, i, num);
+ break;
+ default:
+ PK11err(PK11_F_RSA_PUB_DEC, PK11_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+ if (r < 0)
+ PK11err(PK11_F_RSA_PUB_DEC, PK11_R_PADDING_CHECK_FAILED);
+
+err:
+ BN_clear_free(&f);
+ if (buf != NULL)
+ {
+ OPENSSL_cleanse(buf, num);
+ OPENSSL_free(buf);
+ }
+ return (r);
+ }
+
+/*
+ * This function implements RSA public encryption using C_EncryptInit and
+ * C_Encrypt pk11 interfaces. Note that the CKM_RSA_X_509 is used here.
+ * The calling function allocated sufficient memory in "to" to store results.
+ */
+static int pk11_RSA_public_encrypt_low(int flen,
+ const unsigned char *from, unsigned char *to, RSA *rsa)
+ {
+ CK_ULONG bytes_encrypted = flen;
+ int retval = -1;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_X_509, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_pub_key = CK_INVALID_HANDLE;
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (-1);
+
+ (void) pk11_check_new_rsa_key_pub(sp, rsa);
+
+ h_pub_key = sp->opdata_rsa_pub_key;
+ if (h_pub_key == CK_INVALID_HANDLE)
+ h_pub_key = sp->opdata_rsa_pub_key =
+ pk11_get_public_rsa_key(rsa, sp);
+
+ if (h_pub_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_EncryptInit(sp->session, p_mech,
+ h_pub_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PUB_ENC_LOW,
+ PK11_R_ENCRYPTINIT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+
+ rv = pFuncList->C_Encrypt(sp->session,
+ (unsigned char *)from, flen, to, &bytes_encrypted);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PUB_ENC_LOW,
+ PK11_R_ENCRYPT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+ retval = bytes_encrypted;
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (retval);
+ }
+
+
+/*
+ * This function implements RSA private encryption using C_SignInit and
+ * C_Sign pk11 APIs. Note that CKM_RSA_X_509 is used here.
+ * The calling function allocated sufficient memory in "to" to store results.
+ */
+static int pk11_RSA_private_encrypt_low(int flen,
+ const unsigned char *from, unsigned char *to, RSA *rsa)
+ {
+ CK_ULONG ul_sig_len = flen;
+ int retval = -1;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_X_509, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_priv_key = CK_INVALID_HANDLE;
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (-1);
+
+ (void) pk11_check_new_rsa_key_priv(sp, rsa);
+
+ h_priv_key = sp->opdata_rsa_priv_key;
+ if (h_priv_key == CK_INVALID_HANDLE)
+ h_priv_key = sp->opdata_rsa_priv_key =
+ pk11_get_private_rsa_key(rsa, sp);
+
+ if (h_priv_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_SignInit(sp->session, p_mech,
+ h_priv_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PRIV_ENC_LOW,
+ PK11_R_SIGNINIT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+
+ rv = pFuncList->C_Sign(sp->session,
+ (unsigned char *)from, flen, to, &ul_sig_len);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PRIV_ENC_LOW, PK11_R_SIGN,
+ rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+
+ retval = ul_sig_len;
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (retval);
+ }
+
+
+/*
+ * This function implements RSA private decryption using C_DecryptInit and
+ * C_Decrypt pk11 APIs. Note that CKM_RSA_X_509 mechanism is used here.
+ * The calling function allocated sufficient memory in "to" to store results.
+ */
+static int pk11_RSA_private_decrypt_low(int flen,
+ const unsigned char *from, unsigned char *to, RSA *rsa)
+ {
+ CK_ULONG bytes_decrypted = flen;
+ int retval = -1;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_X_509, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_priv_key;
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (-1);
+
+ (void) pk11_check_new_rsa_key_priv(sp, rsa);
+
+ h_priv_key = sp->opdata_rsa_priv_key;
+ if (h_priv_key == CK_INVALID_HANDLE)
+ h_priv_key = sp->opdata_rsa_priv_key =
+ pk11_get_private_rsa_key(rsa, sp);
+
+ if (h_priv_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_DecryptInit(sp->session, p_mech,
+ h_priv_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PRIV_DEC_LOW,
+ PK11_R_DECRYPTINIT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+
+ rv = pFuncList->C_Decrypt(sp->session,
+ (unsigned char *)from, flen, to, &bytes_decrypted);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PRIV_DEC_LOW,
+ PK11_R_DECRYPT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+ retval = bytes_decrypted;
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (retval);
+ }
+
+
+/*
+ * This function implements RSA public decryption using C_VerifyRecoverInit
+ * and C_VerifyRecover pk11 APIs. Note that CKM_RSA_X_509 is used here.
+ * The calling function allocated sufficient memory in "to" to store results.
+ */
+static int pk11_RSA_public_decrypt_low(int flen,
+ const unsigned char *from, unsigned char *to, RSA *rsa)
+ {
+ CK_ULONG bytes_decrypted = flen;
+ int retval = -1;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_X_509, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_pub_key = CK_INVALID_HANDLE;
+ PK11_SESSION *sp;
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (-1);
+
+ (void) pk11_check_new_rsa_key_pub(sp, rsa);
+
+ h_pub_key = sp->opdata_rsa_pub_key;
+ if (h_pub_key == CK_INVALID_HANDLE)
+ h_pub_key = sp->opdata_rsa_pub_key =
+ pk11_get_public_rsa_key(rsa, sp);
+
+ if (h_pub_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_VerifyRecoverInit(sp->session,
+ p_mech, h_pub_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PUB_DEC_LOW,
+ PK11_R_VERIFYRECOVERINIT, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+
+ rv = pFuncList->C_VerifyRecover(sp->session,
+ (unsigned char *)from, flen, to, &bytes_decrypted);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_PUB_DEC_LOW,
+ PK11_R_VERIFYRECOVER, rv);
+ pk11_return_session(sp, OP_RSA);
+ return (-1);
+ }
+ retval = bytes_decrypted;
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (retval);
+ }
+
+static int pk11_RSA_init(RSA *rsa)
+ {
+ /*
+ * This flag in the RSA_METHOD enables the new rsa_sign,
+ * rsa_verify functions. See rsa.h for details.
+ */
+ rsa->flags |= RSA_FLAG_SIGN_VER;
+
+ return (1);
+ }
+
+static int pk11_RSA_finish(RSA *rsa)
+ {
+ /*
+ * Since we are overloading OpenSSL's native RSA_eay_finish() we need
+ * to do the same as in the original function, i.e. to free bignum
+ * structures.
+ */
+ if (rsa->_method_mod_n != NULL)
+ BN_MONT_CTX_free(rsa->_method_mod_n);
+ if (rsa->_method_mod_p != NULL)
+ BN_MONT_CTX_free(rsa->_method_mod_p);
+ if (rsa->_method_mod_q != NULL)
+ BN_MONT_CTX_free(rsa->_method_mod_q);
+
+ return (1);
+ }
+
+/*
+ * Standard engine interface function. Majority codes here are from
+ * rsa/rsa_sign.c. We replaced the decrypt function call by C_Sign of PKCS#11.
+ * See more details in rsa/rsa_sign.c
+ */
+static int pk11_RSA_sign(int type, const unsigned char *m, unsigned int m_len,
+ unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
+ {
+ X509_SIG sig;
+ ASN1_TYPE parameter;
+ int i, j;
+ unsigned char *p, *s = NULL;
+ X509_ALGOR algor;
+ ASN1_OCTET_STRING digest;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_PKCS, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_priv_key;
+ PK11_SESSION *sp = NULL;
+ int ret = 0;
+ unsigned long ulsiglen;
+
+ /* Encode the digest */
+ /* Special case: SSL signature, just check the length */
+ if (type == NID_md5_sha1)
+ {
+ if (m_len != SSL_SIG_LENGTH)
+ {
+ PK11err(PK11_F_RSA_SIGN,
+ PK11_R_INVALID_MESSAGE_LENGTH);
+ goto err;
+ }
+ i = SSL_SIG_LENGTH;
+ s = (unsigned char *)m;
+ }
+ else
+ {
+ sig.algor = &algor;
+ sig.algor->algorithm = OBJ_nid2obj(type);
+ if (sig.algor->algorithm == NULL)
+ {
+ PK11err(PK11_F_RSA_SIGN,
+ PK11_R_UNKNOWN_ALGORITHM_TYPE);
+ goto err;
+ }
+ if (sig.algor->algorithm->length == 0)
+ {
+ PK11err(PK11_F_RSA_SIGN,
+ PK11_R_UNKNOWN_ASN1_OBJECT_ID);
+ goto err;
+ }
+ parameter.type = V_ASN1_NULL;
+ parameter.value.ptr = NULL;
+ sig.algor->parameter = &parameter;
+
+ sig.digest = &digest;
+ sig.digest->data = (unsigned char *)m;
+ sig.digest->length = m_len;
+
+ i = i2d_X509_SIG(&sig, NULL);
+ }
+
+ j = RSA_size(rsa);
+ if ((i - RSA_PKCS1_PADDING) > j)
+ {
+ PK11err(PK11_F_RSA_SIGN, PK11_R_DIGEST_TOO_BIG);
+ goto err;
+ }
+
+ if (type != NID_md5_sha1)
+ {
+ s = (unsigned char *)OPENSSL_malloc((unsigned int)(j + 1));
+ if (s == NULL)
+ {
+ PK11err(PK11_F_RSA_SIGN, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p = s;
+ (void) i2d_X509_SIG(&sig, &p);
+ }
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ goto err;
+
+ (void) pk11_check_new_rsa_key_priv(sp, rsa);
+
+ h_priv_key = sp->opdata_rsa_priv_key;
+ if (h_priv_key == CK_INVALID_HANDLE)
+ h_priv_key = sp->opdata_rsa_priv_key =
+ pk11_get_private_rsa_key((RSA *)rsa, sp);
+
+ if (h_priv_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_SignInit(sp->session, p_mech, h_priv_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_SIGN, PK11_R_SIGNINIT, rv);
+ goto err;
+ }
+
+ ulsiglen = j;
+ rv = pFuncList->C_Sign(sp->session, s, i, sigret,
+ (CK_ULONG_PTR) &ulsiglen);
+ *siglen = ulsiglen;
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_SIGN, PK11_R_SIGN, rv);
+ goto err;
+ }
+ ret = 1;
+ }
+
+err:
+ if (type != NID_md5_sha1)
+ {
+ (void) memset(s, 0, (unsigned int)(j + 1));
+ OPENSSL_free(s);
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (ret);
+ }
+
+static int pk11_RSA_verify(int type, const unsigned char *m,
+ unsigned int m_len, unsigned char *sigbuf, unsigned int siglen,
+ const RSA *rsa)
+ {
+ X509_SIG sig;
+ ASN1_TYPE parameter;
+ int i, j;
+ unsigned char *p, *s = NULL;
+ X509_ALGOR algor;
+ ASN1_OCTET_STRING digest;
+ CK_RV rv;
+ CK_MECHANISM mech_rsa = {CKM_RSA_PKCS, NULL, 0};
+ CK_MECHANISM *p_mech = &mech_rsa;
+ CK_OBJECT_HANDLE h_pub_key;
+ PK11_SESSION *sp = NULL;
+ int ret = 0;
+
+ /* Encode the digest */
+ /* Special case: SSL signature, just check the length */
+ if (type == NID_md5_sha1)
+ {
+ if (m_len != SSL_SIG_LENGTH)
+ {
+ PK11err(PK11_F_RSA_VERIFY,
+ PK11_R_INVALID_MESSAGE_LENGTH);
+ goto err;
+ }
+ i = SSL_SIG_LENGTH;
+ s = (unsigned char *)m;
+ }
+ else
+ {
+ sig.algor = &algor;
+ sig.algor->algorithm = OBJ_nid2obj(type);
+ if (sig.algor->algorithm == NULL)
+ {
+ PK11err(PK11_F_RSA_VERIFY,
+ PK11_R_UNKNOWN_ALGORITHM_TYPE);
+ goto err;
+ }
+ if (sig.algor->algorithm->length == 0)
+ {
+ PK11err(PK11_F_RSA_VERIFY,
+ PK11_R_UNKNOWN_ASN1_OBJECT_ID);
+ goto err;
+ }
+ parameter.type = V_ASN1_NULL;
+ parameter.value.ptr = NULL;
+ sig.algor->parameter = &parameter;
+ sig.digest = &digest;
+ sig.digest->data = (unsigned char *)m;
+ sig.digest->length = m_len;
+ i = i2d_X509_SIG(&sig, NULL);
+ }
+
+ j = RSA_size(rsa);
+ if ((i - RSA_PKCS1_PADDING) > j)
+ {
+ PK11err(PK11_F_RSA_VERIFY, PK11_R_DIGEST_TOO_BIG);
+ goto err;
+ }
+
+ if (type != NID_md5_sha1)
+ {
+ s = (unsigned char *)OPENSSL_malloc((unsigned int)(j + 1));
+ if (s == NULL)
+ {
+ PK11err(PK11_F_RSA_VERIFY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p = s;
+ (void) i2d_X509_SIG(&sig, &p);
+ }
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ goto err;
+
+ (void) pk11_check_new_rsa_key_pub(sp, rsa);
+
+ h_pub_key = sp->opdata_rsa_pub_key;
+ if (h_pub_key == CK_INVALID_HANDLE)
+ h_pub_key = sp->opdata_rsa_pub_key =
+ pk11_get_public_rsa_key((RSA *)rsa, sp);
+
+ if (h_pub_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_VerifyInit(sp->session, p_mech,
+ h_pub_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_VERIFY, PK11_R_VERIFYINIT,
+ rv);
+ goto err;
+ }
+ rv = pFuncList->C_Verify(sp->session, s, i, sigbuf,
+ (CK_ULONG)siglen);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_RSA_VERIFY, PK11_R_VERIFY, rv);
+ goto err;
+ }
+ ret = 1;
+ }
+
+err:
+ if (type != NID_md5_sha1)
+ {
+ (void) memset(s, 0, (unsigned int)siglen);
+ OPENSSL_free(s);
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (ret);
+ }
+
+#define MAXATTR 1024
+/*
+ * Load RSA private key from a file or get its PKCS#11 handle if stored in the
+ * PKCS#11 token.
+ */
+/* ARGSUSED */
+EVP_PKEY *pk11_load_privkey(ENGINE* e, const char *privkey_id,
+ UI_METHOD *ui_method, void *callback_data)
+ {
+ EVP_PKEY *pkey = NULL;
+ FILE *privkey;
+ CK_OBJECT_HANDLE h_priv_key = CK_INVALID_HANDLE;
+ RSA *rsa = NULL;
+ PK11_SESSION *sp;
+ /* Anything else below is needed for the key by reference extension. */
+ const char *file;
+ int ret;
+ pkcs11_uri uri_struct;
+ CK_RV rv;
+ CK_BBOOL is_token = CK_TRUE;
+ CK_BBOOL rollback = CK_FALSE;
+ CK_BYTE attr_data[8][MAXATTR];
+ CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
+ CK_OBJECT_HANDLE ks_key = CK_INVALID_HANDLE; /* key in keystore */
+
+ /* We look for private keys only. */
+ CK_ATTRIBUTE search_templ[] =
+ {
+ {CKA_TOKEN, &is_token, sizeof (is_token)},
+ {CKA_CLASS, &key_class, sizeof (key_class)},
+ {CKA_LABEL, NULL, 0}
+ };
+
+ /*
+ * These public attributes are needed to initialize the OpenSSL RSA
+ * structure with something we can use to look up the key. Note that we
+ * never ask for private components.
+ */
+ CK_ATTRIBUTE get_templ[] =
+ {
+ {CKA_MODULUS, (void *)attr_data[0], MAXATTR}, /* n */
+ {CKA_PUBLIC_EXPONENT, (void *)attr_data[1], MAXATTR}, /* e */
+ };
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (NULL);
+
+ /*
+ * The next function will decide whether we are going to access keys in
+ * the token or read them from plain files. It all depends on what is in
+ * the 'privkey_id' parameter.
+ */
+ ret = pk11_process_pkcs11_uri(privkey_id, &uri_struct, &file);
+
+ if (ret == 0)
+ goto err;
+
+ /* We will try to access a key from a PKCS#11 token. */
+ if (ret == 1)
+ {
+ if (pk11_check_token_attrs(&uri_struct) == 0)
+ goto err;
+
+ search_templ[2].pValue = uri_struct.object;
+ search_templ[2].ulValueLen = strlen(search_templ[2].pValue);
+
+ if (pk11_token_login(sp->session, &pk11_login_done,
+ &uri_struct, CK_TRUE) == 0)
+ goto err;
+
+ /*
+ * Now let's try to find the key in the token. It is a failure
+ * if we can't find it.
+ */
+ if (find_one_object(OP_RSA, sp->session, search_templ, 3,
+ &ks_key) == 0)
+ goto err;
+
+ /*
+ * Free the structure now. Note that we use uri_struct's field
+ * directly in the template so we cannot free it until the find
+ * is done.
+ */
+ pk11_free_pkcs11_uri(&uri_struct, 0);
+
+ /*
+ * We might have a cache hit which we could confirm according to
+ * the 'n'/'e' params, RSA public pointer as NULL, and non-NULL
+ * RSA private pointer. However, it is easier just to recreate
+ * everything. We expect the keys to be loaded once and used
+ * many times. We do not check the return value because even in
+ * case of failure the sp structure will have both key pointer
+ * and object handle cleaned and pk11_destroy_object() reports
+ * the failure to the OpenSSL error message buffer.
+ */
+ (void) pk11_destroy_rsa_object_priv(sp, CK_TRUE);
+
+ sp->opdata_rsa_priv_key = ks_key;
+ /* This object shall not be deleted on a cache miss. */
+ sp->persistent = CK_TRUE;
+
+ if ((rsa = sp->opdata_rsa_priv = RSA_new_method(e)) == NULL)
+ goto err;
+
+ if ((rv = pFuncList->C_GetAttributeValue(sp->session, ks_key,
+ get_templ, 2)) != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_LOAD_PRIVKEY,
+ PK11_R_GETATTRIBUTVALUE, rv);
+ goto err;
+ }
+
+ /*
+ * Cache the RSA private structure pointer. We do not use it now
+ * for key-by-ref keys but let's do it for consistency reasons.
+ */
+ sp->opdata_rsa_priv = rsa;
+
+ /*
+ * We do not use pk11_get_private_rsa_key() here so we must take
+ * care of handle management ourselves.
+ */
+ KEY_HANDLE_REFHOLD(ks_key, OP_RSA, CK_FALSE, rollback, err);
+
+ /*
+ * Those are the sensitive components we do not want to export
+ * from the token at all: rsa->(d|p|q|dmp1|dmq1|iqmp).
+ */
+ attr_to_BN(&get_templ[0], attr_data[0], &rsa->n);
+ attr_to_BN(&get_templ[1], attr_data[1], &rsa->e);
+ /*
+ * Must have 'n'/'e' components in the session structure as
+ * well. They serve as a public look-up key for the private key
+ * in the keystore.
+ */
+ attr_to_BN(&get_templ[0], attr_data[0], &sp->opdata_rsa_n_num);
+ attr_to_BN(&get_templ[1], attr_data[1], &sp->opdata_rsa_e_num);
+
+ if ((pkey = EVP_PKEY_new()) == NULL)
+ goto err;
+
+ if (EVP_PKEY_set1_RSA(pkey, rsa) == 0)
+ goto err;
+ }
+ else
+ if ((privkey = fopen(file, read_mode_flags)) != NULL)
+ {
+ pkey = PEM_read_PrivateKey(privkey, NULL, NULL, NULL);
+ (void) fclose(privkey);
+ if (pkey != NULL)
+ {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa != NULL)
+ {
+ (void) pk11_check_new_rsa_key_priv(sp,
+ rsa);
+
+ h_priv_key = sp->opdata_rsa_priv_key =
+ pk11_get_private_rsa_key(rsa, sp);
+ if (h_priv_key == CK_INVALID_HANDLE)
+ goto err;
+ }
+ else
+ goto err;
+ }
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (pkey);
+err:
+ if (rsa != NULL)
+ RSA_free(rsa);
+ if (pkey != NULL)
+ {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ return (pkey);
+ }
+
+/* Load RSA public key from a file or load it from the PKCS#11 token. */
+/* ARGSUSED */
+EVP_PKEY *pk11_load_pubkey(ENGINE* e, const char *pubkey_id,
+ UI_METHOD *ui_method, void *callback_data)
+ {
+ EVP_PKEY *pkey = NULL;
+ FILE *pubkey;
+ CK_OBJECT_HANDLE h_pub_key = CK_INVALID_HANDLE;
+ RSA *rsa = NULL;
+ PK11_SESSION *sp;
+ /* everything else below needed for key by reference extension */
+ int ret;
+ const char *file;
+ pkcs11_uri uri_struct;
+ CK_RV rv;
+ CK_BBOOL is_token = CK_TRUE;
+ CK_BYTE attr_data[2][MAXATTR];
+ CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY;
+ CK_OBJECT_HANDLE ks_key = CK_INVALID_HANDLE; /* key in keystore */
+
+ CK_ATTRIBUTE search_templ[] =
+ {
+ {CKA_TOKEN, &is_token, sizeof (is_token)},
+ {CKA_CLASS, &key_class, sizeof (key_class)},
+ {CKA_LABEL, NULL, 0}
+ };
+
+ /*
+ * These public attributes are needed to initialize OpenSSL RSA
+ * structure with something we can use to look up the key.
+ */
+ CK_ATTRIBUTE get_templ[] =
+ {
+ {CKA_MODULUS, (void *)attr_data[0], MAXATTR}, /* n */
+ {CKA_PUBLIC_EXPONENT, (void *)attr_data[1], MAXATTR}, /* e */
+ };
+
+ if ((sp = pk11_get_session(OP_RSA)) == NULL)
+ return (NULL);
+
+ ret = pk11_process_pkcs11_uri(pubkey_id, &uri_struct, &file);
+
+ if (ret == 0)
+ goto err;
+
+ if (ret == 1)
+ {
+ if (pk11_check_token_attrs(&uri_struct) == 0)
+ goto err;
+
+ search_templ[2].pValue = uri_struct.object;
+ search_templ[2].ulValueLen = strlen(search_templ[2].pValue);
+
+ if (pk11_token_login(sp->session, &pk11_login_done,
+ &uri_struct, CK_FALSE) == 0)
+ goto err;
+
+ if (find_one_object(OP_RSA, sp->session, search_templ, 3,
+ &ks_key) == 0)
+ {
+ goto err;
+ }
+
+ /*
+ * Free the structure now. Note that we use uri_struct's field
+ * directly in the template so we can't free until find is done.
+ */
+ pk11_free_pkcs11_uri(&uri_struct, 0);
+ /*
+ * We load a new public key so we will create a new RSA
+ * structure. No cache hit is possible.
+ */
+ (void) pk11_destroy_rsa_object_pub(sp, CK_TRUE);
+ sp->opdata_rsa_pub_key = ks_key;
+
+ if ((rsa = sp->opdata_rsa_pub = RSA_new_method(e)) == NULL)
+ goto err;
+
+ if ((rv = pFuncList->C_GetAttributeValue(sp->session, ks_key,
+ get_templ, 2)) != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_LOAD_PUBKEY,
+ PK11_R_GETATTRIBUTVALUE, rv);
+ goto err;
+ }
+
+ /*
+ * Cache the RSA public structure pointer.
+ */
+ sp->opdata_rsa_pub = rsa;
+
+ /*
+ * These are the sensitive components we do not want to export
+ * from the token at all: rsa->(d|p|q|dmp1|dmq1|iqmp).
+ */
+ attr_to_BN(&get_templ[0], attr_data[0], &rsa->n);
+ attr_to_BN(&get_templ[1], attr_data[1], &rsa->e);
+
+ if ((pkey = EVP_PKEY_new()) == NULL)
+ goto err;
+
+ if (EVP_PKEY_set1_RSA(pkey, rsa) == 0)
+ goto err;
+
+ /*
+ * Create a session object from it so that when calling
+ * pk11_get_public_rsa_key() the next time, we can find it. The
+ * reason why we do that is that we cannot tell from the RSA
+ * structure (OpenSSL RSA structure does not have any room for
+ * additional data used by the engine, for example) if it bears
+ * a public key stored in the keystore or not so it's better if
+ * we always have a session key. Note that this is different
+ * from what we do for the private keystore objects but in that
+ * case, we can tell from the RSA structure that the keystore
+ * object is in play - the 'd' component is NULL in that case.
+ */
+ h_pub_key = sp->opdata_rsa_pub_key =
+ pk11_get_public_rsa_key(rsa, sp);
+ if (h_pub_key == CK_INVALID_HANDLE)
+ goto err;
+ }
+ else
+ if ((pubkey = fopen(file, read_mode_flags)) != NULL)
+ {
+ pkey = PEM_read_PUBKEY(pubkey, NULL, NULL, NULL);
+ (void) fclose(pubkey);
+ if (pkey != NULL)
+ {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa != NULL)
+ {
+ /*
+ * This will always destroy the RSA
+ * object since we have a new RSA
+ * structure here.
+ */
+ (void) pk11_check_new_rsa_key_pub(sp,
+ rsa);
+
+ h_pub_key = sp->opdata_rsa_pub_key =
+ pk11_get_public_rsa_key(rsa, sp);
+ if (h_pub_key == CK_INVALID_HANDLE)
+ {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ }
+ else
+ {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ }
+ }
+
+ pk11_return_session(sp, OP_RSA);
+ return (pkey);
+err:
+ if (rsa != NULL)
+ RSA_free(rsa);
+ if (pkey != NULL)
+ {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ return (pkey);
+ }
+
+/*
+ * Get a public key object in a session from a given rsa structure. If the
+ * PKCS#11 session object already exists it is found, reused, and
+ * the counter in the active object list incremented. If not found, a new
+ * session object is created and put also onto the active object list.
+ *
+ * We use the session field from sp, and we cache rsa->(n|e) in
+ * opdata_rsa_(n|e|d)_num, respectively.
+ */
+static CK_OBJECT_HANDLE
+pk11_get_public_rsa_key(RSA* rsa, PK11_SESSION *sp)
+ {
+ CK_RV rv;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ CK_ULONG found;
+ CK_OBJECT_CLASS o_key = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE k_type = CKK_RSA;
+ CK_ULONG ul_key_attr_count = 7;
+ CK_BBOOL rollback = CK_FALSE;
+
+ CK_ATTRIBUTE a_key_template[] =
+ {
+ {CKA_CLASS, (void *) NULL, sizeof (CK_OBJECT_CLASS)},
+ {CKA_KEY_TYPE, (void *) NULL, sizeof (CK_KEY_TYPE)},
+ {CKA_TOKEN, &pk11_false, sizeof (pk11_false)},
+ {CKA_ENCRYPT, &pk11_true, sizeof (pk11_true)},
+ {CKA_VERIFY_RECOVER, &pk11_true, sizeof (pk11_true)},
+ {CKA_MODULUS, (void *)NULL, 0},
+ {CKA_PUBLIC_EXPONENT, (void *)NULL, 0}
+ };
+
+ int i;
+
+ a_key_template[0].pValue = &o_key;
+ a_key_template[1].pValue = &k_type;
+
+ a_key_template[5].ulValueLen = BN_num_bytes(rsa->n);
+ a_key_template[5].pValue = (CK_VOID_PTR)OPENSSL_malloc(
+ (size_t)a_key_template[5].ulValueLen);
+ if (a_key_template[5].pValue == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ BN_bn2bin(rsa->n, a_key_template[5].pValue);
+
+ a_key_template[6].ulValueLen = BN_num_bytes(rsa->e);
+ a_key_template[6].pValue = (CK_VOID_PTR)OPENSSL_malloc(
+ (size_t)a_key_template[6].ulValueLen);
+ if (a_key_template[6].pValue == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ BN_bn2bin(rsa->e, a_key_template[6].pValue);
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(OP_RSA);
+
+ rv = pFuncList->C_FindObjectsInit(sp->session, a_key_template,
+ ul_key_attr_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_RSA_KEY,
+ PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(sp->session, &h_key, 1, &found);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_RSA_KEY,
+ PK11_R_FINDOBJECTS, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjectsFinal(sp->session);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_RSA_KEY,
+ PK11_R_FINDOBJECTSFINAL, rv);
+ goto err;
+ }
+
+ if (found == 0)
+ {
+ rv = pFuncList->C_CreateObject(sp->session,
+ a_key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_RSA_KEY,
+ PK11_R_CREATEOBJECT, rv);
+ goto err;
+ }
+ }
+
+ if ((sp->opdata_rsa_n_num = BN_dup(rsa->n)) == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ if ((sp->opdata_rsa_e_num = BN_dup(rsa->e)) == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ BN_free(sp->opdata_rsa_n_num);
+ sp->opdata_rsa_n_num = NULL;
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ /* LINTED: E_CONSTANT_CONDITION */
+ KEY_HANDLE_REFHOLD(h_key, OP_RSA, CK_FALSE, rollback, err);
+ sp->opdata_rsa_pub = rsa;
+
+err:
+ if (rollback)
+ {
+ /*
+ * We do not care about the return value from C_DestroyObject()
+ * since we are doing rollback.
+ */
+ if (found == 0)
+ (void) pFuncList->C_DestroyObject(sp->session, h_key);
+ h_key = CK_INVALID_HANDLE;
+ }
+
+ UNLOCK_OBJSTORE(OP_RSA);
+
+malloc_err:
+ for (i = 5; i <= 6; i++)
+ {
+ if (a_key_template[i].pValue != NULL)
+ {
+ OPENSSL_free(a_key_template[i].pValue);
+ a_key_template[i].pValue = NULL;
+ }
+ }
+
+ return (h_key);
+ }
+
+/*
+ * Function similar to pk11_get_public_rsa_key(). In addition to 'n' and 'e'
+ * components, it also caches 'd' if present. Note that if RSA keys by reference
+ * are used, 'd' is never extracted from the token in which case it would be
+ * NULL here.
+ */
+static CK_OBJECT_HANDLE
+pk11_get_private_rsa_key(RSA* rsa, PK11_SESSION *sp)
+ {
+ CK_RV rv;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ int i;
+ CK_ULONG found;
+ CK_OBJECT_CLASS o_key = CKO_PRIVATE_KEY;
+ CK_KEY_TYPE k_type = CKK_RSA;
+ CK_ULONG ul_key_attr_count = 14;
+ CK_BBOOL rollback = CK_FALSE;
+
+ /*
+ * Both CKA_TOKEN and CKA_SENSITIVE have to be CK_FALSE for session keys
+ */
+ CK_ATTRIBUTE a_key_template[] =
+ {
+ {CKA_CLASS, (void *) NULL, sizeof (CK_OBJECT_CLASS)},
+ {CKA_KEY_TYPE, (void *) NULL, sizeof (CK_KEY_TYPE)},
+ {CKA_TOKEN, &pk11_false, sizeof (pk11_false)},
+ {CKA_SENSITIVE, &pk11_false, sizeof (pk11_false)},
+ {CKA_DECRYPT, &pk11_true, sizeof (pk11_true)},
+ {CKA_SIGN, &pk11_true, sizeof (pk11_true)},
+ {CKA_MODULUS, (void *)NULL, 0},
+ {CKA_PUBLIC_EXPONENT, (void *)NULL, 0},
+ {CKA_PRIVATE_EXPONENT, (void *)NULL, 0},
+ {CKA_PRIME_1, (void *)NULL, 0},
+ {CKA_PRIME_2, (void *)NULL, 0},
+ {CKA_EXPONENT_1, (void *)NULL, 0},
+ {CKA_EXPONENT_2, (void *)NULL, 0},
+ {CKA_COEFFICIENT, (void *)NULL, 0},
+ };
+
+ a_key_template[0].pValue = &o_key;
+ a_key_template[1].pValue = &k_type;
+
+ /* Put the private key components into the template */
+ if (init_template_value(rsa->n, &a_key_template[6].pValue,
+ &a_key_template[6].ulValueLen) == 0 ||
+ init_template_value(rsa->e, &a_key_template[7].pValue,
+ &a_key_template[7].ulValueLen) == 0 ||
+ init_template_value(rsa->d, &a_key_template[8].pValue,
+ &a_key_template[8].ulValueLen) == 0 ||
+ init_template_value(rsa->p, &a_key_template[9].pValue,
+ &a_key_template[9].ulValueLen) == 0 ||
+ init_template_value(rsa->q, &a_key_template[10].pValue,
+ &a_key_template[10].ulValueLen) == 0 ||
+ init_template_value(rsa->dmp1, &a_key_template[11].pValue,
+ &a_key_template[11].ulValueLen) == 0 ||
+ init_template_value(rsa->dmq1, &a_key_template[12].pValue,
+ &a_key_template[12].ulValueLen) == 0 ||
+ init_template_value(rsa->iqmp, &a_key_template[13].pValue,
+ &a_key_template[13].ulValueLen) == 0)
+ {
+ PK11err(PK11_F_GET_PRIV_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(OP_RSA);
+
+ /*
+ * We are getting the private key but the private 'd' component is NULL.
+ * That means this is key by reference RSA key. In that case, we can
+ * use only public components for searching for the private key handle.
+ */
+ if (rsa->d == NULL)
+ {
+ ul_key_attr_count = 8;
+ /*
+ * We will perform the search in the token, not in the existing
+ * session keys.
+ */
+ a_key_template[2].pValue = &pk11_true;
+ }
+
+ rv = pFuncList->C_FindObjectsInit(sp->session, a_key_template,
+ ul_key_attr_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_RSA_KEY,
+ PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(sp->session, &h_key, 1, &found);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_RSA_KEY,
+ PK11_R_FINDOBJECTS, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjectsFinal(sp->session);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_RSA_KEY,
+ PK11_R_FINDOBJECTSFINAL, rv);
+ goto err;
+ }
+
+ if (found == 0)
+ {
+ /*
+ * We have an RSA structure with 'n'/'e' components only so we
+ * tried to find the private key in the keystore. If it was
+ * really a token key we have a problem. Note that for other key
+ * types we just create a new session key using the private
+ * components from the RSA structure.
+ */
+ if (rsa->d == NULL)
+ {
+ PK11err(PK11_F_GET_PRIV_RSA_KEY,
+ PK11_R_PRIV_KEY_NOT_FOUND);
+ goto err;
+ }
+
+ rv = pFuncList->C_CreateObject(sp->session,
+ a_key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_RSA_KEY,
+ PK11_R_CREATEOBJECT, rv);
+ goto err;
+ }
+ }
+
+ /*
+ * When RSA keys by reference code is used, we never extract private
+ * components from the keystore. In that case 'd' was set to NULL and we
+ * expect the application to properly cope with that. It is documented
+ * in openssl(5). In general, if keys by reference are used we expect it
+ * to be used exclusively using the high level API and then there is no
+ * problem. If the application expects the private components to be read
+ * from the keystore then that is not a supported way of usage.
+ */
+ if (rsa->d != NULL && (sp->opdata_rsa_d_num = BN_dup(rsa->d)) == NULL)
+ {
+ PK11err(PK11_F_GET_PRIV_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ rollback = CK_TRUE;
+ goto err;
+ }
+ else
+ sp->opdata_rsa_d_num = NULL;
+
+ /*
+ * For the key by reference code, we need public components as well
+ * since 'd' component is always NULL. For that reason, we always cache
+ * 'n'/'e' components as well.
+ */
+ if ((sp->opdata_rsa_n_num = BN_dup(rsa->n)) == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ sp->opdata_rsa_n_num = NULL;
+ rollback = CK_TRUE;
+ goto err;
+ }
+ if ((sp->opdata_rsa_e_num = BN_dup(rsa->e)) == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_RSA_KEY, PK11_R_MALLOC_FAILURE);
+ BN_free(sp->opdata_rsa_n_num);
+ sp->opdata_rsa_n_num = NULL;
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ /* LINTED: E_CONSTANT_CONDITION */
+ KEY_HANDLE_REFHOLD(h_key, OP_RSA, CK_FALSE, rollback, err);
+ sp->opdata_rsa_priv = rsa;
+
+err:
+ if (rollback)
+ {
+ /*
+ * We do not care about the return value from C_DestroyObject()
+ * since we are doing rollback.
+ */
+ if (found == 0)
+ (void) pFuncList->C_DestroyObject(sp->session, h_key);
+ h_key = CK_INVALID_HANDLE;
+ }
+
+ UNLOCK_OBJSTORE(OP_RSA);
+
+malloc_err:
+ /*
+ * 6 to 13 entries in the key template are key components.
+ * They need to be freed upon exit or error.
+ */
+ for (i = 6; i <= 13; i++)
+ {
+ if (a_key_template[i].pValue != NULL)
+ {
+ (void) memset(a_key_template[i].pValue, 0,
+ a_key_template[i].ulValueLen);
+ OPENSSL_free(a_key_template[i].pValue);
+ a_key_template[i].pValue = NULL;
+ }
+ }
+
+ return (h_key);
+ }
+
+/*
+ * Check for cache miss. Objects are cleaned only if we have a full cache miss,
+ * meaning that it's a different RSA key pair. Return 1 for cache hit, 0 for
+ * cache miss.
+ */
+static int
+pk11_check_new_rsa_key_pub(PK11_SESSION *sp, const RSA *rsa)
+ {
+ /*
+ * Provide protection against RSA structure reuse by making the
+ * check for cache hit stronger. Only public components of RSA
+ * key matter here so it is sufficient to compare them with values
+ * cached in PK11_SESSION structure.
+ *
+ * We must check the handle as well since with key by reference, public
+ * components 'n'/'e' are cached in private keys as well. That means we
+ * could have a cache hit in a private key when looking for a public
+ * key. That would not work, you cannot have one PKCS#11 object for
+ * both data signing and verifying.
+ */
+ if (sp->opdata_rsa_pub == rsa &&
+ BN_cmp(sp->opdata_rsa_n_num, rsa->n) == 0 &&
+ BN_cmp(sp->opdata_rsa_e_num, rsa->e) == 0)
+ {
+ if (sp->opdata_rsa_pub_key != CK_INVALID_HANDLE)
+ return (1);
+ else
+ /*
+ * No public key object yet but we have the right RSA
+ * structure with potentially existing private key
+ * object. We can just create a public object and move
+ * on with this session structure.
+ */
+ return (0);
+ }
+
+ /*
+ * A different RSA key pair was using this session structure previously
+ * or it's an empty structure. Destroy what we can.
+ */
+ (void) pk11_destroy_rsa_object_pub(sp, CK_TRUE);
+ (void) pk11_destroy_rsa_object_priv(sp, CK_TRUE);
+ return (0);
+ }
+
+/*
+ * Check for cache miss. Objects are cleaned only if we have a full cache miss,
+ * meaning that it's a different RSA key pair. Return 1 for cache hit, 0 for
+ * cache miss.
+ */
+static int
+pk11_check_new_rsa_key_priv(PK11_SESSION *sp, const RSA *rsa)
+ {
+ /*
+ * Provide protection against RSA structure reuse by making the
+ * check for cache hit stronger. Comparing public exponent of RSA
+ * key with value cached in PK11_SESSION structure should
+ * be sufficient. Note that we want to compare the public component
+ * since with the keys by reference mechanism, private components are
+ * not in the RSA structure. Also, see pk11_check_new_rsa_key_pub()
+ * about why we compare the handle as well.
+ */
+ if (sp->opdata_rsa_priv == rsa &&
+ BN_cmp(sp->opdata_rsa_n_num, rsa->n) == 0 &&
+ BN_cmp(sp->opdata_rsa_e_num, rsa->e) == 0)
+ {
+ if (sp->opdata_rsa_priv_key != CK_INVALID_HANDLE)
+ return (1);
+ else
+ /*
+ * No private key object yet but we have the right RSA
+ * structure with potentially existing public key
+ * object. We can just create a private object and move
+ * on with this session structure.
+ */
+ return (0);
+ }
+
+ /*
+ * A different RSA key pair was using this session structure previously
+ * or it's an empty structure. Destroy what we can.
+ */
+ (void) pk11_destroy_rsa_object_priv(sp, CK_TRUE);
+ (void) pk11_destroy_rsa_object_pub(sp, CK_TRUE);
+ return (0);
+ }
+#endif
+
+#ifndef OPENSSL_NO_DSA
+/* The DSA function implementation */
+/* ARGSUSED */
+static int pk11_DSA_init(DSA *dsa)
+ {
+ return (1);
+ }
+
+/* ARGSUSED */
+static int pk11_DSA_finish(DSA *dsa)
+ {
+ return (1);
+ }
+
+
+static DSA_SIG *
+pk11_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
+ {
+ BIGNUM *r = NULL, *s = NULL;
+ int i;
+ DSA_SIG *dsa_sig = NULL;
+
+ CK_RV rv;
+ CK_MECHANISM Mechanism_dsa = {CKM_DSA, NULL, 0};
+ CK_MECHANISM *p_mech = &Mechanism_dsa;
+ CK_OBJECT_HANDLE h_priv_key;
+
+ /*
+ * The signature is the concatenation of r and s,
+ * each is 20 bytes long
+ */
+ unsigned char sigret[DSA_SIGNATURE_LEN];
+ unsigned long siglen = DSA_SIGNATURE_LEN;
+ unsigned int siglen2 = DSA_SIGNATURE_LEN / 2;
+
+ PK11_SESSION *sp = NULL;
+
+ if ((dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_MISSING_KEY_COMPONENT);
+ goto ret;
+ }
+
+ i = BN_num_bytes(dsa->q); /* should be 20 */
+ if (dlen > i)
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_INVALID_SIGNATURE_LENGTH);
+ goto ret;
+ }
+
+ if ((sp = pk11_get_session(OP_DSA)) == NULL)
+ goto ret;
+
+ (void) check_new_dsa_key_priv(sp, dsa);
+
+ h_priv_key = sp->opdata_dsa_priv_key;
+ if (h_priv_key == CK_INVALID_HANDLE)
+ h_priv_key = sp->opdata_dsa_priv_key =
+ pk11_get_private_dsa_key((DSA *)dsa,
+ &sp->opdata_dsa_priv,
+ &sp->opdata_dsa_priv_num, sp->session);
+
+ if (h_priv_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_SignInit(sp->session, p_mech, h_priv_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DSA_SIGN, PK11_R_SIGNINIT, rv);
+ goto ret;
+ }
+
+ (void) memset(sigret, 0, siglen);
+ rv = pFuncList->C_Sign(sp->session,
+ (unsigned char *) dgst, dlen, sigret,
+ (CK_ULONG_PTR) &siglen);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DSA_SIGN, PK11_R_SIGN, rv);
+ goto ret;
+ }
+ }
+
+
+ if ((s = BN_new()) == NULL)
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_MALLOC_FAILURE);
+ goto ret;
+ }
+
+ if ((r = BN_new()) == NULL)
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_MALLOC_FAILURE);
+ goto ret;
+ }
+
+ if ((dsa_sig = DSA_SIG_new()) == NULL)
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_MALLOC_FAILURE);
+ goto ret;
+ }
+
+ if (BN_bin2bn(sigret, siglen2, r) == NULL ||
+ BN_bin2bn(&sigret[siglen2], siglen2, s) == NULL)
+ {
+ PK11err(PK11_F_DSA_SIGN, PK11_R_MALLOC_FAILURE);
+ goto ret;
+ }
+
+ dsa_sig->r = r;
+ dsa_sig->s = s;
+
+ret:
+ if (dsa_sig == NULL)
+ {
+ if (r != NULL)
+ BN_free(r);
+ if (s != NULL)
+ BN_free(s);
+ }
+
+ pk11_return_session(sp, OP_DSA);
+ return (dsa_sig);
+ }
+
+static int
+pk11_dsa_do_verify(const unsigned char *dgst, int dlen, DSA_SIG *sig,
+ DSA *dsa)
+ {
+ int i;
+ CK_RV rv;
+ int retval = 0;
+ CK_MECHANISM Mechanism_dsa = {CKM_DSA, NULL, 0};
+ CK_MECHANISM *p_mech = &Mechanism_dsa;
+ CK_OBJECT_HANDLE h_pub_key;
+
+ unsigned char sigbuf[DSA_SIGNATURE_LEN];
+ unsigned long siglen = DSA_SIGNATURE_LEN;
+ unsigned long siglen2 = DSA_SIGNATURE_LEN/2;
+
+ PK11_SESSION *sp = NULL;
+
+ if (BN_is_zero(sig->r) || sig->r->neg || BN_ucmp(sig->r, dsa->q) >= 0)
+ {
+ PK11err(PK11_F_DSA_VERIFY,
+ PK11_R_INVALID_DSA_SIGNATURE_R);
+ goto ret;
+ }
+
+ if (BN_is_zero(sig->s) || sig->s->neg || BN_ucmp(sig->s, dsa->q) >= 0)
+ {
+ PK11err(PK11_F_DSA_VERIFY,
+ PK11_R_INVALID_DSA_SIGNATURE_S);
+ goto ret;
+ }
+
+ i = BN_num_bytes(dsa->q); /* should be 20 */
+
+ if (dlen > i)
+ {
+ PK11err(PK11_F_DSA_VERIFY,
+ PK11_R_INVALID_SIGNATURE_LENGTH);
+ goto ret;
+ }
+
+ if ((sp = pk11_get_session(OP_DSA)) == NULL)
+ goto ret;
+
+ (void) check_new_dsa_key_pub(sp, dsa);
+
+ h_pub_key = sp->opdata_dsa_pub_key;
+ if (h_pub_key == CK_INVALID_HANDLE)
+ h_pub_key = sp->opdata_dsa_pub_key =
+ pk11_get_public_dsa_key((DSA *)dsa, &sp->opdata_dsa_pub,
+ &sp->opdata_dsa_pub_num, sp->session);
+
+ if (h_pub_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_VerifyInit(sp->session, p_mech,
+ h_pub_key);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DSA_VERIFY, PK11_R_VERIFYINIT,
+ rv);
+ goto ret;
+ }
+
+ /*
+ * The representation of each of the two big numbers could
+ * be shorter than DSA_SIGNATURE_LEN/2 bytes so we need
+ * to act accordingly and shift if necessary.
+ */
+ (void) memset(sigbuf, 0, siglen);
+ BN_bn2bin(sig->r, sigbuf + siglen2 - BN_num_bytes(sig->r));
+ BN_bn2bin(sig->s, &sigbuf[siglen2] + siglen2 -
+ BN_num_bytes(sig->s));
+
+ rv = pFuncList->C_Verify(sp->session,
+ (unsigned char *) dgst, dlen, sigbuf, (CK_ULONG)siglen);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DSA_VERIFY, PK11_R_VERIFY, rv);
+ goto ret;
+ }
+ }
+
+ retval = 1;
+ret:
+
+ pk11_return_session(sp, OP_DSA);
+ return (retval);
+ }
+
+
+/*
+ * Create a public key object in a session from a given dsa structure.
+ * The *dsa_pub_num pointer is non-NULL for DSA public keys.
+ */
+static CK_OBJECT_HANDLE pk11_get_public_dsa_key(DSA* dsa,
+ DSA **key_ptr, BIGNUM **dsa_pub_num, CK_SESSION_HANDLE session)
+ {
+ CK_RV rv;
+ CK_OBJECT_CLASS o_key = CKO_PUBLIC_KEY;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ CK_ULONG found;
+ CK_KEY_TYPE k_type = CKK_DSA;
+ CK_ULONG ul_key_attr_count = 8;
+ CK_BBOOL rollback = CK_FALSE;
+ int i;
+
+ CK_ATTRIBUTE a_key_template[] =
+ {
+ {CKA_CLASS, (void *) NULL, sizeof (CK_OBJECT_CLASS)},
+ {CKA_KEY_TYPE, (void *) NULL, sizeof (CK_KEY_TYPE)},
+ {CKA_TOKEN, &pk11_false, sizeof (pk11_false)},
+ {CKA_VERIFY, &pk11_true, sizeof (pk11_true)},
+ {CKA_PRIME, (void *)NULL, 0}, /* p */
+ {CKA_SUBPRIME, (void *)NULL, 0}, /* q */
+ {CKA_BASE, (void *)NULL, 0}, /* g */
+ {CKA_VALUE, (void *)NULL, 0} /* pub_key - y */
+ };
+
+ a_key_template[0].pValue = &o_key;
+ a_key_template[1].pValue = &k_type;
+
+ if (init_template_value(dsa->p, &a_key_template[4].pValue,
+ &a_key_template[4].ulValueLen) == 0 ||
+ init_template_value(dsa->q, &a_key_template[5].pValue,
+ &a_key_template[5].ulValueLen) == 0 ||
+ init_template_value(dsa->g, &a_key_template[6].pValue,
+ &a_key_template[6].ulValueLen) == 0 ||
+ init_template_value(dsa->pub_key, &a_key_template[7].pValue,
+ &a_key_template[7].ulValueLen) == 0)
+ {
+ PK11err(PK11_F_GET_PUB_DSA_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(OP_DSA);
+ rv = pFuncList->C_FindObjectsInit(session, a_key_template,
+ ul_key_attr_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_DSA_KEY,
+ PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(session, &h_key, 1, &found);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_DSA_KEY,
+ PK11_R_FINDOBJECTS, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjectsFinal(session);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_DSA_KEY,
+ PK11_R_FINDOBJECTSFINAL, rv);
+ goto err;
+ }
+
+ if (found == 0)
+ {
+ rv = pFuncList->C_CreateObject(session,
+ a_key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PUB_DSA_KEY,
+ PK11_R_CREATEOBJECT, rv);
+ goto err;
+ }
+ }
+
+ if (dsa_pub_num != NULL)
+ if ((*dsa_pub_num = BN_dup(dsa->pub_key)) == NULL)
+ {
+ PK11err(PK11_F_GET_PUB_DSA_KEY, PK11_R_MALLOC_FAILURE);
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ /* LINTED: E_CONSTANT_CONDITION */
+ KEY_HANDLE_REFHOLD(h_key, OP_DSA, CK_FALSE, rollback, err);
+ if (key_ptr != NULL)
+ *key_ptr = dsa;
+
+err:
+ if (rollback)
+ {
+ /*
+ * We do not care about the return value from C_DestroyObject()
+ * since we are doing rollback.
+ */
+ if (found == 0)
+ (void) pFuncList->C_DestroyObject(session, h_key);
+ h_key = CK_INVALID_HANDLE;
+ }
+
+ UNLOCK_OBJSTORE(OP_DSA);
+
+malloc_err:
+ for (i = 4; i <= 7; i++)
+ {
+ if (a_key_template[i].pValue != NULL)
+ {
+ OPENSSL_free(a_key_template[i].pValue);
+ a_key_template[i].pValue = NULL;
+ }
+ }
+
+ return (h_key);
+ }
+
+/*
+ * Create a private key object in the session from a given dsa structure
+ * The *dsa_priv_num pointer is non-NULL for DSA private keys.
+ */
+static CK_OBJECT_HANDLE pk11_get_private_dsa_key(DSA* dsa,
+ DSA **key_ptr, BIGNUM **dsa_priv_num, CK_SESSION_HANDLE session)
+ {
+ CK_RV rv;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS o_key = CKO_PRIVATE_KEY;
+ int i;
+ CK_ULONG found;
+ CK_KEY_TYPE k_type = CKK_DSA;
+ CK_ULONG ul_key_attr_count = 9;
+ CK_BBOOL rollback = CK_FALSE;
+
+ /*
+ * Both CKA_TOKEN and CKA_SENSITIVE have to be CK_FALSE for session keys
+ */
+ CK_ATTRIBUTE a_key_template[] =
+ {
+ {CKA_CLASS, (void *) NULL, sizeof (CK_OBJECT_CLASS)},
+ {CKA_KEY_TYPE, (void *) NULL, sizeof (CK_KEY_TYPE)},
+ {CKA_TOKEN, &pk11_false, sizeof (pk11_false)},
+ {CKA_SENSITIVE, &pk11_false, sizeof (pk11_false)},
+ {CKA_SIGN, &pk11_true, sizeof (pk11_true)},
+ {CKA_PRIME, (void *)NULL, 0}, /* p */
+ {CKA_SUBPRIME, (void *)NULL, 0}, /* q */
+ {CKA_BASE, (void *)NULL, 0}, /* g */
+ {CKA_VALUE, (void *)NULL, 0} /* priv_key - x */
+ };
+
+ a_key_template[0].pValue = &o_key;
+ a_key_template[1].pValue = &k_type;
+
+ /* Put the private key components into the template */
+ if (init_template_value(dsa->p, &a_key_template[5].pValue,
+ &a_key_template[5].ulValueLen) == 0 ||
+ init_template_value(dsa->q, &a_key_template[6].pValue,
+ &a_key_template[6].ulValueLen) == 0 ||
+ init_template_value(dsa->g, &a_key_template[7].pValue,
+ &a_key_template[7].ulValueLen) == 0 ||
+ init_template_value(dsa->priv_key, &a_key_template[8].pValue,
+ &a_key_template[8].ulValueLen) == 0)
+ {
+ PK11err(PK11_F_GET_PRIV_DSA_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(OP_DSA);
+ rv = pFuncList->C_FindObjectsInit(session, a_key_template,
+ ul_key_attr_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_DSA_KEY,
+ PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(session, &h_key, 1, &found);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_DSA_KEY,
+ PK11_R_FINDOBJECTS, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjectsFinal(session);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_DSA_KEY,
+ PK11_R_FINDOBJECTSFINAL, rv);
+ goto err;
+ }
+
+ if (found == 0)
+ {
+ rv = pFuncList->C_CreateObject(session,
+ a_key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_PRIV_DSA_KEY,
+ PK11_R_CREATEOBJECT, rv);
+ goto err;
+ }
+ }
+
+ if (dsa_priv_num != NULL)
+ if ((*dsa_priv_num = BN_dup(dsa->priv_key)) == NULL)
+ {
+ PK11err(PK11_F_GET_PRIV_DSA_KEY, PK11_R_MALLOC_FAILURE);
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ /* LINTED: E_CONSTANT_CONDITION */
+ KEY_HANDLE_REFHOLD(h_key, OP_DSA, CK_FALSE, rollback, err);
+ if (key_ptr != NULL)
+ *key_ptr = dsa;
+
+err:
+ if (rollback)
+ {
+ /*
+ * We do not care about the return value from C_DestroyObject()
+ * since we are doing rollback.
+ */
+ if (found == 0)
+ (void) pFuncList->C_DestroyObject(session, h_key);
+ h_key = CK_INVALID_HANDLE;
+ }
+
+ UNLOCK_OBJSTORE(OP_DSA);
+
+malloc_err:
+ /*
+ * 5 to 8 entries in the key template are key components.
+ * They need to be freed apon exit or error.
+ */
+ for (i = 5; i <= 8; i++)
+ {
+ if (a_key_template[i].pValue != NULL)
+ {
+ (void) memset(a_key_template[i].pValue, 0,
+ a_key_template[i].ulValueLen);
+ OPENSSL_free(a_key_template[i].pValue);
+ a_key_template[i].pValue = NULL;
+ }
+ }
+
+ return (h_key);
+ }
+
+/*
+ * Check for cache miss and clean the object pointer and handle
+ * in such case. Return 1 for cache hit, 0 for cache miss.
+ */
+static int check_new_dsa_key_pub(PK11_SESSION *sp, DSA *dsa)
+ {
+ /*
+ * Provide protection against DSA structure reuse by making the
+ * check for cache hit stronger. Only public key component of DSA
+ * key matters here so it is sufficient to compare it with value
+ * cached in PK11_SESSION structure.
+ */
+ if ((sp->opdata_dsa_pub != dsa) ||
+ (BN_cmp(sp->opdata_dsa_pub_num, dsa->pub_key) != 0))
+ {
+ /*
+ * We do not check the return value because even in case of
+ * failure the sp structure will have both key pointer
+ * and object handle cleaned and pk11_destroy_object()
+ * reports the failure to the OpenSSL error message buffer.
+ */
+ (void) pk11_destroy_dsa_object_pub(sp, CK_TRUE);
+ return (0);
+ }
+ return (1);
+ }
+
+/*
+ * Check for cache miss and clean the object pointer and handle
+ * in such case. Return 1 for cache hit, 0 for cache miss.
+ */
+static int check_new_dsa_key_priv(PK11_SESSION *sp, DSA *dsa)
+ {
+ /*
+ * Provide protection against DSA structure reuse by making the
+ * check for cache hit stronger. Only private key component of DSA
+ * key matters here so it is sufficient to compare it with value
+ * cached in PK11_SESSION structure.
+ */
+ if ((sp->opdata_dsa_priv != dsa) ||
+ (BN_cmp(sp->opdata_dsa_priv_num, dsa->priv_key) != 0))
+ {
+ /*
+ * We do not check the return value because even in case of
+ * failure the sp structure will have both key pointer
+ * and object handle cleaned and pk11_destroy_object()
+ * reports the failure to the OpenSSL error message buffer.
+ */
+ (void) pk11_destroy_dsa_object_priv(sp, CK_TRUE);
+ return (0);
+ }
+ return (1);
+ }
+#endif
+
+
+#ifndef OPENSSL_NO_DH
+/* The DH function implementation */
+/* ARGSUSED */
+static int pk11_DH_init(DH *dh)
+ {
+ return (1);
+ }
+
+/* ARGSUSED */
+static int pk11_DH_finish(DH *dh)
+ {
+ return (1);
+ }
+
+/*
+ * Generate DH key-pair.
+ *
+ * Warning: Unlike OpenSSL's DH_generate_key(3) we ignore dh->priv_key
+ * and override it even if it is set. OpenSSL does not touch dh->priv_key
+ * if set and just computes dh->pub_key. It looks like PKCS#11 standard
+ * is not capable of providing this functionality. This could be a problem
+ * for applications relying on OpenSSL's semantics.
+ */
+static int pk11_DH_generate_key(DH *dh)
+ {
+ CK_ULONG i;
+ CK_RV rv, rv1;
+ int reuse_mem_len = 0, ret = 0;
+ PK11_SESSION *sp = NULL;
+ CK_BYTE_PTR reuse_mem;
+
+ CK_MECHANISM mechanism = {CKM_DH_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
+ CK_OBJECT_HANDLE h_pub_key = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE h_priv_key = CK_INVALID_HANDLE;
+
+ CK_ULONG ul_pub_key_attr_count = 3;
+ CK_ATTRIBUTE pub_key_template[] =
+ {
+ {CKA_PRIVATE, &pk11_false, sizeof (pk11_false)},
+ {CKA_PRIME, (void *)NULL, 0},
+ {CKA_BASE, (void *)NULL, 0}
+ };
+
+ CK_ULONG ul_priv_key_attr_count = 3;
+ CK_ATTRIBUTE priv_key_template[] =
+ {
+ {CKA_PRIVATE, &pk11_false, sizeof (pk11_false)},
+ {CKA_SENSITIVE, &pk11_false, sizeof (pk11_false)},
+ {CKA_DERIVE, &pk11_true, sizeof (pk11_true)}
+ };
+
+ CK_ULONG pub_key_attr_result_count = 1;
+ CK_ATTRIBUTE pub_key_result[] =
+ {
+ {CKA_VALUE, (void *)NULL, 0}
+ };
+
+ CK_ULONG priv_key_attr_result_count = 1;
+ CK_ATTRIBUTE priv_key_result[] =
+ {
+ {CKA_VALUE, (void *)NULL, 0}
+ };
+
+ pub_key_template[1].ulValueLen = BN_num_bytes(dh->p);
+ if (pub_key_template[1].ulValueLen > 0)
+ {
+ /*
+ * We must not increase ulValueLen by DH_BUF_RESERVE since that
+ * could cause the same rounding problem. See definition of
+ * DH_BUF_RESERVE above.
+ */
+ pub_key_template[1].pValue =
+ OPENSSL_malloc(pub_key_template[1].ulValueLen +
+ DH_BUF_RESERVE);
+ if (pub_key_template[1].pValue == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ i = BN_bn2bin(dh->p, pub_key_template[1].pValue);
+ }
+ else
+ goto err;
+
+ pub_key_template[2].ulValueLen = BN_num_bytes(dh->g);
+ if (pub_key_template[2].ulValueLen > 0)
+ {
+ pub_key_template[2].pValue =
+ OPENSSL_malloc(pub_key_template[2].ulValueLen +
+ DH_BUF_RESERVE);
+ if (pub_key_template[2].pValue == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ i = BN_bn2bin(dh->g, pub_key_template[2].pValue);
+ }
+ else
+ goto err;
+
+ /*
+ * Note: we are only using PK11_SESSION structure for getting
+ * a session handle. The objects created in this function are
+ * destroyed before return and thus not cached.
+ */
+ if ((sp = pk11_get_session(OP_DH)) == NULL)
+ goto err;
+
+ rv = pFuncList->C_GenerateKeyPair(sp->session,
+ &mechanism,
+ pub_key_template,
+ ul_pub_key_attr_count,
+ priv_key_template,
+ ul_priv_key_attr_count,
+ &h_pub_key,
+ &h_priv_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_GEN_KEY, PK11_R_GEN_KEY, rv);
+ goto err;
+ }
+
+ /*
+ * Reuse the larger memory allocated. We know the larger memory
+ * should be sufficient for reuse.
+ */
+ if (pub_key_template[1].ulValueLen > pub_key_template[2].ulValueLen)
+ {
+ reuse_mem = pub_key_template[1].pValue;
+ reuse_mem_len = pub_key_template[1].ulValueLen + DH_BUF_RESERVE;
+ }
+ else
+ {
+ reuse_mem = pub_key_template[2].pValue;
+ reuse_mem_len = pub_key_template[2].ulValueLen + DH_BUF_RESERVE;
+ }
+
+ rv = pFuncList->C_GetAttributeValue(sp->session, h_pub_key,
+ pub_key_result, pub_key_attr_result_count);
+ rv1 = pFuncList->C_GetAttributeValue(sp->session, h_priv_key,
+ priv_key_result, priv_key_attr_result_count);
+
+ if (rv != CKR_OK || rv1 != CKR_OK)
+ {
+ rv = (rv != CKR_OK) ? rv : rv1;
+ PK11err_add_data(PK11_F_DH_GEN_KEY,
+ PK11_R_GETATTRIBUTVALUE, rv);
+ goto err;
+ }
+
+ if (((CK_LONG) pub_key_result[0].ulValueLen) <= 0 ||
+ ((CK_LONG) priv_key_result[0].ulValueLen) <= 0)
+ {
+ PK11err(PK11_F_DH_GEN_KEY, PK11_R_GETATTRIBUTVALUE);
+ goto err;
+ }
+
+ /* Reuse the memory allocated */
+ pub_key_result[0].pValue = reuse_mem;
+ pub_key_result[0].ulValueLen = reuse_mem_len;
+
+ rv = pFuncList->C_GetAttributeValue(sp->session, h_pub_key,
+ pub_key_result, pub_key_attr_result_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_GEN_KEY,
+ PK11_R_GETATTRIBUTVALUE, rv);
+ goto err;
+ }
+
+ if (pub_key_result[0].type == CKA_VALUE)
+ {
+ if (dh->pub_key == NULL)
+ if ((dh->pub_key = BN_new()) == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY,
+ PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ dh->pub_key = BN_bin2bn(pub_key_result[0].pValue,
+ pub_key_result[0].ulValueLen, dh->pub_key);
+ if (dh->pub_key == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ /* Reuse the memory allocated */
+ priv_key_result[0].pValue = reuse_mem;
+ priv_key_result[0].ulValueLen = reuse_mem_len;
+
+ rv = pFuncList->C_GetAttributeValue(sp->session, h_priv_key,
+ priv_key_result, priv_key_attr_result_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_GEN_KEY,
+ PK11_R_GETATTRIBUTVALUE, rv);
+ goto err;
+ }
+
+ if (priv_key_result[0].type == CKA_VALUE)
+ {
+ if (dh->priv_key == NULL)
+ if ((dh->priv_key = BN_new()) == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY,
+ PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ dh->priv_key = BN_bin2bn(priv_key_result[0].pValue,
+ priv_key_result[0].ulValueLen, dh->priv_key);
+ if (dh->priv_key == NULL)
+ {
+ PK11err(PK11_F_DH_GEN_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+
+ if (h_pub_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_DestroyObject(sp->session, h_pub_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_GEN_KEY,
+ PK11_R_DESTROYOBJECT, rv);
+ }
+ }
+
+ if (h_priv_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_DestroyObject(sp->session, h_priv_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_GEN_KEY,
+ PK11_R_DESTROYOBJECT, rv);
+ }
+ }
+
+ for (i = 1; i <= 2; i++)
+ {
+ if (pub_key_template[i].pValue != NULL)
+ {
+ OPENSSL_free(pub_key_template[i].pValue);
+ pub_key_template[i].pValue = NULL;
+ }
+ }
+
+ pk11_return_session(sp, OP_DH);
+ return (ret);
+ }
+
+static int pk11_DH_compute_key(unsigned char *key, const BIGNUM *pub_key,
+ DH *dh)
+ {
+ int i;
+ CK_MECHANISM mechanism = {CKM_DH_PKCS_DERIVE, NULL_PTR, 0};
+ CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
+ CK_KEY_TYPE key_type = CKK_GENERIC_SECRET;
+ CK_OBJECT_HANDLE h_derived_key = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+
+ CK_ULONG ul_priv_key_attr_count = 2;
+ CK_ATTRIBUTE priv_key_template[] =
+ {
+ {CKA_CLASS, (void*) NULL, sizeof (key_class)},
+ {CKA_KEY_TYPE, (void*) NULL, sizeof (key_type)},
+ };
+
+ CK_ULONG priv_key_attr_result_count = 1;
+ CK_ATTRIBUTE priv_key_result[] =
+ {
+ {CKA_VALUE, (void *)NULL, 0}
+ };
+
+ CK_RV rv;
+ int ret = -1;
+ PK11_SESSION *sp = NULL;
+
+ if (dh->priv_key == NULL)
+ goto err;
+
+ priv_key_template[0].pValue = &key_class;
+ priv_key_template[1].pValue = &key_type;
+
+ if ((sp = pk11_get_session(OP_DH)) == NULL)
+ goto err;
+
+ mechanism.ulParameterLen = BN_num_bytes(pub_key);
+ mechanism.pParameter = OPENSSL_malloc(mechanism.ulParameterLen);
+ if (mechanism.pParameter == NULL)
+ {
+ PK11err(PK11_F_DH_COMP_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ BN_bn2bin(pub_key, mechanism.pParameter);
+
+ (void) check_new_dh_key(sp, dh);
+
+ h_key = sp->opdata_dh_key;
+ if (h_key == CK_INVALID_HANDLE)
+ h_key = sp->opdata_dh_key =
+ pk11_get_dh_key((DH*) dh, &sp->opdata_dh,
+ &sp->opdata_dh_priv_num, sp->session);
+
+ if (h_key == CK_INVALID_HANDLE)
+ {
+ PK11err(PK11_F_DH_COMP_KEY, PK11_R_CREATEOBJECT);
+ goto err;
+ }
+
+ rv = pFuncList->C_DeriveKey(sp->session,
+ &mechanism,
+ h_key,
+ priv_key_template,
+ ul_priv_key_attr_count,
+ &h_derived_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_COMP_KEY, PK11_R_DERIVEKEY, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_GetAttributeValue(sp->session, h_derived_key,
+ priv_key_result, priv_key_attr_result_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_COMP_KEY, PK11_R_GETATTRIBUTVALUE,
+ rv);
+ goto err;
+ }
+
+ if (((CK_LONG) priv_key_result[0].ulValueLen) <= 0)
+ {
+ PK11err(PK11_F_DH_COMP_KEY, PK11_R_GETATTRIBUTVALUE);
+ goto err;
+ }
+ priv_key_result[0].pValue =
+ OPENSSL_malloc(priv_key_result[0].ulValueLen);
+ if (!priv_key_result[0].pValue)
+ {
+ PK11err(PK11_F_DH_COMP_KEY, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ rv = pFuncList->C_GetAttributeValue(sp->session, h_derived_key,
+ priv_key_result, priv_key_attr_result_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_COMP_KEY, PK11_R_GETATTRIBUTVALUE,
+ rv);
+ goto err;
+ }
+
+ /*
+ * OpenSSL allocates the output buffer 'key' which is the same
+ * length of the public key. It is long enough for the derived key
+ */
+ if (priv_key_result[0].type == CKA_VALUE)
+ {
+ /*
+ * CKM_DH_PKCS_DERIVE mechanism is not supposed to strip
+ * leading zeros from a computed shared secret. However,
+ * OpenSSL always did it so we must do the same here. The
+ * vagueness of the spec regarding leading zero bytes was
+ * finally cleared with TLS 1.1 (RFC 4346) saying that leading
+ * zeros are stripped before the computed data is used as the
+ * pre-master secret.
+ */
+ for (i = 0; i < priv_key_result[0].ulValueLen; ++i)
+ {
+ if (((char *)priv_key_result[0].pValue)[i] != 0)
+ break;
+ }
+
+ (void) memcpy(key, ((char *)priv_key_result[0].pValue) + i,
+ priv_key_result[0].ulValueLen - i);
+ ret = priv_key_result[0].ulValueLen - i;
+ }
+
+err:
+
+ if (h_derived_key != CK_INVALID_HANDLE)
+ {
+ rv = pFuncList->C_DestroyObject(sp->session, h_derived_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_DH_COMP_KEY,
+ PK11_R_DESTROYOBJECT, rv);
+ }
+ }
+ if (priv_key_result[0].pValue)
+ {
+ OPENSSL_free(priv_key_result[0].pValue);
+ priv_key_result[0].pValue = NULL;
+ }
+
+ if (mechanism.pParameter)
+ {
+ OPENSSL_free(mechanism.pParameter);
+ mechanism.pParameter = NULL;
+ }
+
+ pk11_return_session(sp, OP_DH);
+ return (ret);
+ }
+
+
+static CK_OBJECT_HANDLE pk11_get_dh_key(DH* dh,
+ DH **key_ptr, BIGNUM **dh_priv_num, CK_SESSION_HANDLE session)
+ {
+ CK_RV rv;
+ CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
+ CK_KEY_TYPE key_type = CKK_DH;
+ CK_ULONG found;
+ CK_BBOOL rollback = CK_FALSE;
+ int i;
+
+ CK_ULONG ul_key_attr_count = 7;
+ CK_ATTRIBUTE key_template[] =
+ {
+ {CKA_CLASS, (void*) NULL, sizeof (class)},
+ {CKA_KEY_TYPE, (void*) NULL, sizeof (key_type)},
+ {CKA_DERIVE, &pk11_true, sizeof (pk11_true)},
+ {CKA_PRIVATE, &pk11_false, sizeof (pk11_false)},
+ {CKA_PRIME, (void *) NULL, 0},
+ {CKA_BASE, (void *) NULL, 0},
+ {CKA_VALUE, (void *) NULL, 0},
+ };
+
+ key_template[0].pValue = &class;
+ key_template[1].pValue = &key_type;
+
+ key_template[4].ulValueLen = BN_num_bytes(dh->p);
+ key_template[4].pValue = (CK_VOID_PTR)OPENSSL_malloc(
+ (size_t)key_template[4].ulValueLen);
+ if (key_template[4].pValue == NULL)
+ {
+ PK11err(PK11_F_GET_DH_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ BN_bn2bin(dh->p, key_template[4].pValue);
+
+ key_template[5].ulValueLen = BN_num_bytes(dh->g);
+ key_template[5].pValue = (CK_VOID_PTR)OPENSSL_malloc(
+ (size_t)key_template[5].ulValueLen);
+ if (key_template[5].pValue == NULL)
+ {
+ PK11err(PK11_F_GET_DH_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ BN_bn2bin(dh->g, key_template[5].pValue);
+
+ key_template[6].ulValueLen = BN_num_bytes(dh->priv_key);
+ key_template[6].pValue = (CK_VOID_PTR)OPENSSL_malloc(
+ (size_t)key_template[6].ulValueLen);
+ if (key_template[6].pValue == NULL)
+ {
+ PK11err(PK11_F_GET_DH_KEY, PK11_R_MALLOC_FAILURE);
+ goto malloc_err;
+ }
+
+ BN_bn2bin(dh->priv_key, key_template[6].pValue);
+
+ /* see find_lock array definition for more info on object locking */
+ LOCK_OBJSTORE(OP_DH);
+ rv = pFuncList->C_FindObjectsInit(session, key_template,
+ ul_key_attr_count);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_DH_KEY, PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(session, &h_key, 1, &found);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_DH_KEY, PK11_R_FINDOBJECTS, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjectsFinal(session);
+
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_DH_KEY, PK11_R_FINDOBJECTSFINAL,
+ rv);
+ goto err;
+ }
+
+ if (found == 0)
+ {
+ rv = pFuncList->C_CreateObject(session,
+ key_template, ul_key_attr_count, &h_key);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_GET_DH_KEY, PK11_R_CREATEOBJECT,
+ rv);
+ goto err;
+ }
+ }
+
+ if (dh_priv_num != NULL)
+ if ((*dh_priv_num = BN_dup(dh->priv_key)) == NULL)
+ {
+ PK11err(PK11_F_GET_DH_KEY, PK11_R_MALLOC_FAILURE);
+ rollback = CK_TRUE;
+ goto err;
+ }
+
+ /* LINTED: E_CONSTANT_CONDITION */
+ KEY_HANDLE_REFHOLD(h_key, OP_DH, CK_FALSE, rollback, err);
+ if (key_ptr != NULL)
+ *key_ptr = dh;
+
+err:
+ if (rollback)
+ {
+ /*
+ * We do not care about the return value from C_DestroyObject()
+ * since we are doing rollback.
+ */
+ if (found == 0)
+ (void) pFuncList->C_DestroyObject(session, h_key);
+ h_key = CK_INVALID_HANDLE;
+ }
+
+ UNLOCK_OBJSTORE(OP_DH);
+
+malloc_err:
+ for (i = 4; i <= 6; i++)
+ {
+ if (key_template[i].pValue != NULL)
+ {
+ OPENSSL_free(key_template[i].pValue);
+ key_template[i].pValue = NULL;
+ }
+ }
+
+ return (h_key);
+ }
+
+/*
+ * Check for cache miss and clean the object pointer and handle
+ * in such case. Return 1 for cache hit, 0 for cache miss.
+ *
+ * Note: we rely on pk11_destroy_dh_key_objects() to set sp->opdata_dh
+ * to CK_INVALID_HANDLE even when it fails to destroy the object.
+ */
+static int check_new_dh_key(PK11_SESSION *sp, DH *dh)
+ {
+ /*
+ * Provide protection against DH structure reuse by making the
+ * check for cache hit stronger. Private key component of DH key
+ * is unique so it is sufficient to compare it with value cached
+ * in PK11_SESSION structure.
+ */
+ if ((sp->opdata_dh != dh) ||
+ (BN_cmp(sp->opdata_dh_priv_num, dh->priv_key) != 0))
+ {
+ /*
+ * We do not check the return value because even in case of
+ * failure the sp structure will have both key pointer
+ * and object handle cleaned and pk11_destroy_object()
+ * reports the failure to the OpenSSL error message buffer.
+ */
+ (void) pk11_destroy_dh_object(sp, CK_TRUE);
+ return (0);
+ }
+ return (1);
+ }
+#endif
+
+/*
+ * Local function to simplify key template population
+ * Return 0 -- error, 1 -- no error
+ */
+static int
+init_template_value(BIGNUM *bn, CK_VOID_PTR *p_value,
+ CK_ULONG *ul_value_len)
+ {
+ CK_ULONG len;
+
+ /*
+ * This function can be used on non-initialized BIGNUMs. It is easier to
+ * check that here than individually in the callers.
+ */
+ if (bn != NULL)
+ len = BN_num_bytes(bn);
+
+ if (bn == NULL || len == 0)
+ return (1);
+
+ *ul_value_len = len;
+ *p_value = (CK_VOID_PTR)OPENSSL_malloc((size_t)*ul_value_len);
+ if (*p_value == NULL)
+ return (0);
+
+ BN_bn2bin(bn, *p_value);
+
+ return (1);
+ }
+
+static void
+attr_to_BN(CK_ATTRIBUTE_PTR attr, CK_BYTE attr_data[], BIGNUM **bn)
+ {
+ if (attr->ulValueLen > 0)
+ *bn = BN_bin2bn(attr_data, attr->ulValueLen, NULL);
+ }
+
+/*
+ * Find one object in the token. It is an error if we can not find the object or
+ * if we find more objects based on the template we got.
+ *
+ * Returns:
+ * 1 OK
+ * 0 no object or more than 1 object found
+ */
+static int
+find_one_object(PK11_OPTYPE op, CK_SESSION_HANDLE s,
+ CK_ATTRIBUTE_PTR ptempl, CK_ULONG nattr, CK_OBJECT_HANDLE_PTR pkey)
+ {
+ CK_RV rv;
+ CK_ULONG objcnt;
+
+ LOCK_OBJSTORE(op);
+ if ((rv = pFuncList->C_FindObjectsInit(s, ptempl, nattr)) != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_FIND_ONE_OBJECT,
+ PK11_R_FINDOBJECTSINIT, rv);
+ goto err;
+ }
+
+ rv = pFuncList->C_FindObjects(s, pkey, 1, &objcnt);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_FIND_ONE_OBJECT, PK11_R_FINDOBJECTS,
+ rv);
+ goto err;
+ }
+
+ if (objcnt > 1)
+ {
+ PK11err(PK11_F_FIND_ONE_OBJECT,
+ PK11_R_MORE_THAN_ONE_OBJECT_FOUND);
+ goto err;
+ }
+ else
+ if (objcnt == 0)
+ {
+ PK11err(PK11_F_FIND_ONE_OBJECT, PK11_R_NO_OBJECT_FOUND);
+ goto err;
+ }
+
+ (void) pFuncList->C_FindObjectsFinal(s);
+ UNLOCK_OBJSTORE(op);
+ return (1);
+err:
+ UNLOCK_OBJSTORE(op);
+ return (0);
+ }
+
+#endif /* OPENSSL_NO_HW_PK11 */
+#endif /* OPENSSL_NO_HW */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11_uri.c b/openssl0.9.8/engines/pkcs11/hw_pk11_uri.c
new file mode 100644
index 0000000..db98b11
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11_uri.c
@@ -0,0 +1,870 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. 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
+ * the documentation and/or other materials provided with the
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <strings.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <openssl/crypto.h>
+
+#ifndef OPENSSL_NO_HW
+#ifndef OPENSSL_NO_HW_PK11
+
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include "hw_pk11.h"
+#include "hw_pk11_uri.h"
+
+/*
+ * The keystore used is always from the pubkey slot so we need to know which one
+ * was selected so that we can get the information needed for the URI
+ * processing.
+ */
+extern CK_SLOT_ID pubkey_SLOTID;
+extern CK_FUNCTION_LIST_PTR pFuncList;
+
+/*
+ * Cached PIN so that child can use it during the re-login. Note that we do not
+ * cache the PIN by default.
+ */
+static char *token_pin;
+
+static int mlock_pin_in_memory(char *pin);
+static char *run_askpass(char *dialog);
+
+/*
+ * Get the PIN. Either run the command and use its standard output as a PIN to
+ * fill in the PKCS11 URI structure, or read the PIN from the terminal. Using
+ * the external command is of higher precedence. The memory for PIN is allocated
+ * in this function and the PIN is always NULL terminated. The caller must take
+ * care of freeing the memory used for the PIN. The maximum PIN length accepted
+ * is PK11_MAX_PIN_LEN.
+ *
+ * The function is used also during the re-initialization of the engine after
+ * the fork.
+ *
+ * The function must not be called under the protection of the mutex "uri_lock"
+ * because the lock is acquired in the prefork function.
+ *
+ * Returns:
+ * 0 in case of troubles (and sets "*pin" to NULL)
+ * 1 if we got the PIN
+ */
+#define EXEC_SPEC "exec:"
+#define BUILTIN_SPEC "builtin"
+int
+pk11_get_pin(char *dialog, char **pin)
+ {
+ /* Initialize as an error. */
+ *pin = NULL;
+
+ if (strcmp(dialog, BUILTIN_SPEC) == 0)
+ {
+ /* The getpassphrase() function is not MT safe. */
+ (void) pthread_mutex_lock(uri_lock);
+ /* Note that OpenSSL is not localized at all. */
+ *pin = getpassphrase("Enter token PIN: ");
+ if (*pin == NULL)
+ {
+ PK11err(PK11_F_GET_PIN, PK11_R_COULD_NOT_READ_PIN);
+ (void) pthread_mutex_unlock(uri_lock);
+ goto err;
+ }
+ else
+ {
+ char *pw;
+
+ /*
+ * getpassphrase() uses an internal buffer to hold the
+ * entered password. Note that it terminates the buffer
+ * with '\0'.
+ */
+ if ((pw = strdup(*pin)) == NULL)
+ {
+ PK11err(PK11_F_GET_PIN, PK11_R_MALLOC_FAILURE);
+ (void) pthread_mutex_unlock(uri_lock);
+ goto err;
+ }
+ /* Zero the internal buffer to get rid of the PIN. */
+ memset(*pin, 0, strlen(*pin));
+ *pin = pw;
+ (void) pthread_mutex_unlock(uri_lock);
+ }
+ }
+ else
+ {
+ /*
+ * This is the "exec:" case. We will get the PIN from the output
+ * of an external command.
+ */
+ if (strncmp(dialog, EXEC_SPEC, strlen(EXEC_SPEC)) == 0)
+ {
+ dialog += strlen(EXEC_SPEC);
+ if ((*pin = run_askpass(dialog)) == NULL)
+ goto err;
+ }
+ else
+ {
+ /*
+ * Invalid specification in the passphrasedialog
+ * keyword.
+ */
+ PK11err(PK11_F_GET_PIN, PK11_R_BAD_PASSPHRASE_SPEC);
+ goto err;
+ }
+ }
+
+ return (1);
+err:
+ return (0);
+ }
+
+/*
+ * Process the PKCS#11 URI and get the PIN. It uses information from the
+ * passphrasedialog keyword to get the PIN. If passphrasedialog is not present
+ * it is not considered an error since it depends on the token attributes
+ * whether C_Login() is required. The function expects an allocated 'uri_struct'
+ * structure.
+ *
+ * Returns:
+ * 0 if URI is not valid at all, or if we could not get the PIN
+ * 1 if all is OK
+ * 2 if the URI is not the PKCS#11 URI. In that case, put the string
+ * pointer to the filename to "*file". Note that the pointer just points
+ * inside of the "uristr", possibly skipping the file:// prefix if present.
+ */
+int
+pk11_process_pkcs11_uri(const char *uristr, pkcs11_uri *uri_struct,
+ const char **file)
+ {
+ char *uristr2, *l1, *l2, *tok, *name;
+
+ /* Check the "file://" case. */
+ if (strncmp(uristr, FILE_URI_PREFIX, strlen(FILE_URI_PREFIX)) == 0)
+ {
+ *file = uristr + strlen(FILE_URI_PREFIX);
+ return (2);
+ }
+
+ /* This is the "pkcs11:" case. */
+ if (strncmp(uristr, PK11_URI_PREFIX, strlen(PK11_URI_PREFIX)) != 0)
+ {
+ /* Not PKCS#11 URI at all, could be a filename. */
+ *file = (const char *)uristr;
+ return (2);
+ }
+ else
+ {
+ /* Dup the string and skip over the pkcs11: prefix then. */
+ uristr2 = strdup(uristr + strlen(PK11_URI_PREFIX));
+ if (uristr2 == NULL)
+ {
+ PK11err(PK11_F_CHECK_TOKEN_ATTRS,
+ PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ /* Initialize the structure. */
+ memset(uri_struct, 0, sizeof (*uri_struct));
+
+ /*
+ * Using strtok_r() would silently skip over multiple semicolons. We
+ * must check that before moving on. We must also avoid ';' as the first
+ * and the last character in the URI.
+ */
+ if (strstr(uristr2, ";;") != NULL || uristr2[0] == ';' ||
+ (strlen(uristr2) > 0 && uristr2[strlen(uristr2) - 1] == ';'))
+ goto bad_uri;
+
+ tok = strtok_r(uristr2, ";", &l1);
+ for (; tok != NULL; tok = strtok_r(NULL, ";", &l1))
+ {
+ /* "tok" is not empty so there will be something in "name". */
+ name = strtok_r(tok, "=", &l2);
+ /* Check whether there is '=' at all. */
+ if (l2 == NULL)
+ goto bad_uri;
+
+ /*
+ * Fill out the URI structure. We do not accept duplicit
+ * attributes.
+ */
+ if (strcmp(name, PK11_TOKEN) == 0)
+ if (uri_struct->token == NULL)
+ {
+ if ((uri_struct->token = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_MANUF) == 0)
+ if (uri_struct->manuf == NULL)
+ {
+ if ((uri_struct->manuf = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_SERIAL) == 0)
+ if (uri_struct->serial == NULL)
+ {
+ if ((uri_struct->serial = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_MODEL) == 0)
+ if (uri_struct->model == NULL)
+ {
+ if ((uri_struct->model = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_OBJECT) == 0)
+ if (uri_struct->object == NULL)
+ {
+ if ((uri_struct->object = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_OBJECTTYPE) == 0)
+ if (uri_struct->objecttype == NULL)
+ {
+ uri_struct->objecttype = strdup(l2);
+ if (uri_struct->objecttype == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else if (strcmp(name, PK11_ASKPASS) == 0)
+ if (uri_struct->askpass == NULL)
+ {
+ if ((uri_struct->askpass = strdup(l2)) == NULL)
+ goto no_mem;
+ }
+ else
+ goto bad_uri;
+ else
+ goto bad_uri;
+ }
+
+ /* The "object" token is mandatory in the PKCS#11 URI. */
+ if (uri_struct->object == NULL)
+ {
+ PK11err(PK11_F_LOAD_PRIVKEY, PK11_R_MISSING_OBJECT_LABEL);
+ goto err;
+ }
+
+ free(uristr2);
+ return (1);
+bad_uri:
+ PK11err(PK11_F_LOAD_PRIVKEY, PK11_R_INVALID_PKCS11_URI);
+ if (uristr2 != NULL)
+ free(uristr2);
+ return (0);
+no_mem:
+ PK11err(PK11_F_LOAD_PRIVKEY, PK11_R_MALLOC_FAILURE);
+err:
+ pk11_free_pkcs11_uri(uri_struct, CK_FALSE);
+ if (uristr2 != NULL)
+ free(uristr2);
+ return (0);
+ }
+
+/*
+ * Free the PKCS11 URI structure and anything that might be inside.
+ */
+void
+pk11_free_pkcs11_uri(pkcs11_uri *uri_struct, CK_BBOOL free_uri_itself)
+ {
+ if (uri_struct->token != NULL)
+ free(uri_struct->token);
+ if (uri_struct->manuf != NULL)
+ free(uri_struct->manuf);
+ if (uri_struct->serial != NULL)
+ free(uri_struct->serial);
+ if (uri_struct->model != NULL)
+ free(uri_struct->model);
+ if (uri_struct->object != NULL)
+ free(uri_struct->object);
+ if (uri_struct->objecttype != NULL)
+ free(uri_struct->objecttype);
+ if (uri_struct->askpass != NULL)
+ free(uri_struct->askpass);
+
+ if (free_uri_itself == CK_TRUE)
+ OPENSSL_free(uri_struct);
+ }
+
+/*
+ * While our keystore is always the one used by the pubkey slot (which is
+ * usually the Metaslot) we must make sure that those URI attributes that
+ * specify the keystore match the real attributes of our slot keystore. Note
+ * that one can use the METASLOT_OBJECTSTORE_TOKEN environment variable to
+ * change the Metaslot's keystore from the softtoken to something else (see
+ * libpkcs11(3LIB)). The user might want to use such attributes in the PKCS#11
+ * URI to make sure that the intended keystore is used.
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int
+pk11_check_token_attrs(pkcs11_uri *uri_struct)
+ {
+ CK_RV rv;
+ static CK_TOKEN_INFO_PTR token_info = NULL;
+
+ (void) pthread_mutex_lock(uri_lock);
+ if (token_info == NULL)
+ {
+ token_info = OPENSSL_malloc(sizeof (CK_TOKEN_INFO));
+ if (token_info == NULL)
+ {
+ PK11err(PK11_F_CHECK_TOKEN_ATTRS,
+ PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ rv = pFuncList->C_GetTokenInfo(pubkey_SLOTID, token_info);
+ if (rv != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_CHECK_TOKEN_ATTRS,
+ PK11_R_GETTOKENINFO, rv);
+ goto err;
+ }
+ }
+
+ if (uri_struct->token != NULL)
+ if (strncmp(uri_struct->token, (char *)token_info->label,
+ strlen(uri_struct->token) > 32 ? 32 :
+ strlen(uri_struct->token)) != 0)
+ {
+ goto urierr;
+ }
+
+ if (uri_struct->manuf != NULL)
+ if (strncmp(uri_struct->manuf,
+ (char *)token_info->manufacturerID,
+ strlen(uri_struct->manuf) > 32 ? 32 :
+ strlen(uri_struct->manuf)) != 0)
+ goto urierr;
+
+ if (uri_struct->model != NULL)
+ if (strncmp(uri_struct->model, (char *)token_info->model,
+ strlen(uri_struct->model) > 16 ? 16 :
+ strlen(uri_struct->model)) != 0)
+ goto urierr;
+
+ if (uri_struct->serial != NULL)
+ if (strncmp(uri_struct->serial,
+ (char *)token_info->serialNumber,
+ strlen(uri_struct->serial) > 16 ? 16 :
+ strlen(uri_struct->serial)) != 0)
+ goto urierr;
+
+ (void) pthread_mutex_unlock(uri_lock);
+ return (1);
+
+urierr:
+ PK11err(PK11_F_CHECK_TOKEN_ATTRS, PK11_R_TOKEN_ATTRS_DO_NOT_MATCH);
+ /* Correct error already set above for the "err" label. */
+err:
+ (void) pthread_mutex_unlock(uri_lock);
+ return (0);
+ }
+
+/*
+ * Return the process PIN caching policy. We initialize it just once so if the
+ * process change OPENSSL_PKCS11_PIN_CACHING_POLICY during the operation it will
+ * not have any affect on the policy.
+ *
+ * We assume that the "uri_lock" mutex is already locked.
+ *
+ * Returns the caching policy number.
+ */
+int
+pk11_get_pin_caching_policy(void)
+ {
+ char *value = NULL;
+ static int policy = POLICY_NOT_INITIALIZED;
+
+ if (policy != POLICY_NOT_INITIALIZED)
+ return (policy);
+
+ value = getenv("OPENSSL_PKCS11_PIN_CACHING_POLICY");
+
+ if (value == NULL || strcmp(value, "none") == 0)
+ {
+ policy = POLICY_NONE;
+ goto done;
+ }
+
+ if (strcmp(value, "memory") == 0)
+ {
+ policy = POLICY_MEMORY;
+ goto done;
+ }
+
+ if (strcmp(value, "mlocked-memory") == 0)
+ {
+ policy = POLICY_MLOCKED_MEMORY;
+ goto done;
+ }
+
+ return (POLICY_WRONG_VALUE);
+done:
+ return (policy);
+ }
+
+/*
+ * Cache the PIN in memory once. We already know that we have either "memory" or
+ * "mlocked-memory" keyword correctly set.
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int
+pk11_cache_pin(char *pin)
+ {
+ (void) pthread_mutex_lock(uri_lock);
+ /* We set the PIN only once since all URIs must have it the same. */
+ if (token_pin != NULL)
+ goto ok;
+
+ if (pk11_get_pin_caching_policy() == POLICY_MEMORY)
+ if ((token_pin = strdup(pin)) == NULL)
+ {
+ PK11err(PK11_F_CACHE_PIN, PK11_R_MALLOC_FAILURE);
+ goto err;
+ }
+ else
+ if (pk11_get_pin_caching_policy() == POLICY_MLOCKED_MEMORY)
+ {
+ if (mlock_pin_in_memory(pin) == 0)
+ goto err;
+ }
+
+ok:
+ (void) pthread_mutex_unlock(uri_lock);
+ return (1);
+err:
+ (void) pthread_mutex_unlock(uri_lock);
+ return (0);
+ }
+
+/*
+ * Cache the PIN in mlock(3C)ed memory. If mlock(3C) fails we will not resort to
+ * the normal memory caching.
+ *
+ * Note that this function must be called under the protection of the "uri_lock"
+ * mutex.
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+static int
+mlock_pin_in_memory(char *pin)
+ {
+ void *addr = NULL;
+ long pagesize = 0;
+
+ /* mlock(3C) locks pages so we need one whole page for the PIN. */
+ if ((pagesize = sysconf(_SC_PAGESIZE)) == -1)
+ {
+ PK11err(PK11_F_MLOCK_PIN_IN_MEMORY, PK11_R_SYSCONF_FAILED);
+ goto err;
+ }
+
+ /* This will ensure we have a page aligned pointer... */
+ if ((addr = mmap(0, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED)
+ {
+ PK11err(PK11_F_MLOCK_PIN_IN_MEMORY, PK11_R_MMAP_FAILED);
+ goto err;
+ }
+
+ /* ...because "addr" must be page aligned here. */
+ if (mlock(addr, pagesize) == -1)
+ {
+ /*
+ * Missing the PRIV_PROC_LOCK_MEMORY privilege might be a common
+ * problem so distinguish this situation from other issues.
+ */
+ if (errno == EPERM)
+ PK11err(PK11_F_MLOCK_PIN_IN_MEMORY,
+ PK11_R_PRIV_PROC_LOCK_MEMORY_MISSING);
+ else
+ PK11err(PK11_F_MLOCK_PIN_IN_MEMORY,
+ PK11_R_MLOCK_FAILED);
+
+ /*
+ * We already have a problem here so there is no need to check
+ * that we could unmap the page. The PIN is not there yet
+ * anyway.
+ */
+ (void) munmap(addr, pagesize);
+ goto err;
+ }
+
+ /* Copy the PIN to the mlocked memory. */
+ token_pin = (char *)addr;
+ strlcpy(token_pin, pin, PK11_MAX_PIN_LEN + 1);
+ return (1);
+err:
+ return (0);
+ }
+
+/*
+ * Log in to the keystore if we are supposed to do that at all. Take care of
+ * reading and caching the PIN etc. Log in only once even when called from
+ * multiple threads.
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int
+pk11_token_login(CK_SESSION_HANDLE session, CK_BBOOL *login_done,
+ pkcs11_uri *uri_struct, CK_BBOOL is_private)
+ {
+ CK_RV rv;
+
+ if ((pubkey_token_flags & CKF_TOKEN_INITIALIZED) == 0)
+ {
+ PK11err(PK11_F_TOKEN_LOGIN,
+ PK11_R_TOKEN_NOT_INITIALIZED);
+ goto err;
+ }
+
+ /*
+ * If login is required or needed but the PIN has not been even
+ * initialized we can bail out right now. Note that we are supposed to
+ * always log in if we are going to access private keys. However, we may
+ * need to log in even for accessing public keys in case that the
+ * CKF_LOGIN_REQUIRED flag is set.
+ */
+ if ((pubkey_token_flags & CKF_LOGIN_REQUIRED ||
+ is_private == CK_TRUE) && ~pubkey_token_flags &
+ CKF_USER_PIN_INITIALIZED)
+ {
+ PK11err(PK11_F_TOKEN_LOGIN, PK11_R_TOKEN_PIN_NOT_SET);
+ goto err;
+ }
+
+ /*
+ * Note on locking: it is possible that more than one thread gets into
+ * pk11_get_pin() so we must deal with that. We cannot avoid it since we
+ * cannot guard fork() in there with a lock because we could end up in
+ * a dead lock in the child. Why? Remember we are in a multithreaded
+ * environment so we must lock all mutexes in the prefork function to
+ * avoid a situation in which a thread that did not call fork() held a
+ * lock, making future unlocking impossible. We lock right before
+ * C_Login().
+ */
+ if (pubkey_token_flags & CKF_LOGIN_REQUIRED || is_private == CK_TRUE)
+ {
+ if (*login_done == CK_FALSE &&
+ uri_struct->askpass == NULL)
+ {
+ PK11err(PK11_F_TOKEN_LOGIN,
+ PK11_R_TOKEN_PIN_NOT_PROVIDED);
+ goto err;
+ }
+
+ if (*login_done == CK_FALSE &&
+ uri_struct->askpass != NULL)
+ {
+ if (pk11_get_pin(uri_struct->askpass,
+ &uri_struct->pin) == 0)
+ {
+ PK11err(PK11_F_TOKEN_LOGIN,
+ PK11_R_TOKEN_PIN_NOT_PROVIDED);
+ goto err;
+ }
+ }
+
+ /*
+ * Note that what we are logging into is the keystore from
+ * pubkey_SLOTID because we work with OP_RSA session type here.
+ * That also means that we can work with only one keystore in
+ * the engine.
+ *
+ * We must make sure we do not try to login more than once.
+ * Also, see the comment above on locking strategy.
+ */
+ (void) pthread_mutex_lock(uri_lock);
+ if (*login_done == CK_FALSE)
+ {
+ if ((rv = pFuncList->C_Login(session,
+ CKU_USER, (CK_UTF8CHAR*)uri_struct->pin,
+ strlen(uri_struct->pin))) != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_TOKEN_LOGIN,
+ PK11_R_TOKEN_LOGIN_FAILED, rv);
+ goto err_locked;
+ }
+
+ *login_done = CK_TRUE;
+
+ /*
+ * Cache the passphrasedialog for possible child (which
+ * would need to relogin).
+ */
+ if (passphrasedialog == NULL &&
+ uri_struct->askpass != NULL)
+ {
+ passphrasedialog =
+ strdup(uri_struct->askpass);
+
+ if (passphrasedialog == NULL)
+ {
+ PK11err_add_data(PK11_F_TOKEN_LOGIN,
+ PK11_R_MALLOC_FAILURE, rv);
+ goto err_locked;
+ }
+ }
+
+ /*
+ * Check the PIN caching policy. Note that user might
+ * have provided a PIN even when no PIN was required -
+ * in that case we always remove the PIN from memory.
+ */
+ if (pk11_get_pin_caching_policy() ==
+ POLICY_WRONG_VALUE)
+ {
+ PK11err(PK11_F_TOKEN_LOGIN,
+ PK11_R_PIN_CACHING_POLICY_INVALID);
+ goto err_locked;
+ }
+
+ if (pk11_get_pin_caching_policy() != POLICY_NONE)
+ if (pk11_cache_pin(uri_struct->pin) == 0)
+ goto err_locked;
+ }
+ (void) pthread_mutex_unlock(uri_lock);
+ }
+ else
+ {
+ /*
+ * If token does not require login we take it as the
+ * login was done.
+ */
+ *login_done = CK_TRUE;
+ }
+
+ /*
+ * If we raced at pk11_get_pin() we must make sure that all threads that
+ * called pk11_get_pin() will erase the PIN from memory, not just the
+ * one that called C_Login(). Note that if we were supposed to cache the
+ * PIN it was already cached by now so filling "uri_struct.pin" with
+ * zero bytes is always OK since pk11_cache_pin() makes a copy of it.
+ */
+ if (uri_struct->pin != NULL)
+ memset(uri_struct->pin, 0, strlen(uri_struct->pin));
+
+ return (1);
+
+err_locked:
+ (void) pthread_mutex_unlock(uri_lock);
+err:
+ /* Always get rid of the PIN. */
+ if (uri_struct->pin != NULL)
+ memset(uri_struct->pin, 0, strlen(uri_struct->pin));
+ return (0);
+ }
+
+/*
+ * Log in to the keystore in the child if we were logged in in the parent. There
+ * are similarities in the code with pk11_token_login() but still it is quite
+ * different so we need a separate function for this.
+ *
+ * Note that this function is called under the locked session mutex when fork is
+ * detected. That means that C_Login() will be called from the child just once.
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int
+pk11_token_relogin(CK_SESSION_HANDLE session)
+ {
+ CK_RV rv;
+
+ /*
+ * We are in the child so check if we should login to the token again.
+ * Note that it is enough to log in to the token through one session
+ * only, all already open and all future sessions can access the token
+ * then.
+ */
+ if (passphrasedialog != NULL)
+ {
+ char *pin = NULL;
+
+ /* If we cached the PIN then use it. */
+ if (token_pin != NULL)
+ pin = token_pin;
+ else if (pk11_get_pin(passphrasedialog, &pin) == 0)
+ goto err;
+
+ (void) pthread_mutex_lock(uri_lock);
+ if ((rv = pFuncList->C_Login(session, CKU_USER,
+ (CK_UTF8CHAR_PTR)pin, strlen(pin))) != CKR_OK)
+ {
+ PK11err_add_data(PK11_F_TOKEN_RELOGIN,
+ PK11_R_TOKEN_LOGIN_FAILED, rv);
+ (void) pthread_mutex_unlock(uri_lock);
+ goto err;
+ }
+ (void) pthread_mutex_unlock(uri_lock);
+
+ /* Forget the PIN now if we did not cache it before. */
+ if (pin != token_pin)
+ {
+ memset(pin, 0, strlen(pin));
+ OPENSSL_free(pin);
+ }
+ }
+
+ return (1);
+err:
+ return (0);
+ }
+
+/*
+ * This function forks and runs an external command. It would be nice if we
+ * could use popen(3C)/pclose(3C) for that but unfortunately we need to be able
+ * to get rid of the PIN from the memory. With p(open|close) function calls we
+ * cannot control the stdio's memory used for buffering and our tests showed
+ * that the PIN really stays there even after pclose().
+ *
+ * Returns:
+ * allocated buffer on success
+ * NULL on failure
+ */
+static char *
+run_askpass(char *dialog)
+ {
+ pid_t pid;
+ int n, p[2];
+ char *buf = NULL;
+
+ if (pipe(p) == -1)
+ {
+ PK11err(PK11_F_RUN_ASKPASS, PK11_R_PIPE_FAILED);
+ return (NULL);
+ }
+
+ switch (pid = fork())
+ {
+ case -1:
+ PK11err(PK11_F_RUN_ASKPASS, PK11_R_FORK_FAILED);
+ return (NULL);
+ /* child */
+ case 0:
+ /*
+ * This should make sure that dup2() will not fail on
+ * file descriptor shortage.
+ */
+ close(p[0]);
+ (void) dup2(p[1], 1);
+ close(p[1]);
+ /*
+ * Note that we cannot use PK11err() here since we are
+ * in the child. However, parent will get read() error
+ * so do not worry.
+ */
+ (void) execl(dialog, basename(dialog), NULL);
+ exit(1);
+ /* parent */
+ default:
+ /* +1 is for the terminating '\0' */
+ buf = (char *)OPENSSL_malloc(PK11_MAX_PIN_LEN + 1);
+ if (buf == NULL)
+ {
+ PK11err(PK11_F_RUN_ASKPASS,
+ PK11_R_MALLOC_FAILURE);
+ return (NULL);
+ }
+
+ close(p[1]);
+ n = read(p[0], buf, PK11_MAX_PIN_LEN);
+ if (n == -1 || n == 0)
+ {
+ PK11err(PK11_F_RUN_ASKPASS,
+ PK11_R_PIN_NOT_READ_FROM_COMMAND);
+ OPENSSL_free(buf);
+ return (NULL);
+ }
+ buf[n] = '\0';
+
+ (void) waitpid(pid, NULL, 0);
+ }
+
+ return (buf);
+ }
+
+#endif /* OPENSSL_NO_HW_PK11 */
+#endif /* OPENSSL_NO_HW */
diff --git a/openssl0.9.8/engines/pkcs11/hw_pk11_uri.h b/openssl0.9.8/engines/pkcs11/hw_pk11_uri.h
new file mode 100644
index 0000000..32edd0f
--- /dev/null
+++ b/openssl0.9.8/engines/pkcs11/hw_pk11_uri.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. 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
+ * the documentation and/or other materials provided with the
+ * 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.
+ */
+
+#ifndef HW_PK11_URI_H
+#define HW_PK11_URI_H
+
+#include <security/pkcs11t.h>
+
+/* PKCS#11 URI related prefixes and attributes. */
+#define PK11_URI_PREFIX "pkcs11:"
+#define FILE_URI_PREFIX "file://"
+#define PK11_TOKEN "token"
+#define PK11_MANUF "manuf"
+#define PK11_SERIAL "serial"
+#define PK11_MODEL "model"
+#define PK11_OBJECT "object"
+#define PK11_OBJECTTYPE "objecttype"
+#define PK11_ASKPASS "passphrasedialog"
+
+/* PIN caching policy. */
+#define POLICY_NOT_INITIALIZED 0
+#define POLICY_NONE 1
+#define POLICY_MEMORY 2
+#define POLICY_MLOCKED_MEMORY 3
+#define POLICY_WRONG_VALUE 4
+
+/*
+ * That's what getpassphrase(3c) supports.
+ */
+#define PK11_MAX_PIN_LEN 256
+
+/* Add new attributes of the PKCS#11 URI here. */
+typedef struct pkcs11_uri_struct {
+ char *object; /* object label, the only mandatory info */
+ char *objecttype; /* (private|public|cert), currently unused */
+ char *token; /* token label */
+ char *manuf; /* manufacturer label */
+ char *serial; /* serial number label */
+ char *model; /* model label */
+ char *askpass; /* full path to the command to get the PIN */
+ /* Not part of the PKCS11 URI itself. */
+ char *pin; /* token PIN */
+} pkcs11_uri;
+
+/* For URI processing. */
+extern pthread_mutex_t *uri_lock;
+
+int pk11_get_pin(char *dialog, char **pin);
+int pk11_get_pin_caching_policy(void);
+int pk11_process_pkcs11_uri(const char *uristr, pkcs11_uri *uri_struct,
+ const char **file);
+int pk11_check_token_attrs(pkcs11_uri *uri_struct);
+void pk11_free_pkcs11_uri(pkcs11_uri *uri_struct, CK_BBOOL free_uri_itself);
+int pk11_cache_pin(char *pin);
+int pk11_token_login(CK_SESSION_HANDLE session, CK_BBOOL *login_done,
+ pkcs11_uri *uri_struct, CK_BBOOL is_private);
+int pk11_token_relogin(CK_SESSION_HANDLE session);
+
+#endif /* HW_PK11_URI_H */
diff --git a/openssl0.9.8/openssl-header.p5m b/openssl0.9.8/openssl-header.p5m
new file mode 100644
index 0000000..329db66
--- /dev/null
+++ b/openssl0.9.8/openssl-header.p5m
@@ -0,0 +1,92 @@
+set name=pkg.fmri value=pkg:/library/openssl$(version-base)-headers@$(ips-version)
+set name=pkg.summary value="OpenSSL $(version-base) header files"
+set name=info.upstream-url value="$(home)"
+set name=info.source-url value="$(download)"
+
+license $(license-file) license=$(license)
+
+depend fmri=pkg:/library/openssl$(version-base)@$(ips-version) type=require
+depend fmri=pkg:/library/openssl$(version-base)@$(ips-version) type=incorporate
+
+dir path=usr
+dir path=usr/include
+
+# Wrapper for 32/64 bits:
+file wrapper-opensslconf.h path=usr/include/openssl/opensslconf.h
+file $(protodir.32)/usr/include/openssl/opensslconf.h path=usr/include/openssl/opensslconf.32.h
+file $(protodir.64)/usr/include/openssl/opensslconf.h path=usr/include/openssl/opensslconf.64.h
+
+file path=usr/include/openssl/aes.h
+file path=usr/include/openssl/asn1.h
+file path=usr/include/openssl/asn1_mac.h
+file path=usr/include/openssl/asn1t.h
+file path=usr/include/openssl/bio.h
+file path=usr/include/openssl/blowfish.h
+file path=usr/include/openssl/bn.h
+file path=usr/include/openssl/buffer.h
+file path=usr/include/openssl/cast.h
+file path=usr/include/openssl/comp.h
+file path=usr/include/openssl/conf.h
+file path=usr/include/openssl/conf_api.h
+file path=usr/include/openssl/crypto.h
+file path=usr/include/openssl/des.h
+file path=usr/include/openssl/des_old.h
+file path=usr/include/openssl/dh.h
+file path=usr/include/openssl/dsa.h
+file path=usr/include/openssl/dso.h
+file path=usr/include/openssl/dtls1.h
+file path=usr/include/openssl/e_os2.h
+file path=usr/include/openssl/ebcdic.h
+file path=usr/include/openssl/engine.h
+file path=usr/include/openssl/err.h
+file path=usr/include/openssl/evp.h
+file path=usr/include/openssl/hmac.h
+file path=usr/include/openssl/krb5_asn.h
+file path=usr/include/openssl/kssl.h
+file path=usr/include/openssl/lhash.h
+file path=usr/include/openssl/md2.h
+file path=usr/include/openssl/md4.h
+file path=usr/include/openssl/md5.h
+file path=usr/include/openssl/obj_mac.h
+file path=usr/include/openssl/objects.h
+file path=usr/include/openssl/ocsp.h
+file path=usr/include/openssl/opensslv.h
+file path=usr/include/openssl/ossl_typ.h
+file path=usr/include/openssl/pem.h
+file path=usr/include/openssl/pem2.h
+file path=usr/include/openssl/pkcs12.h
+file path=usr/include/openssl/pkcs7.h
+file path=usr/include/openssl/pq_compat.h
+file path=usr/include/openssl/pqueue.h
+file path=usr/include/openssl/rand.h
+file path=usr/include/openssl/rc2.h
+file path=usr/include/openssl/rc4.h
+file path=usr/include/openssl/ripemd.h
+file path=usr/include/openssl/rsa.h
+file path=usr/include/openssl/safestack.h
+file path=usr/include/openssl/sha.h
+file path=usr/include/openssl/ssl.h
+file path=usr/include/openssl/ssl2.h
+file path=usr/include/openssl/ssl23.h
+file path=usr/include/openssl/ssl3.h
+file path=usr/include/openssl/stack.h
+file path=usr/include/openssl/store.h
+file path=usr/include/openssl/symhacks.h
+file path=usr/include/openssl/tls1.h
+file path=usr/include/openssl/tmdiff.h
+file path=usr/include/openssl/txt_db.h
+file path=usr/include/openssl/ui.h
+file path=usr/include/openssl/ui_compat.h
+file path=usr/include/openssl/x509.h
+file path=usr/include/openssl/x509_vfy.h
+file path=usr/include/openssl/x509v3.h
+
+dir path=usr/lib/$(mach64)/pkgconfig
+file path=usr/lib/$(mach64)/pkgconfig/libcrypto.pc
+file path=usr/lib/$(mach64)/pkgconfig/libssl.pc
+file path=usr/lib/$(mach64)/pkgconfig/openssl.pc
+
+dir path=usr/lib/pkgconfig
+file path=usr/lib/pkgconfig/libcrypto.pc
+file path=usr/lib/pkgconfig/libssl.pc
+file path=usr/lib/pkgconfig/openssl.pc
diff --git a/openssl0.9.8/openssl.p5m b/openssl0.9.8/openssl.p5m
new file mode 100644
index 0000000..d9968f3
--- /dev/null
+++ b/openssl0.9.8/openssl.p5m
@@ -0,0 +1,44 @@
+set name=pkg.fmri value=pkg:/library/openssl$(version-base)@$(ips-version)
+set name=pkg.summary value="OpenSSL $(version-base) shared libraries"
+set name=pkg.description value="$(description)"
+set name=info.upstream-url value="$(home)"
+set name=info.source-url value="$(download)"
+
+license $(license-file) license=$(license)
+
+dir path=usr
+dir path=usr/lib
+dir path=usr/lib/openssl-$(version-base)
+dir path=usr/lib/openssl-$(version-base)/engines
+dir path=usr/lib/openssl-$(version-base)/engines/64
+
+file $(builddir.32)/engines/lib4758cca.so path=usr/lib/openssl-$(version-base)/engines/lib4758cca.so
+file $(builddir.32)/engines/libaep.so path=usr/lib/openssl-$(version-base)/engines/libaep.so
+file $(builddir.32)/engines/libatalla.so path=usr/lib/openssl-$(version-base)/engines/libatalla.so
+file $(builddir.32)/engines/libcapi.so path=usr/lib/openssl-$(version-base)/engines/libcapi.so
+file $(builddir.32)/engines/libchil.so path=usr/lib/openssl-$(version-base)/engines/libchil.so
+file $(builddir.32)/engines/libcswift.so path=usr/lib/openssl-$(version-base)/engines/libcswift.so
+file $(builddir.32)/engines/libdevcrypto.so path=usr/lib/openssl-$(version-base)/engines/libdevcrypto.so
+file $(builddir.32)/engines/libgmp.so path=usr/lib/openssl-$(version-base)/engines/libgmp.so
+file $(builddir.32)/engines/libnuron.so path=usr/lib/openssl-$(version-base)/engines/libnuron.so
+file $(builddir.32)/engines/libsureware.so path=usr/lib/openssl-$(version-base)/engines/libsureware.so
+file $(builddir.32)/engines/libubsec.so path=usr/lib/openssl-$(version-base)/engines/libubsec.so
+
+file path=usr/lib/libssl.so.0.9.8
+file path=usr/lib/libcrypto.so.0.9.8
+
+file $(builddir.64)/engines/lib4758cca.so path=usr/lib/openssl-$(version-base)/engines/64/lib4758cca.so
+file $(builddir.64)/engines/libaep.so path=usr/lib/openssl-$(version-base)/engines/64/libaep.so
+file $(builddir.64)/engines/libatalla.so path=usr/lib/openssl-$(version-base)/engines/64/libatalla.so
+file $(builddir.64)/engines/libcapi.so path=usr/lib/openssl-$(version-base)/engines/64/libcapi.so
+file $(builddir.64)/engines/libchil.so path=usr/lib/openssl-$(version-base)/engines/64/libchil.so
+file $(builddir.64)/engines/libcswift.so path=usr/lib/openssl-$(version-base)/engines/64/libcswift.so
+file $(builddir.64)/engines/libdevcrypto.so path=usr/lib/openssl-$(version-base)/engines/64/libdevcrypto.so
+file $(builddir.64)/engines/libgmp.so path=usr/lib/openssl-$(version-base)/engines/64/libgmp.so
+file $(builddir.64)/engines/libnuron.so path=usr/lib/openssl-$(version-base)/engines/64/libnuron.so
+file $(builddir.64)/engines/libsureware.so path=usr/lib/openssl-$(version-base)/engines/64/libsureware.so
+file $(builddir.64)/engines/libubsec.so path=usr/lib/openssl-$(version-base)/engines/64/libubsec.so
+
+file path=usr/lib/$(mach64)/libssl.so.0.9.8
+file path=usr/lib/$(mach64)/libcrypto.so.0.9.8
+
diff --git a/openssl0.9.8/patches/15-pkcs11_engine-0.9.8a.patch b/openssl0.9.8/patches/15-pkcs11_engine-0.9.8a.patch
new file mode 100644
index 0000000..59e11fe
--- /dev/null
+++ b/openssl0.9.8/patches/15-pkcs11_engine-0.9.8a.patch
@@ -0,0 +1,131 @@
+diff -ruN ../a/openssl-0.9.8o/Configure openssl-0.9.8o/Configure
+--- ../a/openssl-0.9.8o/Configure 2010-05-20 10:36:23.000000000 -0700
++++ openssl-0.9.8o/Configure 2010-09-22 18:32:18.922795700 -0700
+@@ -12,7 +12,7 @@
+
+ # see INSTALL for instructions.
+
+-my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [enable-montasm] [no-asm] [no-dso] [no-krb5] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]\n";
++my $usage="Usage: Configure --pk11-libname=PK11_LIB_LOCATION [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [enable-montasm] [no-asm] [no-dso] [no-krb5] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]\n";
+
+ # Options:
+ #
+@@ -21,6 +21,9 @@
+ # --prefix prefix for the OpenSSL include, lib and bin directories
+ # (Default: the OPENSSLDIR directory)
+ #
++# --pk11-libname PKCS#11 library name.
++# (Default: none)
++#
+ # --install_prefix Additional prefix for package builders (empty by
+ # default). This needn't be set in advance, you can
+ # just as well use "make INSTALL_PREFIX=/whatever install".
+@@ -587,6 +590,9 @@
+ my $idx_ranlib = $idx++;
+ my $idx_arflags = $idx++;
+
++# PKCS#11 engine patch
++my $pk11_libname="";
++
+ my $prefix="";
+ my $libdir="";
+ my $openssldir="";
+@@ -825,6 +831,10 @@
+ {
+ $flags.=$_." ";
+ }
++ elsif (/^--pk11-libname=(.*)$/)
++ {
++ $pk11_libname=$1;
++ }
+ elsif (/^--prefix=(.*)$/)
+ {
+ $prefix=$1;
+@@ -960,6 +970,13 @@
+ exit 0;
+ }
+
++if (! $pk11_libname)
++ {
++ print STDERR "You must set --pk11-libname for PKCS#11 library.\n";
++ print STDERR "See README.pkcs11 for more information.\n";
++ exit 1;
++ }
++
+ if ($target =~ m/^CygWin32(-.*)$/) {
+ $target = "Cygwin".$1;
+ }
+@@ -1126,6 +1143,8 @@
+ if ($flags ne "") { $cflags="$flags$cflags"; }
+ else { $no_user_cflags=1; }
+
++$cflags="-DPK11_LIB_LOCATION=\"$pk11_libname\" $cflags";
++
+ # Kerberos settings. The flavor must be provided from outside, either through
+ # the script "config" or manually.
+ if (!$no_krb5)
+@@ -1489,6 +1508,7 @@
+ s/^VERSION=.*/VERSION=$version/;
+ s/^MAJOR=.*/MAJOR=$major/;
+ s/^MINOR=.*/MINOR=$minor/;
++ s/^PK11_LIB_LOCATION=.*/PK11_LIB_LOCATION=$pk11_libname/;
+ s/^SHLIB_VERSION_NUMBER=.*/SHLIB_VERSION_NUMBER=$shlib_version_number/;
+ s/^SHLIB_VERSION_HISTORY=.*/SHLIB_VERSION_HISTORY=$shlib_version_history/;
+ s/^SHLIB_MAJOR=.*/SHLIB_MAJOR=$shlib_major/;
+diff -ruN ../a/openssl-0.9.8o/Makefile.org openssl-0.9.8o/Makefile.org
+--- ../a/openssl-0.9.8o/Makefile.org 2010-01-27 08:06:36.000000000 -0800
++++ openssl-0.9.8o/Makefile.org 2010-09-22 18:32:19.152576100 -0700
+@@ -26,6 +26,9 @@
+ INSTALL_PREFIX=
+ INSTALLTOP=/usr/local/ssl
+
++# You must set this through --pk11-libname configure option.
++PK11_LIB_LOCATION=
++
+ # Do not edit this manually. Use Configure --openssldir=DIR do change this!
+ OPENSSLDIR=/usr/local/ssl
+
+diff -ruN ../a/openssl-0.9.8o/crypto/engine/Makefile openssl-0.9.8o/crypto/engine/Makefile
+--- ../a/openssl-0.9.8o/crypto/engine/Makefile 2009-09-27 07:04:32.000000000 -0700
++++ openssl-0.9.8o/crypto/engine/Makefile 2010-09-22 18:32:19.109972600 -0700
+@@ -21,12 +21,14 @@
+ eng_table.c eng_pkey.c eng_fat.c eng_all.c \
+ tb_rsa.c tb_dsa.c tb_ecdsa.c tb_dh.c tb_ecdh.c tb_rand.c tb_store.c \
+ tb_cipher.c tb_digest.c \
+- eng_openssl.c eng_cnf.c eng_dyn.c eng_cryptodev.c eng_padlock.c
++ eng_openssl.c eng_cnf.c eng_dyn.c eng_cryptodev.c eng_padlock.c \
++ hw_pk11.c hw_pk11_pub.c hw_pk11_uri.c
+ LIBOBJ= eng_err.o eng_lib.o eng_list.o eng_init.o eng_ctrl.o \
+ eng_table.o eng_pkey.o eng_fat.o eng_all.o \
+ tb_rsa.o tb_dsa.o tb_ecdsa.o tb_dh.o tb_ecdh.o tb_rand.o tb_store.o \
+ tb_cipher.o tb_digest.o \
+- eng_openssl.o eng_cnf.o eng_dyn.o eng_cryptodev.o eng_padlock.o
++ eng_openssl.o eng_cnf.o eng_dyn.o eng_cryptodev.o eng_padlock.o \
++ hw_pk11.o hw_pk11_pub.o hw_pk11_uri.o
+
+ SRC= $(LIBSRC)
+
+diff -ruN ../a/openssl-0.9.8o/crypto/engine/eng_all.c openssl-0.9.8o/crypto/engine/eng_all.c
+--- ../a/openssl-0.9.8o/crypto/engine/eng_all.c 2010-02-28 16:30:11.000000000 -0800
++++ openssl-0.9.8o/crypto/engine/eng_all.c 2010-09-22 18:33:15.326949000 -0700
+@@ -72,6 +72,9 @@
+ ENGINE_load_padlock();
+ #endif
+ ENGINE_load_dynamic();
++#ifndef OPENSSL_NO_HW_PKCS11
++ ENGINE_load_pk11();
++#endif
+ #ifndef OPENSSL_NO_STATIC_ENGINE
+ #ifndef OPENSSL_NO_HW
+ #ifndef OPENSSL_NO_HW_4758_CCA
+diff -ruN ../a/openssl-0.9.8o/crypto/engine/engine.h openssl-0.9.8o/crypto/engine/engine.h
+--- ../a/openssl-0.9.8o/crypto/engine/engine.h 2010-02-09 06:18:15.000000000 -0800
++++ openssl-0.9.8o/crypto/engine/engine.h 2010-09-22 18:32:19.063758100 -0700
+@@ -337,6 +337,7 @@
+ void ENGINE_load_ubsec(void);
+ #endif
+ void ENGINE_load_cryptodev(void);
++void ENGINE_load_pk11(void);
+ void ENGINE_load_padlock(void);
+ void ENGINE_load_builtin_engines(void);
+ #ifdef OPENSSL_SYS_WIN32
diff --git a/openssl0.9.8/patches/28-enginesdir.patch b/openssl0.9.8/patches/28-enginesdir.patch
new file mode 100644
index 0000000..10a07aa
--- /dev/null
+++ b/openssl0.9.8/patches/28-enginesdir.patch
@@ -0,0 +1,59 @@
+--- openssl-0.9.8n/Configure 2010-04-19 17:45:39.421625300 -0700
++++ openssl-0.9.8n/Configure.new 2010-06-18 15:18:52.437417100 -0700
+@@ -20,6 +20,8 @@
+ # --prefix option is given; /usr/local/ssl otherwise)
+ # --prefix prefix for the OpenSSL include, lib and bin directories
+ # (Default: the OPENSSLDIR directory)
++# --enginesdir engines shared library location
++# (Default: $prefix/lib/engines)
+ #
+ # --pk11-libname PKCS#11 library name.
+ # (Default: none)
+@@ -607,6 +609,7 @@
+ my $prefix="";
+ my $libdir="";
+ my $openssldir="";
++my $enginesdir="";
+ my $exe_ext="";
+ my $install_prefix= "$ENV{'INSTALL_PREFIX'}";
+ my $cross_compile_prefix="";
+@@ -858,6 +861,10 @@
+ {
+ $openssldir=$1;
+ }
++ elsif (/^--enginesdir=(.*)$/)
++ {
++ $enginesdir=$1;
++ }
+ elsif (/^--install.prefix=(.*)$/)
+ {
+ $install_prefix=$1;
+@@ -1125,8 +1132,16 @@
+ }
+ $prefix=$openssldir if $prefix eq "";
+
++if ($enginesdir eq "")
++ {
++ $enginesdir = "$prefix/lib/engines";
++ }
++
+ $libdir="lib" if $libdir eq "";
+
++
++
++
+ $default_ranlib= &which("ranlib") or $default_ranlib="true";
+ $perl=$ENV{'PERL'} or $perl=&which("perl5") or $perl=&which("perl")
+ or $perl="perl";
+@@ -1724,10 +1739,7 @@
+ }
+ elsif (/^#define\s+ENGINESDIR/)
+ {
+- # $foo is to become "$prefix/lib$multilib/engines";
+- # as Makefile.org and engines/Makefile are adapted for
+- # $multilib suffix.
+- my $foo = "$prefix/lib/engines";
++ my $foo = $enginesdir;
+ $foo =~ s/\\/\\\\/g;
+ print OUT "#define ENGINESDIR \"$foo\"\n";
+ }
diff --git a/openssl0.9.8/patches/29-devcrypto_engine.patch b/openssl0.9.8/patches/29-devcrypto_engine.patch
new file mode 100644
index 0000000..57efc17
--- /dev/null
+++ b/openssl0.9.8/patches/29-devcrypto_engine.patch
@@ -0,0 +1,52 @@
+diff -ruN ../a/openssl-0.9.8o/engines/Makefile openssl-0.9.8o/engines/Makefile
+--- ../a/openssl-0.9.8o/engines/Makefile 2009-11-09 17:53:02.000000000 -0800
++++ openssl-0.9.8o/engines/Makefile 2010-07-23 17:36:14.456537100 -0700
+@@ -20,7 +20,8 @@
+ APPS=
+
+ LIB=$(TOP)/libcrypto.a
+-LIBNAMES= 4758cca aep atalla cswift gmp chil nuron sureware ubsec capi
++LIBNAMES= 4758cca aep atalla cswift gmp chil nuron sureware ubsec capi \
++ devcrypto
+
+ LIBSRC= e_4758cca.c \
+ e_aep.c \
+@@ -31,7 +32,8 @@
+ e_nuron.c \
+ e_sureware.c \
+ e_ubsec.c \
+- e_capi.c
++ e_capi.c \
++ e_devcrypto.c
+ LIBOBJ= e_4758cca.o \
+ e_aep.o \
+ e_atalla.o \
+@@ -41,7 +43,8 @@
+ e_nuron.o \
+ e_sureware.o \
+ e_ubsec.o \
+- e_capi.o
++ e_capi.o \
++ e_devcrypto.o
+
+ SRC= $(LIBSRC)
+
+@@ -55,7 +58,8 @@
+ e_nuron_err.c e_nuron_err.h \
+ e_sureware_err.c e_sureware_err.h \
+ e_ubsec_err.c e_ubsec_err.h \
+- e_capi_err.c e_capi_err.h
++ e_capi_err.c e_capi_err.h \
++ e_devcrypto_err.c e_devcrypto_err.h
+
+ ALL= $(GENERAL) $(SRC) $(HEADER)
+
+@@ -70,7 +74,7 @@
+ for l in $(LIBNAMES); do \
+ $(MAKE) -f ../Makefile.shared -e \
+ LIBNAME=$$l LIBEXTRAS=e_$$l.o \
+- LIBDEPS='-L.. -lcrypto $(EX_LIBS)' \
++ LIBDEPS='-L.. -lcrypto -lcryptoutil $(EX_LIBS)' \
+ link_o.$(SHLIB_TARGET); \
+ done; \
+ else \
diff --git a/openssl0.9.8/patches/CVE-2010-2939.patch b/openssl0.9.8/patches/CVE-2010-2939.patch
new file mode 100644
index 0000000..2307326
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2010-2939.patch
@@ -0,0 +1,12 @@
+Index: openssl-0.9.8o/ssl/s3_clnt.c
+===================================================================
+--- openssl-0.9.8o.orig/ssl/s3_clnt.c 2010-01-26 19:40:36.000000000 +0000
++++ openssl-0.9.8o/ssl/s3_clnt.c 2010-08-26 16:45:11.000000000 +0000
+@@ -1377,6 +1377,7 @@
+ s->session->sess_cert->peer_ecdh_tmp=ecdh;
+ ecdh=NULL;
+ BN_CTX_free(bn_ctx);
++ bn_ctx = NULL;
+ EC_POINT_free(srvr_ecpoint);
+ srvr_ecpoint = NULL;
+ }
diff --git a/openssl0.9.8/patches/CVE-2010-3864.patch b/openssl0.9.8/patches/CVE-2010-3864.patch
new file mode 100644
index 0000000..c2b2f7b
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2010-3864.patch
@@ -0,0 +1,45 @@
+Index: ssl/t1_lib.c
+===================================================================
+RCS file: /v/openssl/cvs/openssl/ssl/t1_lib.c,v
+retrieving revision 1.13.2.27
+diff -u -r1.13.2.27 t1_lib.c
+--- openssl/ssl/t1_lib.c 12 Jun 2010 13:18:58 -0000 1.13.2.27
++++ openssl/ssl/t1_lib.c 3 Nov 2010 23:44:54 -0000
+@@ -432,14 +432,23 @@
+ switch (servname_type)
+ {
+ case TLSEXT_NAMETYPE_host_name:
+- if (s->session->tlsext_hostname == NULL)
++ if (!s->hit)
+ {
+- if (len > TLSEXT_MAXLEN_host_name ||
+- ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL))
++ if(s->session->tlsext_hostname)
++ {
++ *al = SSL_AD_DECODE_ERROR;
++ return 0;
++ }
++ if (len > TLSEXT_MAXLEN_host_name)
+ {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
++ if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
++ {
++ *al = TLS1_AD_INTERNAL_ERROR;
++ return 0;
++ }
+ memcpy(s->session->tlsext_hostname, sdata, len);
+ s->session->tlsext_hostname[len]='\0';
+ if (strlen(s->session->tlsext_hostname) != len) {
+@@ -452,7 +461,8 @@
+
+ }
+ else
+- s->servername_done = strlen(s->session->tlsext_hostname) == len
++ s->servername_done = s->session->tlsext_hostname
++ && strlen(s->session->tlsext_hostname) == len
+ && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
+
+ break;
+
diff --git a/openssl0.9.8/patches/CVE-2010-4180.patch b/openssl0.9.8/patches/CVE-2010-4180.patch
new file mode 100644
index 0000000..019a780
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2010-4180.patch
@@ -0,0 +1,63 @@
+diff --git a/doc/ssl/SSL_CTX_set_options.pod b/doc/ssl/SSL_CTX_set_options.pod
+index 06025d1..a703ce0 100644
+--- a/doc/ssl/SSL_CTX_set_options.pod
++++ b/doc/ssl/SSL_CTX_set_options.pod
+@@ -78,18 +78,7 @@ this breaks this server so 16 bytes is the way to go.
+
+ =item SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+
+-ssl3.netscape.com:443, first a connection is established with RC4-MD5.
+-If it is then resumed, we end up using DES-CBC3-SHA. It should be
+-RC4-MD5 according to 7.6.1.3, 'cipher_suite'.
+-
+-Netscape-Enterprise/2.01 (https://merchant.netscape.com) has this bug.
+-It only really shows up when connecting via SSLv2/v3 then reconnecting
+-via SSLv3. The cipher list changes....
+-
+-NEW INFORMATION. Try connecting with a cipher list of just
+-DES-CBC-SHA:RC4-MD5. For some weird reason, each new connection uses
+-RC4-MD5, but a re-connect tries to use DES-CBC-SHA. So netscape, when
+-doing a re-connect, always takes the first cipher in the cipher list.
++As of OpenSSL 0.9.8q and 1.0.0c, this option has no effect.
+
+ =item SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+
+diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
+index f0995b9..a7cb7a1 100644
+--- a/ssl/s3_clnt.c
++++ b/ssl/s3_clnt.c
+@@ -814,8 +814,11 @@ int ssl3_get_server_hello(SSL *s)
+ s->session->cipher_id = s->session->cipher->id;
+ if (s->hit && (s->session->cipher_id != c->id))
+ {
++/* Workaround is now obsolete */
++#if 0
+ if (!(s->options &
+ SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
++#endif
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
+index e696450..e2d570f 100644
+--- a/ssl/s3_srvr.c
++++ b/ssl/s3_srvr.c
+@@ -927,6 +927,10 @@ int ssl3_get_client_hello(SSL *s)
+ break;
+ }
+ }
++/* Disabled because it can be used in a ciphersuite downgrade
++ * attack: CVE-2010-4180.
++ */
++#if 0
+ if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
+ {
+ /* Special case as client bug workaround: the previously used cipher may
+@@ -941,6 +945,7 @@ int ssl3_get_client_hello(SSL *s)
+ j = 1;
+ }
+ }
++#endif
+ if (j == 0)
+ {
+ /* we need to have the cipher in the cipher
diff --git a/openssl0.9.8/patches/CVE-2011-0014.patch b/openssl0.9.8/patches/CVE-2011-0014.patch
new file mode 100644
index 0000000..65c8e4b
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2011-0014.patch
@@ -0,0 +1,27 @@
+--- a/ssl/t1_lib.c 25 Nov 2010 12:28:28 -0000 1.64.2.17
++++ b/ssl/t1_lib.c 8 Feb 2011 00:00:00 -0000
+@@ -917,6 +917,7 @@
+ }
+ n2s(data, idsize);
+ dsize -= 2 + idsize;
++ size -= 2 + idsize;
+ if (dsize < 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+@@ -955,9 +956,14 @@
+ }
+
+ /* Read in request_extensions */
++ if (size < 2)
++ {
++ *al = SSL_AD_DECODE_ERROR;
++ return 0;
++ }
+ n2s(data,dsize);
+ size -= 2;
+- if (dsize > size)
++ if (dsize != size)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+
diff --git a/openssl0.9.8/patches/CVE-2011-1945.patch b/openssl0.9.8/patches/CVE-2011-1945.patch
new file mode 100644
index 0000000..c15dc80
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2011-1945.patch
@@ -0,0 +1,23 @@
+Description: Fix CVE-2011-1945, timing attacks against ECDHE_ECDSA makes
+ it easier to determine private keys.
+Origin: http://cvs.openssl.org/chngview?cn=20892
+
+Index: openssl-0.9.8o/crypto/ecdsa/ecs_ossl.c
+===================================================================
+--- openssl-0.9.8o.orig/crypto/ecdsa/ecs_ossl.c
++++ openssl-0.9.8o/crypto/ecdsa/ecs_ossl.c
+@@ -144,6 +144,14 @@ static int ecdsa_sign_setup(EC_KEY *ecke
+ }
+ while (BN_is_zero(k));
+
++ /* We do not want timing information to leak the length of k,
++ * so we compute G*k using an equivalent scalar of fixed
++ * bit-length. */
++
++ if (!BN_add(k, k, order)) goto err;
++ if (BN_num_bits(k) <= BN_num_bits(order))
++ if (!BN_add(k, k, order)) goto err;
++
+ /* compute r the x-coordinate of generator * k */
+ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx))
+ {
diff --git a/openssl0.9.8/patches/CVE-2011-4109.patch b/openssl0.9.8/patches/CVE-2011-4109.patch
new file mode 100644
index 0000000..b602938
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2011-4109.patch
@@ -0,0 +1,60 @@
+diff --git a/crypto/x509v3/pcy_map.c b/crypto/x509v3/pcy_map.c
+index f28796e..acd2ede 100644
+--- a/crypto/x509v3/pcy_map.c
++++ b/crypto/x509v3/pcy_map.c
+@@ -70,8 +70,6 @@ static int ref_cmp(const X509_POLICY_REF * const *a,
+
+ static void policy_map_free(X509_POLICY_REF *map)
+ {
+- if (map->subjectDomainPolicy)
+- ASN1_OBJECT_free(map->subjectDomainPolicy);
+ OPENSSL_free(map);
+ }
+
+@@ -95,6 +93,7 @@ int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps)
+ {
+ POLICY_MAPPING *map;
+ X509_POLICY_REF *ref = NULL;
++ ASN1_OBJECT *subjectDomainPolicyRef;
+ X509_POLICY_DATA *data;
+ X509_POLICY_CACHE *cache = x->policy_cache;
+ int i;
+@@ -153,13 +152,16 @@ int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps)
+ if (!sk_ASN1_OBJECT_push(data->expected_policy_set,
+ map->subjectDomainPolicy))
+ goto bad_mapping;
++ /* map->subjectDomainPolicy will be freed when
++ * cache->data is freed. Set it to NULL to avoid double-free. */
++ subjectDomainPolicyRef = map->subjectDomainPolicy;
++ map->subjectDomainPolicy = NULL;
+
+ ref = OPENSSL_malloc(sizeof(X509_POLICY_REF));
+ if (!ref)
+ goto bad_mapping;
+
+- ref->subjectDomainPolicy = map->subjectDomainPolicy;
+- map->subjectDomainPolicy = NULL;
++ ref->subjectDomainPolicy = subjectDomainPolicyRef;
+ ref->data = data;
+
+ if (!sk_X509_POLICY_REF_push(cache->maps, ref))
+diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c
+index 89f84bf..92ad0a2 100644
+--- a/crypto/x509v3/pcy_tree.c
++++ b/crypto/x509v3/pcy_tree.c
+@@ -612,6 +612,10 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+ case 2:
+ return 1;
+
++ /* Some internal error */
++ case -1:
++ return -1;
++
+ /* Some internal error */
+ case 0:
+ return 0;
+@@ -691,4 +695,3 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+ return 0;
+
+ }
+-
diff --git a/openssl0.9.8/patches/CVE-2011-4576.patch b/openssl0.9.8/patches/CVE-2011-4576.patch
new file mode 100644
index 0000000..7e65fda
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2011-4576.patch
@@ -0,0 +1,14 @@
+diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
+index 1539a4c..759231d 100644
+--- a/ssl/s3_enc.c
++++ b/ssl/s3_enc.c
+@@ -479,6 +479,9 @@ int ssl3_enc(SSL *s, int send)
+
+ /* we need to add 'i-1' padding bytes */
+ l+=i;
++ /* the last of these zero bytes will be overwritten
++ * with the padding length. */
++ memset(&rec->input[rec->length], 0, i);
+ rec->length+=i;
+ rec->input[l-1]=(i-1);
+ }
diff --git a/openssl0.9.8/patches/CVE-2011-4619.patch b/openssl0.9.8/patches/CVE-2011-4619.patch
new file mode 100644
index 0000000..9e51777
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2011-4619.patch
@@ -0,0 +1,104 @@
+Index: openssl-0.9.8o/ssl/s3_srvr.c
+===================================================================
+--- openssl-0.9.8o.orig/ssl/s3_srvr.c 2012-03-13 21:44:39.000000000 +0100
++++ openssl-0.9.8o/ssl/s3_srvr.c 2012-03-13 21:44:42.000000000 +0100
+@@ -235,6 +235,7 @@
+ }
+
+ s->init_num=0;
++ s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
+
+ if (s->state != SSL_ST_RENEGOTIATE)
+ {
+@@ -709,6 +710,13 @@
+ s->s3->tmp.reuse_message = 1;
+ if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
+ {
++ /* We only allow the client to restart the handshake once per
++ * negotiation. */
++ if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
++ {
++ SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
++ return -1;
++ }
+ /* Throw away what we have done so far in the current handshake,
+ * which will now be aborted. (A full SSL_clear would be too much.) */
+ #ifndef OPENSSL_NO_DH
+@@ -725,6 +733,7 @@
+ s->s3->tmp.ecdh = NULL;
+ }
+ #endif
++ s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
+ return 2;
+ }
+ return 1;
+Index: openssl-0.9.8o/ssl/ssl.h
+===================================================================
+--- openssl-0.9.8o.orig/ssl/ssl.h 2012-03-13 21:44:39.000000000 +0100
++++ openssl-0.9.8o/ssl/ssl.h 2012-03-13 21:44:42.000000000 +0100
+@@ -1739,6 +1739,7 @@
+ #define SSL_F_SSL3_CALLBACK_CTRL 233
+ #define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
+ #define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
++#define SSL_F_SSL3_CHECK_CLIENT_HELLO 292
+ #define SSL_F_SSL3_CLIENT_HELLO 131
+ #define SSL_F_SSL3_CONNECT 132
+ #define SSL_F_SSL3_CTRL 213
+@@ -1974,6 +1975,7 @@
+ #define SSL_R_MISSING_TMP_RSA_KEY 172
+ #define SSL_R_MISSING_TMP_RSA_PKEY 173
+ #define SSL_R_MISSING_VERIFY_MESSAGE 174
++#define SSL_R_MULTIPLE_SGC_RESTARTS 325
+ #define SSL_R_NON_SSLV2_INITIAL_PACKET 175
+ #define SSL_R_NO_CERTIFICATES_RETURNED 176
+ #define SSL_R_NO_CERTIFICATE_ASSIGNED 177
+Index: openssl-0.9.8o/ssl/ssl3.h
+===================================================================
+--- openssl-0.9.8o.orig/ssl/ssl3.h 2012-03-13 21:44:39.000000000 +0100
++++ openssl-0.9.8o/ssl/ssl3.h 2012-03-13 21:44:42.000000000 +0100
+@@ -333,6 +333,17 @@
+ #define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002
+ #define SSL3_FLAGS_POP_BUFFER 0x0004
+ #define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
++
++/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
++ * restart a handshake because of MS SGC and so prevents us
++ * from restarting the handshake in a loop. It's reset on a
++ * renegotiation, so effectively limits the client to one restart
++ * per negotiation. This limits the possibility of a DDoS
++ * attack where the client handshakes in a loop using SGC to
++ * restart. Servers which permit renegotiation can still be
++ * effected, but we can't prevent that.
++ */
++#define SSL3_FLAGS_SGC_RESTART_DONE 0x0040
+
+ typedef struct ssl3_state_st
+ {
+Index: openssl-0.9.8o/ssl/ssl_err.c
+===================================================================
+--- openssl-0.9.8o.orig/ssl/ssl_err.c 2012-03-13 21:44:39.000000000 +0100
++++ openssl-0.9.8o/ssl/ssl_err.c 2012-03-13 21:44:42.000000000 +0100
+@@ -1,6 +1,6 @@
+ /* ssl/ssl_err.c */
+ /* ====================================================================
+- * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved.
++ * Copyright (c) 1999-2011 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
+@@ -137,6 +137,7 @@
+ {ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "SSL3_CALLBACK_CTRL"},
+ {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "SSL3_CHANGE_CIPHER_STATE"},
+ {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM), "SSL3_CHECK_CERT_AND_ALGORITHM"},
++{ERR_FUNC(SSL_F_SSL3_CHECK_CLIENT_HELLO), "SSL3_CHECK_CLIENT_HELLO"},
+ {ERR_FUNC(SSL_F_SSL3_CLIENT_HELLO), "SSL3_CLIENT_HELLO"},
+ {ERR_FUNC(SSL_F_SSL3_CONNECT), "SSL3_CONNECT"},
+ {ERR_FUNC(SSL_F_SSL3_CTRL), "SSL3_CTRL"},
+@@ -375,6 +376,7 @@
+ {ERR_REASON(SSL_R_MISSING_TMP_RSA_KEY) ,"missing tmp rsa key"},
+ {ERR_REASON(SSL_R_MISSING_TMP_RSA_PKEY) ,"missing tmp rsa pkey"},
+ {ERR_REASON(SSL_R_MISSING_VERIFY_MESSAGE),"missing verify message"},
++{ERR_REASON(SSL_R_MULTIPLE_SGC_RESTARTS) ,"multiple sgc restarts"},
+ {ERR_REASON(SSL_R_NON_SSLV2_INITIAL_PACKET),"non sslv2 initial packet"},
+ {ERR_REASON(SSL_R_NO_CERTIFICATES_RETURNED),"no certificates returned"},
+ {ERR_REASON(SSL_R_NO_CERTIFICATE_ASSIGNED),"no certificate assigned"},
diff --git a/openssl0.9.8/patches/CVE-2012-1165.patch b/openssl0.9.8/patches/CVE-2012-1165.patch
new file mode 100644
index 0000000..7abc720
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2012-1165.patch
@@ -0,0 +1,22 @@
+Index: openssl-0.9.8o/crypto/asn1/asn_mime.c
+===================================================================
+--- openssl-0.9.8o.orig/crypto/asn1/asn_mime.c 2009-03-08 23:05:34.000000000 +0000
++++ openssl-0.9.8o/crypto/asn1/asn_mime.c 2012-03-17 15:09:03.000000000 +0000
+@@ -790,12 +790,17 @@
+ static int mime_hdr_cmp(const MIME_HEADER * const *a,
+ const MIME_HEADER * const *b)
+ {
++ if (!(*a)->name || !(*b)->name)
++ return !!(*a)->name - !!(*b)->name;
++
+ return(strcmp((*a)->name, (*b)->name));
+ }
+
+ static int mime_param_cmp(const MIME_PARAM * const *a,
+ const MIME_PARAM * const *b)
+ {
++ if (!(*a)->param_name || !(*b)->param_name)
++ return !!(*a)->param_name - !!(*b)->param_name;
+ return(strcmp((*a)->param_name, (*b)->param_name));
+ }
+
diff --git a/openssl0.9.8/patches/CVE-2012-2131.patch b/openssl0.9.8/patches/CVE-2012-2131.patch
new file mode 100644
index 0000000..565467c
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2012-2131.patch
@@ -0,0 +1,28 @@
+Index: openssl-0.9.8o/crypto/buffer/buffer.c
+===================================================================
+--- openssl-0.9.8o.orig/crypto/buffer/buffer.c
++++ openssl-0.9.8o/crypto/buffer/buffer.c
+@@ -99,6 +99,11 @@ int BUF_MEM_grow(BUF_MEM *str, int len)
+ char *ret;
+ unsigned int n;
+
++ if (len < 0)
++ {
++ BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
+ if (str->length >= len)
+ {
+ str->length=len;
+@@ -141,6 +146,11 @@ int BUF_MEM_grow_clean(BUF_MEM *str, int
+ char *ret;
+ unsigned int n;
+
++ if (len < 0)
++ {
++ BUFerr(BUF_F_BUF_MEM_GROW_CLEAN,ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
+ if (str->length >= len)
+ {
+ memset(&str->data[len],0,str->length-len);
diff --git a/openssl0.9.8/patches/CVE-2012-2333.patch b/openssl0.9.8/patches/CVE-2012-2333.patch
new file mode 100644
index 0000000..2476ee3
--- /dev/null
+++ b/openssl0.9.8/patches/CVE-2012-2333.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8o/ssl/d1_enc.c
+===================================================================
+--- openssl-0.9.8o.orig/ssl/d1_enc.c
++++ openssl-0.9.8o/ssl/d1_enc.c
+@@ -257,7 +257,7 @@ int dtls1_enc(SSL *s, int send)
+ }
+ /* TLS 1.0 does not bound the number of padding bytes by the block size.
+ * All of them must have value 'padding_length'. */
+- if (i > (int)rec->length)
++ if (i + bs > (int)rec->length)
+ {
+ /* Incorrect padding. SSLerr() and ssl3_alert are done
+ * by caller: we don't want to reveal whether this is
diff --git a/openssl0.9.8/patches/block_diginotar.patch b/openssl0.9.8/patches/block_diginotar.patch
new file mode 100644
index 0000000..b9f8bad
--- /dev/null
+++ b/openssl0.9.8/patches/block_diginotar.patch
@@ -0,0 +1,59 @@
+From: Raphael Geissert <geissert@debian.org>
+Description: make X509_verify_cert indicate that any certificate whose
+ name contains "DigiNotar" is revoked.
+Origin: vendor
+Forwarded: not-needed
+Last-Update: 2011-09-07
+Bug: http://bugs.debian.org/639744
+
+diff -urpN openssl-0.9.8o-4squeeze1.orig/crypto/x509/x509_vfy.c openssl-0.9.8o-4squeeze1/crypto/x509/x509_vfy.c
+--- openssl-0.9.8o-4squeeze1.orig/crypto/x509/x509_vfy.c 2009-06-26 06:34:21.000000000 -0500
++++ openssl-0.9.8o-4squeeze1/crypto/x509/x509_vfy.c 2011-09-07 21:23:58.000000000 -0500
+@@ -78,6 +78,7 @@ static int check_trust(X509_STORE_CTX *c
+ static int check_revocation(X509_STORE_CTX *ctx);
+ static int check_cert(X509_STORE_CTX *ctx);
+ static int check_policy(X509_STORE_CTX *ctx);
++static int check_ca_blacklist(X509_STORE_CTX *ctx);
+ static int internal_verify(X509_STORE_CTX *ctx);
+ const char X509_version[]="X.509" OPENSSL_VERSION_PTEXT;
+
+@@ -312,6 +313,9 @@ int X509_verify_cert(X509_STORE_CTX *ctx
+ ok=internal_verify(ctx);
+ if(!ok) goto end;
+
++ ok = check_ca_blacklist(ctx);
++ if(!ok) goto end;
++
+ #ifndef OPENSSL_NO_RFC3779
+ /* RFC 3779 path validation, now that CRL check has been done */
+ ok = v3_asid_validate_path(ctx);
+@@ -661,6 +665,29 @@ static int check_crl_time(X509_STORE_CTX
+ return 1;
+ }
+
++static int check_ca_blacklist(X509_STORE_CTX *ctx)
++ {
++ X509 *x;
++ int i;
++ /* Check all certificates against the blacklist */
++ for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--)
++ {
++ x = sk_X509_value(ctx->chain, i);
++ /* Mark DigiNotar certificates as revoked, no matter
++ * where in the chain they are.
++ */
++ if (x->name && strstr(x->name, "DigiNotar"))
++ {
++ ctx->error = X509_V_ERR_CERT_REVOKED;
++ ctx->error_depth = i;
++ ctx->current_cert = x;
++ if (!ctx->verify_cb(0,ctx))
++ return 0;
++ }
++ }
++ return 1;
++ }
++
+ /* Lookup CRLs from the supplied list. Look for matching isser name
+ * and validity. If we can't find a valid CRL return the last one
+ * with matching name. This gives more meaningful error codes. Otherwise
diff --git a/openssl0.9.8/patches/ca.patch b/openssl0.9.8/patches/ca.patch
new file mode 100644
index 0000000..761eebe
--- /dev/null
+++ b/openssl0.9.8/patches/ca.patch
@@ -0,0 +1,20 @@
+Index: openssl-0.9.8m/apps/CA.pl.in
+===================================================================
+--- openssl-0.9.8m.orig/apps/CA.pl.in 2006-04-28 00:28:51.000000000 +0000
++++ openssl-0.9.8m/apps/CA.pl.in 2010-02-27 00:36:51.000000000 +0000
+@@ -65,6 +65,7 @@
+ foreach (@ARGV) {
+ if ( /^(-\?|-h|-help)$/ ) {
+ print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
++ print STDERR "usage: CA -signcert certfile keyfile|-newcert|-newreq|-newca|-sign|-verify\n";
+ exit 0;
+ } elsif (/^-newcert$/) {
+ # create a certificate
+@@ -165,6 +166,7 @@
+ } else {
+ print STDERR "Unknown arg $_\n";
+ print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
++ print STDERR "usage: CA -signcert certfile keyfile|-newcert|-newreq|-newca|-sign|-verify\n";
+ exit 1;
+ }
+ }
diff --git a/openssl0.9.8/patches/debian-targets.patch b/openssl0.9.8/patches/debian-targets.patch
new file mode 100644
index 0000000..988a789
--- /dev/null
+++ b/openssl0.9.8/patches/debian-targets.patch
@@ -0,0 +1,56 @@
+Index: openssl-0.9.8k/Configure
+===================================================================
+--- openssl-0.9.8k.orig/Configure 2009-12-09 16:09:41.000000000 +0000
++++ openssl-0.9.8k/Configure 2009-12-09 16:09:55.000000000 +0000
+@@ -320,6 +320,51 @@
+ "osf1-alpha-cc", "cc:-std1 -tune host -O4 -readonly_strings::(unknown):::SIXTY_FOUR_BIT_LONG RC4_CHUNK:${no_asm}:dlfcn:alpha-osf1-shared:::.so",
+ "tru64-alpha-cc", "cc:-std1 -tune host -fast -readonly_strings::-pthread:::SIXTY_FOUR_BIT_LONG RC4_CHUNK:${no_asm}:dlfcn:alpha-osf1-shared::-msym:.so",
+
++# Debian GNU/* (various architectures)
++"debian-alpha","gcc:-DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-alpha-ev4","gcc:-DTERMIO -O3 -Wa,--noexecstack -mcpu=ev4 -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-alpha-ev5","gcc:-DTERMIO -O3 -Wa,--noexecstack -mcpu=ev5 -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-arm","gcc:-DL_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armeb","gcc:-DB_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armel","gcc:-DL_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armhf","gcc:-DL_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++#"debian-amd64","gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -fomit-frame-pointer -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-amd64", "gcc:-m64 -DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall -DMD32_REG_T=int::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK RC4_CHAR BF_PTR2 DES_INT DES_UNROLL:${x86_64_asm_linux}:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-avr32", "gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -fomit-frame-pointer -g -Wall::-D_REENTRANT::-ldl:BN_LLONG_BF_PTR::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-kfreebsd-amd64","gcc:-m64 -DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -Wall -DMD32_REG_T=int::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK BF_PTR2 DES_INT DES_UNROLL:${x86_64_asm}:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++#"debian-freebsd-alpha","gcc:-DTERMIOS -O -Wa,--noexecstack -fomit-frame-pointer -g -Wall::(unknown):::SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_PTR DES_RISC2::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-kfreebsd-i386","gcc:-DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -march=i486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-hppa","gcc:-DB_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-hurd-i386","gcc:-DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -mtune=i486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-ia64","gcc:-DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK RC4_CHAR:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++#"debian-i386","gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -fomit-frame-pointer -m486 -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::dlfcn:linux-shared:-fPIC",
++"debian-i386","gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i486","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i486 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i586","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i586 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i686/cmov","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i686 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-m68k","gcc:-DB_ENDIAN -DTERMIO -O2 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-mips", "gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-mipsel", "gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -m486 -Wall::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-m68k", "gcc:-DB_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -Wall::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL::::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-sparc", "gcc:-DB_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -mv8 -Wall::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL::::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-alpha","gcc:-DTERMIOS -O3 -Wa,--noexecstack -g::(unknown):::SIXTY_FOUR_BIT_LONG DES_INT DES_PTR DES_RISC2::::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -m486::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_out_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-mips","gcc:-O2 -Wa,--noexecstack -g -DL_ENDIAN::(unknown)::BN_LLONG MD2_CHAR RC4_INDEX RC4_CHAR DES_UNROLL DES_RISC2 DES_PTR BF_PTR:::::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-powerpc","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_UNROLL DES_RISC2 DES_PTR MD2_CHAR RC4_INDEX::linux_ppc32.o::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-powerpcspe","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_UNROLL DES_RISC2 DES_PTR MD2_CHAR RC4_INDEX::linux_ppc32.o::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-ppc64","gcc:-m64 -DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL::linux_ppc64.o::::::::::dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-s390","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh3", "gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh4", "gcc:-DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh3eb", "gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh4eb", "gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-m32r","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc-v8","gcc:-DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -mcpu=v8 -g -Wall -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::sparcv8.o:des_enc-sparc.o fcrypt_b.o:::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc-v9","gcc:-DB_ENDIAN -DTERMIO -O3 -mcpu=v9 -Wa,--noexecstack -Wa,-Av8plus -g -Wall -DULTRASPARC -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::sparcv8plus.o:des_enc-sparc.o fcrypt_b.o:::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc64","gcc:-m64 -DB_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall -DULTRASPARC -DBN_DIV2W::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL BF_PTR:::des_enc-sparc.o fcrypt_b.o:::::::::dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++
+ ####
+ #### Variety of LINUX:-)
+ ####
diff --git a/openssl0.9.8/patches/dtls-fragment-alert.patch b/openssl0.9.8/patches/dtls-fragment-alert.patch
new file mode 100644
index 0000000..c538340
--- /dev/null
+++ b/openssl0.9.8/patches/dtls-fragment-alert.patch
@@ -0,0 +1,33 @@
+Index: openssl-0.9.8o/ssl/d1_both.c
+===================================================================
+--- openssl-0.9.8o.orig/ssl/d1_both.c 2010-05-03 13:01:59.000000000 +0000
++++ openssl-0.9.8o/ssl/d1_both.c 2012-01-14 21:46:02.000000000 +0000
+@@ -806,7 +806,13 @@
+ *ok = 0;
+ return i;
+ }
+- OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH);
++ /* Handshake fails if message header is incomplete */
++ if (i != DTLS1_HM_HEADER_LENGTH)
++ {
++ al=SSL_AD_UNEXPECTED_MESSAGE;
++ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
++ goto f_err;
++ }
+
+ /* parse the message fragment header */
+ dtls1_get_message_header(wire, &msg_hdr);
+@@ -876,7 +882,12 @@
+
+ /* XDTLS: an incorrectly formatted fragment should cause the
+ * handshake to fail */
+- OPENSSL_assert(i == (int)frag_len);
++ if (i != (int)frag_len)
++ {
++ al=SSL3_AD_ILLEGAL_PARAMETER;
++ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL3_AD_ILLEGAL_PARAMETER);
++ goto f_err;
++ }
+
+ *ok = 1;
+
diff --git a/openssl0.9.8/patches/kfreebsd-pipe.patch b/openssl0.9.8/patches/kfreebsd-pipe.patch
new file mode 100644
index 0000000..da97186
--- /dev/null
+++ b/openssl0.9.8/patches/kfreebsd-pipe.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8k/crypto/perlasm/x86_64-xlate.pl
+===================================================================
+--- openssl-0.9.8k.orig/crypto/perlasm/x86_64-xlate.pl 2008-02-13 21:01:48.000000000 +0100
++++ openssl-0.9.8k/crypto/perlasm/x86_64-xlate.pl 2009-07-19 11:37:23.000000000 +0200
+@@ -62,7 +62,7 @@
+ my ($outdev,$outino,@junk)=stat($output);
+
+ open STDOUT,">$output" || die "can't open $output: $!"
+- if ($stddev!=$outdev || $stdino!=$outino);
++# if ($stddev!=$outdev || $stdino!=$outino);
+ }
+
+ my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005
diff --git a/openssl0.9.8/patches/make-targets.patch b/openssl0.9.8/patches/make-targets.patch
new file mode 100644
index 0000000..b123972
--- /dev/null
+++ b/openssl0.9.8/patches/make-targets.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8k/Makefile.org
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.org 2009-07-19 11:32:41.000000000 +0200
++++ openssl-0.9.8k/Makefile.org 2009-07-19 11:37:31.000000000 +0200
+@@ -131,7 +131,7 @@
+
+ BASEADDR=
+
+-DIRS= crypto fips ssl engines apps test tools
++DIRS= crypto fips ssl engines apps tools
+ SHLIBDIRS= crypto ssl fips
+
+ # dirs in crypto to build
diff --git a/openssl0.9.8/patches/man-dir.patch b/openssl0.9.8/patches/man-dir.patch
new file mode 100644
index 0000000..29563ec
--- /dev/null
+++ b/openssl0.9.8/patches/man-dir.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8k/Makefile.org
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.org 2009-07-19 11:32:41.000000000 +0200
++++ openssl-0.9.8k/Makefile.org 2009-07-19 11:37:29.000000000 +0200
+@@ -152,7 +152,7 @@
+
+ MAKEFILE= Makefile
+
+-MANDIR=$(OPENSSLDIR)/man
++MANDIR=/usr/share/man
+ MAN1=1
+ MAN3=3
+ MANSUFFIX=
diff --git a/openssl0.9.8/patches/man-section.patch b/openssl0.9.8/patches/man-section.patch
new file mode 100644
index 0000000..fe20ab0
--- /dev/null
+++ b/openssl0.9.8/patches/man-section.patch
@@ -0,0 +1,32 @@
+Index: openssl-0.9.8k/Makefile.org
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.org 2009-07-19 11:34:06.000000000 +0200
++++ openssl-0.9.8k/Makefile.org 2009-07-19 11:37:21.000000000 +0200
+@@ -155,7 +155,8 @@
+ MANDIR=/usr/share/man
+ MAN1=1
+ MAN3=3
+-MANSUFFIX=
++MANSUFFIX=ssl
++MANSECTION=SSL
+ SHELL=/bin/sh
+
+ TOP= .
+@@ -694,7 +695,7 @@
+ echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
+ (cd `$(PERL) util/dirname.pl $$i`; \
+ sh -c "$$pod2man \
+- --section=$$sec --center=OpenSSL \
++ --section=$${sec}$(MANSECTION) --center=OpenSSL \
+ --release=$(VERSION) `basename $$i`") \
+ > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
+ $(PERL) util/extract-names.pl < $$i | \
+@@ -711,7 +712,7 @@
+ echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
+ (cd `$(PERL) util/dirname.pl $$i`; \
+ sh -c "$$pod2man \
+- --section=$$sec --center=OpenSSL \
++ --section=$${sec}$(MANSECTION) --center=OpenSSL \
+ --release=$(VERSION) `basename $$i`") \
+ > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
+ $(PERL) util/extract-names.pl < $$i | \
diff --git a/openssl0.9.8/patches/no-rpath.patch b/openssl0.9.8/patches/no-rpath.patch
new file mode 100644
index 0000000..3ebc9ac
--- /dev/null
+++ b/openssl0.9.8/patches/no-rpath.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8k/Makefile.shared
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.shared 2008-09-17 17:56:40.000000000 +0200
++++ openssl-0.9.8k/Makefile.shared 2009-07-19 11:37:25.000000000 +0200
+@@ -151,7 +151,7 @@
+ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \
+ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-Bsymbolic -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
+
+-DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,$(LIBRPATH)"
++DO_GNU_APP=LDFLAGS="$(CFLAGS)"
+
+ #This is rather special. It's a special target with which one can link
+ #applications without bothering with any features that have anything to
diff --git a/openssl0.9.8/patches/no-symbolic.patch b/openssl0.9.8/patches/no-symbolic.patch
new file mode 100644
index 0000000..2504fa7
--- /dev/null
+++ b/openssl0.9.8/patches/no-symbolic.patch
@@ -0,0 +1,13 @@
+Index: openssl-0.9.8k/Makefile.shared
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.shared 2009-07-19 11:35:02.000000000 +0200
++++ openssl-0.9.8k/Makefile.shared 2009-07-19 11:35:48.000000000 +0200
+@@ -149,7 +149,7 @@
+ SHLIB_SUFFIX=; \
+ ALLSYMSFLAGS='-Wl,--whole-archive'; \
+ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \
+- SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-Bsymbolic -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
+
+ DO_GNU_APP=LDFLAGS="$(CFLAGS)"
+
diff --git a/openssl0.9.8/patches/perl-path.diff b/openssl0.9.8/patches/perl-path.diff
new file mode 100644
index 0000000..a72f938
--- /dev/null
+++ b/openssl0.9.8/patches/perl-path.diff
@@ -0,0 +1,760 @@
+From: Kurt Roeckx <kurt@roeckx.be>
+Subject: Change the perl path's to /usr/bin/perl
+
+This is the result of running:
+perl util/perlpath.pl /usr/bin
+
+The upstream sources have this set to various different paths.
+
+--- openssl-0.9.8m.orig/Configure
++++ openssl-0.9.8m/Configure
+@@ -1,4 +1,4 @@
+-:
++#!/usr/bin/perl
+ eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+ ##
+--- openssl-0.9.8m.orig/VMS/VMSify-conf.pl
++++ openssl-0.9.8m/VMS/VMSify-conf.pl
+@@ -1,4 +1,4 @@
+-#! /usr/bin/perl
++#!/usr/bin/perl
+
+ use strict;
+ use warnings;
+--- openssl-0.9.8m.orig/Netware/do_tests.pl
++++ openssl-0.9.8m/Netware/do_tests.pl
+@@ -1,4 +1,4 @@
+-# perl script to run OpenSSL tests
++#!/usr/bin/perl
+
+
+ my $base_path = "\\openssl";
+--- openssl-0.9.8m.orig/apps/progs.pl
++++ openssl-0.9.8m/apps/progs.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ print "/* apps/progs.h */\n";
+ print "/* automatically generated by progs.pl for openssl.c */\n\n";
+--- openssl-0.9.8m.orig/os2/backwardify.pl
++++ openssl-0.9.8m/os2/backwardify.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/perl -w
++#!/usr/bin/perl
+ use strict;
+
+ # Use as $0
+--- openssl-0.9.8m.orig/times/091/mips-rel.pl
++++ openssl-0.9.8m/times/091/mips-rel.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ &doit(100,"Pentium 100 32",0.0195,0.1000,0.6406,4.6100); # pentium-100
+ &doit(200,"PPro 200 32",0.0070,0.0340,0.2087,1.4700); # pentium-100
+--- openssl-0.9.8m.orig/fips/mkfipsscr.pl
++++ openssl-0.9.8m/fips/mkfipsscr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ # Quick & dirty utility to generate a script for executing the
+ # FIPS 140-2 CMVP algorithm tests based on the pathnames of
+ # input algorithm test files actually present (the unqualified
+--- openssl-0.9.8m.orig/fips/fipsalgtest.pl
++++ openssl-0.9.8m/fips/fipsalgtest.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/perl -w
++#!/usr/bin/perl
+ # Perl utility to run or verify FIPS 140-2 CMVP algorithm tests based on the
+ # pathnames of input algorithm test files actually present (the unqualified
+ # file names are consistent but the pathnames are not).
+--- openssl-0.9.8m.orig/ms/uplink.pl
++++ openssl-0.9.8m/ms/uplink.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # For Microsoft CL this is implemented as inline assembler. So that
+ # even though this script can generate even Win32 code, we'll be
+--- openssl-0.9.8m.orig/ms/segrenam.pl
++++ openssl-0.9.8m/ms/segrenam.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ my $quiet = 1;
+
+--- openssl-0.9.8m.orig/ms/cmp.pl
++++ openssl-0.9.8m/ms/cmp.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ ($#ARGV == 1) || die "usage: cmp.pl <file1> <file2>\n";
+
+--- openssl-0.9.8m.orig/test/cms-test.pl
++++ openssl-0.9.8m/test/cms-test.pl
+@@ -1,4 +1,4 @@
+-# test/cms-test.pl
++#!/usr/bin/perl
+ # Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ # project.
+ #
+--- openssl-0.9.8m.orig/test/cms-examples.pl
++++ openssl-0.9.8m/test/cms-examples.pl
+@@ -1,4 +1,4 @@
+-# test/cms-examples.pl
++#!/usr/bin/perl
+ # Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ # project.
+ #
+--- openssl-0.9.8m.orig/demos/b64.pl
++++ openssl-0.9.8m/demos/b64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ #
+ # Make PEM encoded data have lines of 64 bytes of data
+--- openssl-0.9.8m.orig/demos/tunala/configure.in
++++ openssl-0.9.8m/demos/tunala/configure.in
+@@ -1,4 +1,4 @@
+-dnl Process this file with autoconf to produce a configure script.
++#!/usr/bin/perl
+ AC_INIT(tunala.c)
+ AM_CONFIG_HEADER(config.h)
+ AM_INIT_AUTOMAKE(tunala, 0.0.1-dev)
+--- openssl-0.9.8m.orig/crypto/x86cpuid.pl
++++ openssl-0.9.8m/crypto/x86cpuid.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/x86_64cpuid.pl
++++ openssl-0.9.8m/crypto/x86_64cpuid.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ $output=shift;
+ $masm=1 if ($output =~ /\.asm/);
+--- openssl-0.9.8m.orig/crypto/md5/asm/md5-586.pl
++++ openssl-0.9.8m/crypto/md5/asm/md5-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # Normal is the
+ # md5_block_x86(MD5_CTX *c, ULONG *X);
+--- openssl-0.9.8m.orig/crypto/md5/asm/md5-x86_64.pl
++++ openssl-0.9.8m/crypto/md5/asm/md5-x86_64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/perl -w
++#!/usr/bin/perl
+ #
+ # MD5 optimized for AMD64.
+ #
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha1-ia64.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha1-ia64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha1-x86_64.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha1-x86_64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha512-sse2.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha512-sse2.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha512-ia64.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha512-ia64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha512-x86_64.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha512-x86_64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/sha/asm/sha1-586.pl
++++ openssl-0.9.8m/crypto/sha/asm/sha1-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ # ====================================================================
+ # [Re]written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/des/asm/des-586.pl
++++ openssl-0.9.8m/crypto/des/asm/des-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # The inner loop instruction sequence and the IP/FP modifications are from
+ # Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
+--- openssl-0.9.8m.orig/crypto/des/asm/desboth.pl
++++ openssl-0.9.8m/crypto/des/asm/desboth.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ $L="edi";
+ $R="esi";
+--- openssl-0.9.8m.orig/crypto/des/asm/des686.pl
++++ openssl-0.9.8m/crypto/des/asm/des686.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ $prog="des686.pl";
+
+--- openssl-0.9.8m.orig/crypto/des/asm/crypt586.pl
++++ openssl-0.9.8m/crypto/des/asm/crypt586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # The inner loop instruction sequence and the IP/FP modifications are from
+ # Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
+--- openssl-0.9.8m.orig/crypto/lhash/num.pl
++++ openssl-0.9.8m/crypto/lhash/num.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ #node 10 -> 4
+
+--- openssl-0.9.8m.orig/crypto/ripemd/asm/rmd-586.pl
++++ openssl-0.9.8m/crypto/ripemd/asm/rmd-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # Normal is the
+ # ripemd160_block_asm_data_order(RIPEMD160_CTX *c, ULONG *X,int blocks);
+--- openssl-0.9.8m.orig/crypto/rc4/asm/rc4-586.pl
++++ openssl-0.9.8m/crypto/rc4/asm/rc4-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # At some point it became apparent that the original SSLeay RC4
+ # assembler implementation performs suboptimaly on latest IA-32
+--- openssl-0.9.8m.orig/crypto/rc4/asm/rc4-x86_64.pl
++++ openssl-0.9.8m/crypto/rc4/asm/rc4-x86_64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/cast/asm/cast-586.pl
++++ openssl-0.9.8m/crypto/cast/asm/cast-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # define for pentium pro friendly version
+ $ppro=1;
+--- openssl-0.9.8m.orig/crypto/rc5/asm/rc5-586.pl
++++ openssl-0.9.8m/crypto/rc5/asm/rc5-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/perlasm/x86ms.pl
++++ openssl-0.9.8m/crypto/perlasm/x86ms.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ package x86ms;
+
+--- openssl-0.9.8m.orig/crypto/perlasm/x86asm.pl
++++ openssl-0.9.8m/crypto/perlasm/x86asm.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # require 'x86asm.pl';
+ # &asm_init("cpp","des-586.pl");
+--- openssl-0.9.8m.orig/crypto/perlasm/x86nasm.pl
++++ openssl-0.9.8m/crypto/perlasm/x86nasm.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ package x86nasm;
+
+--- openssl-0.9.8m.orig/crypto/perlasm/x86unix.pl
++++ openssl-0.9.8m/crypto/perlasm/x86unix.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ package x86unix; # GAS actually...
+
+--- openssl-0.9.8m.orig/crypto/perlasm/cbc.pl
++++ openssl-0.9.8m/crypto/perlasm/cbc.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+ # des_cblock (*input);
+--- openssl-0.9.8m.orig/crypto/perlasm/x86_64-xlate.pl
++++ openssl-0.9.8m/crypto/perlasm/x86_64-xlate.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ # Ascetic x86_64 AT&T to MASM assembler translator by <appro>.
+ #
+--- openssl-0.9.8m.orig/crypto/bf/asm/bf-686.pl
++++ openssl-0.9.8m/crypto/bf/asm/bf-686.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/bf/asm/bf-586.pl
++++ openssl-0.9.8m/crypto/bf/asm/bf-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/objects/objects.pl
++++ openssl-0.9.8m/crypto/objects/objects.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ open (NUMIN,"$ARGV[1]") || die "Can't open number file $ARGV[1]";
+ $max_nid=0;
+--- openssl-0.9.8m.orig/crypto/objects/obj_dat.pl
++++ openssl-0.9.8m/crypto/objects/obj_dat.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # fixes bug in floating point emulation on sparc64 when
+ # this script produces off-by-one output on sparc64
+--- openssl-0.9.8m.orig/crypto/conf/keysets.pl
++++ openssl-0.9.8m/crypto/conf/keysets.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ $NUMBER=0x01;
+ $UPPER=0x02;
+--- openssl-0.9.8m.orig/crypto/bn/bn_prime.pl
++++ openssl-0.9.8m/crypto/bn/bn_prime.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # bn_prime.pl
+
+ $num=2048;
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/bn/asm/ppc.pl
++++ openssl-0.9.8m/crypto/bn/asm/ppc.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # Implemented as a Perl wrapper as we want to support several different
+ # architectures with single file. We pick up the target based on the
+--- openssl-0.9.8m.orig/crypto/bn/asm/co-586.pl
++++ openssl-0.9.8m/crypto/bn/asm/co-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/bn/asm/bn-586.pl
++++ openssl-0.9.8m/crypto/bn/asm/bn-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+--- openssl-0.9.8m.orig/crypto/bn/asm/mo-586.pl
++++ openssl-0.9.8m/crypto/bn/asm/mo-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ # This is crypto/bn/asm/x86-mont.pl (with asciz from crypto/perlasm/x86asm.pl)
+ # from OpenSSL 0.9.9-dev
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86_64-mont.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86_64-mont.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/comba.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/comba.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub mul_add_c
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/add.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/add.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_add_words
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/mul.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/mul.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_mul_words
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/mul_add.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/mul_add.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_mul_add_words
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/sqr.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/sqr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_sqr_words
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/sub.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/sub.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_sub_words
+--- openssl-0.9.8m.orig/crypto/bn/asm/x86/div.pl
++++ openssl-0.9.8m/crypto/bn/asm/x86/div.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # x86 assember
+
+ sub bn_div_words
+--- openssl-0.9.8m.orig/crypto/aes/asm/aes-586.pl
++++ openssl-0.9.8m/crypto/aes/asm/aes-586.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/aes/asm/aes-x86_64.pl
++++ openssl-0.9.8m/crypto/aes/asm/aes-x86_64.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+--- openssl-0.9.8m.orig/crypto/asn1/charmap.pl
++++ openssl-0.9.8m/crypto/asn1/charmap.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+
+ use strict;
+
+--- openssl-0.9.8m.orig/util/mksdef.pl
++++ openssl-0.9.8m/util/mksdef.pl
+@@ -1,4 +1,4 @@
+-
++#!/usr/bin/perl
+ # Perl script to split libeay32.def into two distinct DEF files for use in
+ # fipdso mode. It works out symbols in each case by running "link" command and
+ # parsing the output to find the list of missing symbols then splitting
+--- openssl-0.9.8m.orig/util/dirname.pl
++++ openssl-0.9.8m/util/dirname.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ if ($#ARGV < 0) {
+ die "dirname.pl: too few arguments\n";
+--- openssl-0.9.8m.orig/util/tab_num.pl
++++ openssl-0.9.8m/util/tab_num.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ $num=1;
+ $width=40;
+--- openssl-0.9.8m.orig/util/sp-diff.pl
++++ openssl-0.9.8m/util/sp-diff.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # This file takes as input, the files that have been output from
+ # ssleay speed.
+--- openssl-0.9.8m.orig/util/mkerr.pl
++++ openssl-0.9.8m/util/mkerr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+
+ my $config = "crypto/err/openssl.ec";
+ my $debug = 0;
+--- openssl-0.9.8m.orig/util/clean-depend.pl
++++ openssl-0.9.8m/util/clean-depend.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ # Clean the dependency list in a makefile of standard includes...
+ # Written by Ben Laurie <ben@algroup.co.uk> 19 Jan 1999
+
+--- openssl-0.9.8m.orig/util/add_cr.pl
++++ openssl-0.9.8m/util/add_cr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # This adds a copyright message to a souce code file.
+ # It also gets the file name correct.
+--- openssl-0.9.8m.orig/util/pod2man.pl
++++ openssl-0.9.8m/util/pod2man.pl
+@@ -1,4 +1,4 @@
+-: #!/usr/bin/perl-5.005
++#!/usr/bin/perl
+ eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+--- openssl-0.9.8m.orig/util/mkstack.pl
++++ openssl-0.9.8m/util/mkstack.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+
+ # This is a utility that searches out "DECLARE_STACK_OF()"
+ # declarations in .h and .c files, and updates/creates/replaces
+--- openssl-0.9.8m.orig/util/selftest.pl
++++ openssl-0.9.8m/util/selftest.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ #
+ # Run the test suite and generate a report
+ #
+--- openssl-0.9.8m.orig/util/ck_errf.pl
++++ openssl-0.9.8m/util/ck_errf.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # This is just a quick script to scan for cases where the 'error'
+ # function name in a XXXerr() macro is wrong.
+--- openssl-0.9.8m.orig/util/mklink.pl
++++ openssl-0.9.8m/util/mklink.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # mklink.pl
+
+--- openssl-0.9.8m.orig/util/src-dep.pl
++++ openssl-0.9.8m/util/src-dep.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # we make up an array of
+ # $file{function_name}=filename;
+--- openssl-0.9.8m.orig/util/deleof.pl
++++ openssl-0.9.8m/util/deleof.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ while (<>)
+ {
+--- openssl-0.9.8m.orig/util/arx.pl
++++ openssl-0.9.8m/util/arx.pl
+@@ -1,4 +1,4 @@
+-#!/bin/perl
++#!/usr/bin/perl
+
+ # Simple perl script to wrap round "ar" program and exclude any
+ # object files in the environment variable EXCL_OBJ
+--- openssl-0.9.8m.orig/util/copy.pl
++++ openssl-0.9.8m/util/copy.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ use Fcntl;
+
+--- openssl-0.9.8m.orig/util/mkdir-p.pl
++++ openssl-0.9.8m/util/mkdir-p.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # mkdir-p.pl
+
+--- openssl-0.9.8m.orig/util/mkdef.pl
++++ openssl-0.9.8m/util/mkdef.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ #
+ # generate a .def file
+ #
+--- openssl-0.9.8m.orig/util/files.pl
++++ openssl-0.9.8m/util/files.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # used to generate the file MINFO for use by util/mk1mf.pl
+ # It is basically a list of all variables from the passed makefile
+--- openssl-0.9.8m.orig/util/mkfiles.pl
++++ openssl-0.9.8m/util/mkfiles.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # This is a hacked version of files.pl for systems that can't do a 'make files'.
+ # Do a perl util/mkminfo.pl >MINFO to build MINFO
+--- openssl-0.9.8m.orig/util/perlpath.pl
++++ openssl-0.9.8m/util/perlpath.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # modify the '#!/usr/local/bin/perl'
+ # line in all scripts that rely on perl.
+--- openssl-0.9.8m.orig/util/mk1mf.pl
++++ openssl-0.9.8m/util/mk1mf.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # A bit of an evil hack but it post processes the file ../MINFO which
+ # is generated by `make files` in the top directory.
+ # This script outputs one mega makefile that has no shell stuff or any
+--- openssl-0.9.8m.orig/util/err-ins.pl
++++ openssl-0.9.8m/util/err-ins.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # tack error codes onto the end of a file
+ #
+--- openssl-0.9.8m.orig/util/pl/Mingw32.pl
++++ openssl-0.9.8m/util/pl/Mingw32.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # Mingw32.pl -- Mingw
+ #
+--- openssl-0.9.8m.orig/util/pl/unix.pl
++++ openssl-0.9.8m/util/pl/unix.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # unix.pl - the standard unix makefile stuff.
+ #
+--- openssl-0.9.8m.orig/util/pl/netware.pl
++++ openssl-0.9.8m/util/pl/netware.pl
+@@ -1,4 +1,4 @@
+-# Metrowerks Codewarrior or gcc / nlmconv for NetWare
++#!/usr/bin/perl
+ #
+
+ $version_header = "crypto/opensslv.h";
+--- openssl-0.9.8m.orig/util/pl/VC-32.pl
++++ openssl-0.9.8m/util/pl/VC-32.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # VC-32.pl - unified script for Microsoft Visual C++, covering Win32,
+ # Win64 and WinCE [follow $FLAVOR variable to trace the differences].
+ #
+--- openssl-0.9.8m.orig/util/pl/OS2-EMX.pl
++++ openssl-0.9.8m/util/pl/OS2-EMX.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # OS2-EMX.pl - for EMX GCC on OS/2
+ #
+--- openssl-0.9.8m.orig/util/pl/ultrix.pl
++++ openssl-0.9.8m/util/pl/ultrix.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # linux.pl - the standard unix makefile stuff.
+ #
+--- openssl-0.9.8m.orig/util/pl/linux.pl
++++ openssl-0.9.8m/util/pl/linux.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ #
+ # linux.pl - the standard unix makefile stuff.
+ #
+--- openssl-0.9.8m.orig/util/pl/BC-32.pl
++++ openssl-0.9.8m/util/pl/BC-32.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ # Borland C++ builder 3 and 4 -- Janez Jere <jj@void.si>
+ #
+
diff --git a/openssl0.9.8/patches/pic.patch b/openssl0.9.8/patches/pic.patch
new file mode 100644
index 0000000..b534afa
--- /dev/null
+++ b/openssl0.9.8/patches/pic.patch
@@ -0,0 +1,301 @@
+Index: openssl-0.9.8o/crypto/Makefile
+===================================================================
+--- openssl-0.9.8o.orig/crypto/Makefile 2008-09-17 17:10:55.000000000 +0000
++++ openssl-0.9.8o/crypto/Makefile 2010-06-06 13:09:28.000000000 +0000
+@@ -57,7 +57,7 @@
+ echo " #define DATE \"`LC_ALL=C LC_TIME=C date`\""; \
+ echo '#endif' ) >buildinf.h
+
+-x86cpuid-elf.s: x86cpuid.pl perlasm/x86asm.pl
++x86cpuid-elf.S: x86cpuid.pl perlasm/x86asm.pl
+ $(PERL) x86cpuid.pl elf $(CFLAGS) $(PROCESSOR) > $@
+ x86cpuid-cof.s: x86cpuid.pl perlasm/x86asm.pl
+ $(PERL) x86cpuid.pl coff $(CFLAGS) $(PROCESSOR) > $@
+@@ -70,7 +70,7 @@
+ uplink-cof.s: ../ms/uplink.pl
+ $(PERL) ../ms/uplink.pl coff > $@
+
+-x86_64cpuid.s: x86_64cpuid.pl
++x86_64cpuid.S: x86_64cpuid.pl
+ $(PERL) x86_64cpuid.pl $@
+ ia64cpuid.s: ia64cpuid.S
+ $(CC) $(CFLAGS) -E ia64cpuid.S > $@
+Index: openssl-0.9.8o/crypto/x86_64cpuid.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/x86_64cpuid.pl 2007-11-11 16:25:00.000000000 +0000
++++ openssl-0.9.8o/crypto/x86_64cpuid.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -95,7 +95,11 @@
+ .size OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
+
+ .section .init
++#ifdef OPENSSL_PIC
++ call OPENSSL_cpuid_setup\@PLT
++#else
+ call OPENSSL_cpuid_setup
++#endif
+
+ ___
+
+Index: openssl-0.9.8o/crypto/md5/Makefile
+===================================================================
+--- openssl-0.9.8o.orig/crypto/md5/Makefile 2008-09-17 17:11:02.000000000 +0000
++++ openssl-0.9.8o/crypto/md5/Makefile 2010-06-06 13:09:28.000000000 +0000
+@@ -52,7 +52,8 @@
+ mx86-out.s: asm/md5-586.pl ../perlasm/x86asm.pl
+ (cd asm; $(PERL) md5-586.pl a.out $(CFLAGS) > ../$@)
+
+-md5-x86_64.s: asm/md5-x86_64.pl; $(PERL) asm/md5-x86_64.pl $@
++md5-x86_64.s: asm/md5-x86_64.pl
++ $(PERL) asm/md5-x86_64.pl $@
+
+ files:
+ $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
+Index: openssl-0.9.8o/crypto/des/asm/desboth.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/des/asm/desboth.pl 2001-10-24 21:20:56.000000000 +0000
++++ openssl-0.9.8o/crypto/des/asm/desboth.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -16,6 +16,11 @@
+
+ &push("edi");
+
++ &call (&label("pic_point0"));
++ &set_label("pic_point0");
++ &blindpop("ebp");
++ &add ("ebp", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point0") . "]");
++
+ &comment("");
+ &comment("Load the data words");
+ &mov($L,&DWP(0,"ebx","",0));
+@@ -47,15 +52,21 @@
+ &mov(&swtmp(2), (DWC(($enc)?"1":"0")));
+ &mov(&swtmp(1), "eax");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+ &mov(&swtmp(2), (DWC(($enc)?"0":"1")));
+ &mov(&swtmp(1), "edi");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+ &mov(&swtmp(2), (DWC(($enc)?"1":"0")));
+ &mov(&swtmp(1), "esi");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+
+ &stack_pop(3);
+ &mov($L,&DWP(0,"ebx","",0));
+Index: openssl-0.9.8o/crypto/rc4/Makefile
+===================================================================
+--- openssl-0.9.8o.orig/crypto/rc4/Makefile 2008-11-19 16:03:50.000000000 +0000
++++ openssl-0.9.8o/crypto/rc4/Makefile 2010-06-06 13:09:28.000000000 +0000
+@@ -51,7 +51,7 @@
+ rx86-out.s: asm/rc4-586.pl ../perlasm/x86asm.pl
+ (cd asm; $(PERL) rc4-586.pl a.out $(CFLAGS) > ../$@)
+
+-rc4-x86_64.s: asm/rc4-x86_64.pl; $(PERL) asm/rc4-x86_64.pl $@
++rc4-x86_64.S: asm/rc4-x86_64.pl; $(PERL) asm/rc4-x86_64.pl $@
+
+ rc4-ia64.s: asm/rc4-ia64.S
+ @case `awk '/^#define RC4_INT/{print$$NF}' $(TOP)/include/openssl/opensslconf.h` in \
+Index: openssl-0.9.8o/crypto/rc4/asm/rc4-x86_64.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/rc4/asm/rc4-x86_64.pl 2008-09-16 10:47:27.000000000 +0000
++++ openssl-0.9.8o/crypto/rc4/asm/rc4-x86_64.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -270,7 +270,11 @@
+ xor %r10,%r10
+ xor %r11,%r11
+
++#ifdef OPENSSL_PIC
++ mov OPENSSL_ia32cap_P\@GOTPCREL(%rip),$idx#d
++#else
+ mov OPENSSL_ia32cap_P(%rip),$idx#d
++#endif
+ bt \$20,$idx#d
+ jnc .Lw1stloop
+ bt \$30,$idx#d
+@@ -338,7 +342,11 @@
+ RC4_options:
+ .picmeup %rax
+ lea .Lopts-.(%rax),%rax
++#ifdef OPENSSL_PIC
++ mov OPENSSL_ia32cap_P\@GOTPCREL(%rip),%edx
++#else
+ mov OPENSSL_ia32cap_P(%rip),%edx
++#endif
+ bt \$20,%edx
+ jnc .Ldone
+ add \$12,%rax
+Index: openssl-0.9.8o/crypto/perlasm/x86unix.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/perlasm/x86unix.pl 2008-05-01 23:11:32.000000000 +0000
++++ openssl-0.9.8o/crypto/perlasm/x86unix.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -400,6 +400,29 @@
+ $stack=4;
+ }
+
++sub main'function_begin_B_static
++ {
++ local($func,$extra)=@_;
++
++ &main'external_label($func);
++ $func=$under.$func;
++
++ local($tmp)=<<"EOF";
++.text
++EOF
++ push(@out,$tmp);
++ if ($main'cpp)
++ { push(@out,"TYPE($func,\@function)\n"); }
++ elsif ($main'coff)
++ { $tmp=push(@out,".def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
++ elsif ($main'aout and !$main'pic)
++ { }
++ else { push(@out,".type $func,\@function\n"); }
++ push(@out,".align\t$align\n");
++ push(@out,"$func:\n");
++ $stack=4;
++ }
++
+ sub main'function_end
+ {
+ local($func)=@_;
+@@ -694,7 +717,17 @@
+ {
+ $tmp=<<___;
+ .section .init
++#ifdef OPENSSL_PIC
++ pushl %ebx
++ call .pic_point0
++.pic_point0:
++ popl %ebx
++ addl \$_GLOBAL_OFFSET_TABLE_+[.-.pic_point0],%ebx
++ call $under$f\@PLT
++ popl %ebx
++#else
+ call $under$f
++#endif
+ jmp .Linitalign
+ .align $align
+ .Linitalign:
+Index: openssl-0.9.8o/crypto/perlasm/cbc.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/perlasm/cbc.pl 2005-05-09 21:48:00.000000000 +0000
++++ openssl-0.9.8o/crypto/perlasm/cbc.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -122,7 +122,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($enc_func);
++ &call (&label("pic_point0"));
++ &set_label("pic_point0");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point0") . "]");
++ &call("$enc_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+@@ -187,7 +191,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($enc_func);
++ &call (&label("pic_point1"));
++ &set_label("pic_point1");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point1") . "]");
++ &call("$enc_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+@@ -220,7 +228,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($dec_func);
++ &call (&label("pic_point2"));
++ &set_label("pic_point2");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point2") . "]");
++ &call("$dec_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+@@ -263,7 +275,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($dec_func);
++ &call (&label("pic_point3"));
++ &set_label("pic_point3");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point3") . "]");
++ &call("$dec_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+Index: openssl-0.9.8o/crypto/perlasm/x86_64-xlate.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/perlasm/x86_64-xlate.pl 2010-06-06 13:09:00.000000000 +0000
++++ openssl-0.9.8o/crypto/perlasm/x86_64-xlate.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -435,7 +435,7 @@
+
+ chomp($line);
+
+- $line =~ s|[#!].*$||; # get rid of asm-style comments...
++# $line =~ s|[#!].*$||; # get rid of asm-style comments...
+ $line =~ s|/\*.*\*/||; # ... and C-style comments...
+ $line =~ s|^\s+||; # ... and skip white spaces in beginning
+
+Index: openssl-0.9.8o/crypto/aes/asm/aes-586.pl
+===================================================================
+--- openssl-0.9.8o.orig/crypto/aes/asm/aes-586.pl 2008-12-17 14:14:51.000000000 +0000
++++ openssl-0.9.8o/crypto/aes/asm/aes-586.pl 2010-06-06 13:09:28.000000000 +0000
+@@ -250,7 +250,7 @@
+ sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } }
+
+ &public_label("AES_Te");
+-&function_begin_B("_x86_AES_encrypt");
++&function_begin_B_static("_x86_AES_encrypt");
+ if ($vertical_spin) {
+ # I need high parts of volatile registers to be accessible...
+ &exch ($s1="edi",$key="ebx");
+@@ -539,7 +539,7 @@
+ }
+
+ &public_label("AES_Td");
+-&function_begin_B("_x86_AES_decrypt");
++&function_begin_B_static("_x86_AES_decrypt");
+ # note that caller is expected to allocate stack frame for me!
+ &mov (&DWP(12,"esp"),$key); # save key
+
+@@ -1461,15 +1461,22 @@
+ &public_label("AES_Td");
+ &public_label("AES_Te");
+ &function_begin_B("AES_set_decrypt_key");
++ &push ("ebx");
+ &mov ("eax",&wparam(0));
+ &mov ("ecx",&wparam(1));
+ &mov ("edx",&wparam(2));
+ &sub ("esp",12);
++
++ &call (&label("pic_point0"));
++ &set_label("pic_point0");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point0") . "]");
+ &mov (&DWP(0,"esp"),"eax");
+ &mov (&DWP(4,"esp"),"ecx");
+ &mov (&DWP(8,"esp"),"edx");
+- &call ("AES_set_encrypt_key");
++ &call ("AES_set_encrypt_key\@PLT");
+ &add ("esp",12);
++ &pop ("ebx");
+ &cmp ("eax",0);
+ &je (&label("proceed"));
+ &ret ();
diff --git a/openssl0.9.8/patches/pkg-config.patch b/openssl0.9.8/patches/pkg-config.patch
new file mode 100644
index 0000000..38923b0
--- /dev/null
+++ b/openssl0.9.8/patches/pkg-config.patch
@@ -0,0 +1,34 @@
+Index: openssl-0.9.8k/Makefile.org
+===================================================================
+--- openssl-0.9.8k.orig/Makefile.org 2009-07-19 11:34:56.000000000 +0200
++++ openssl-0.9.8k/Makefile.org 2009-07-19 11:36:02.000000000 +0200
+@@ -444,7 +444,8 @@
+ echo 'Description: OpenSSL cryptography library'; \
+ echo 'Version: '$(VERSION); \
+ echo 'Requires: '; \
+- echo 'Libs: -L$${libdir} -lcrypto $(EX_LIBS)'; \
++ echo 'Libs: -L$${libdir} -lcrypto'; \
++ echo 'Libs.private: $(EX_LIBS)'; \
+ echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > libcrypto.pc
+
+ libssl.pc: Makefile
+@@ -457,7 +458,8 @@
+ echo 'Description: Secure Sockets Layer and cryptography libraries'; \
+ echo 'Version: '$(VERSION); \
+ echo 'Requires: '; \
+- echo 'Libs: -L$${libdir} -lssl -lcrypto $(EX_LIBS)'; \
++ echo 'Libs: -L$${libdir} -lssl'; \
++ echo 'Libs.private: -lcrypto $(EX_LIBS)'; \
+ echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > libssl.pc
+
+ openssl.pc: Makefile
+@@ -470,7 +472,8 @@
+ echo 'Description: Secure Sockets Layer and cryptography libraries and tools'; \
+ echo 'Version: '$(VERSION); \
+ echo 'Requires: '; \
+- echo 'Libs: -L$${libdir} -lssl -lcrypto $(EX_LIBS)'; \
++ echo 'Libs: -L$${libdir} -lssl -lcrypto'; \
++ echo 'Libs.private: $(EX_LIBS)'; \
+ echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > openssl.pc
+
+ Makefile: Makefile.org Configure config
diff --git a/openssl0.9.8/patches/rc4-amd64.patch b/openssl0.9.8/patches/rc4-amd64.patch
new file mode 100644
index 0000000..6f0421a
--- /dev/null
+++ b/openssl0.9.8/patches/rc4-amd64.patch
@@ -0,0 +1,14 @@
+Index: openssl-0.9.8k/Configure
+===================================================================
+--- openssl-0.9.8k.orig/Configure 2009-07-19 11:32:41.000000000 +0200
++++ openssl-0.9.8k/Configure 2009-07-19 11:37:10.000000000 +0200
+@@ -128,6 +128,9 @@
+ my $x86_out_asm="x86cpuid-out.o:bn86-out.o co86-out.o MAYBE-MO86-out.o:dx86-out.o yx86-out.o:ax86-out.o:bx86-out.o:mx86-out.o:sx86-out.o s512sse2-out.o:cx86-out.o:rx86-out.o rc4_skey.o:rm86-out.o:r586-out.o";
+
+ my $x86_64_asm="x86_64cpuid.o:x86_64-gcc.o x86_64-mont.o::aes-x86_64.o::md5-x86_64.o:sha1-x86_64.o sha256-x86_64.o sha512-x86_64.o::rc4-x86_64.o::";
++# rc4 asm is disabled on amd64 because we configured it with RC4_CHAR while
++# the assembler only works with int
++my $x86_64_asm_linux="x86_64cpuid.o:x86_64-gcc.o x86_64-mont.o::aes-x86_64.o::md5-x86_64.o:sha1-x86_64.o sha256-x86_64.o sha512-x86_64.o::::";
+ my $ia64_asm=":bn-ia64.o::aes_core.o aes_cbc.o aes-ia64.o:::sha1-ia64.o sha256-ia64.o sha512-ia64.o::rc4-ia64.o rc4_skey.o::";
+
+ my $no_asm="::::::::::";
diff --git a/openssl0.9.8/patches/rehash-crt.patch b/openssl0.9.8/patches/rehash-crt.patch
new file mode 100644
index 0000000..a8ff28c
--- /dev/null
+++ b/openssl0.9.8/patches/rehash-crt.patch
@@ -0,0 +1,33 @@
+Index: openssl-0.9.8k/tools/c_rehash.in
+===================================================================
+--- openssl-0.9.8k.orig/tools/c_rehash.in 2002-10-11 22:31:27.000000000 +0200
++++ openssl-0.9.8k/tools/c_rehash.in 2009-07-19 11:36:26.000000000 +0200
+@@ -59,12 +59,15 @@
+ }
+ }
+ closedir DIR;
+- FILE: foreach $fname (grep {/\.pem$/} @flist) {
++ FILE: foreach $fname (grep {/\.pem$|\.crt$/} @flist) {
+ # Check to see if certificates and/or CRLs present.
+ my ($cert, $crl) = check_file($fname);
+ if(!$cert && !$crl) {
+- print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
+- next;
++ ($cert, $crl) = check_file("$openssl x509 -in \"$fname\" -inform der -outform pem | ");
++ if(!$cert && !$crl) {
++ print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
++ next;
++ }
+ }
+ link_hash_cert($fname) if($cert);
+ link_hash_crl($fname) if($crl);
+@@ -102,6 +105,9 @@
+ my $fname = $_[0];
+ $fname =~ s/'/'\\''/g;
+ my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname'`;
++ if(!$hash || !fprint) {
++ ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname' -inform der`;
++ }
+ chomp $hash;
+ chomp $fprint;
+ $fprint =~ s/^.*=//;
diff --git a/openssl0.9.8/patches/rehash_pod.patch b/openssl0.9.8/patches/rehash_pod.patch
new file mode 100644
index 0000000..94792c4
--- /dev/null
+++ b/openssl0.9.8/patches/rehash_pod.patch
@@ -0,0 +1,60 @@
+Index: openssl-0.9.8k/doc/apps/c_rehash.pod
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openssl-0.9.8k/doc/apps/c_rehash.pod 2009-07-19 11:36:27.000000000 +0200
+@@ -0,0 +1,55 @@
++
++=pod
++
++=head1 NAME
++
++c_rehash - Create symbolic links to files named by the hash values
++
++=head1 SYNOPSIS
++
++B<c_rehash>
++[directory] ...
++
++=head1 DESCRIPTION
++
++c_rehash scans directories and takes a hash value of each .pem and .crt file in the directory. It then creates symbolic links for each of the files named by the hash value. This is useful as many programs require directories to be set up like this in order to find the certificates they require.
++
++If any directories are named on the command line then these directories are processed in turn. If not then and the environment variable SSL_CERT_DIR is defined then that is consulted. This variable should be a colon (:) separated list of directories, all of which will be processed. If neither of these conditions are true then /usr/lib/ssl/certs is processed.
++
++For each directory that is to be processed he user must have write permissions on the directory, if they do not then nothing will be printed for that directory.
++
++Note that this program deletes all the symbolic links that look like ones that it creates before processing a directory. Beware that if you run the program on a directory that contains symbolic links for other purposes that are named in the same format as those created by this program they will be lost.
++
++The hashes for certificate files are of the form <hash>.<n> where n is an integer. If the hash value already exists then n will be incremented, unless the file is a duplicate. Duplicates are detected using the fingerprint of the certificate. A warning will be printed if a duplicate is detected. The hashes for CRL files are of the form <hash>.r<n> and have the same behavior.
++
++The program will also warn if there are files with extension .pem which are not certificate or CRL files.
++
++The program uses the openssl program to compute the hashes and fingerprints. It expects the executable to be named openssl and be on the PATH, or in the /usr/lib/ssl/bin directory. If the OPENSSL environment variable is defined then this is used instead as the executable that provides the hashes and fingerprints. When called as $OPENSSL x509 -hash -fingerprint -noout -in $file it must output the hash of $file on the first line followed by the fingerprint on the second line, optionally prefixed with some text and an equals sign (=).
++
++=head1 OPTIONS
++
++None
++
++=head1 ENVIRONMENT
++
++=over 4
++
++=item B<OPENSSL>
++
++The name (and path) of an executable to use to generate hashes and fingerprints (see above).
++
++=item B<SSL_CERT_DIR>
++
++Colon separated list of directories to operate on. Ignored if directories are listed on the command line.
++
++=head1 SEE ALSO
++
++L<openssl(1)|openssl(1)>, L<x509(1)|x509(1)>
++
++=back
++
++=head1 BUGS
++
++No known bugs
++
++=cut
diff --git a/openssl0.9.8/patches/shared-lib-ext.patch b/openssl0.9.8/patches/shared-lib-ext.patch
new file mode 100644
index 0000000..d27e9b2
--- /dev/null
+++ b/openssl0.9.8/patches/shared-lib-ext.patch
@@ -0,0 +1,14 @@
+Index: openssl-0.9.8k/Configure
+===================================================================
+--- openssl-0.9.8k.orig/Configure 2009-07-19 11:36:24.000000000 +0200
++++ openssl-0.9.8k/Configure 2009-07-19 11:37:03.000000000 +0200
+@@ -1568,7 +1568,8 @@
+ elsif ($shared_extension ne "" && $shared_extension =~ /^\.s([ol])\.[^\.]*\.[^\.]*$/)
+ {
+ my $sotmp = $1;
+- s/^SHARED_LIBS_LINK_EXTS=.*/SHARED_LIBS_LINK_EXTS=.s$sotmp.\$(SHLIB_MAJOR) .s$sotmp/;
++# s/^SHARED_LIBS_LINK_EXTS=.*/SHARED_LIBS_LINK_EXTS=.s$sotmp.\$(SHLIB_MAJOR) .s$sotmp/;
++ s/^SHARED_LIBS_LINK_EXTS=.*/SHARED_LIBS_LINK_EXTS=.s$sotmp/;
+ }
+ elsif ($shared_extension ne "" && $shared_extension =~ /^\.[^\.]*\.[^\.]*\.dylib$/)
+ {
diff --git a/openssl0.9.8/patches/stddef.patch b/openssl0.9.8/patches/stddef.patch
new file mode 100644
index 0000000..bb65b23
--- /dev/null
+++ b/openssl0.9.8/patches/stddef.patch
@@ -0,0 +1,12 @@
+Index: openssl-0.9.8k/crypto/sha/sha.h
+===================================================================
+--- openssl-0.9.8k.orig/crypto/sha/sha.h 2008-09-16 12:47:28.000000000 +0200
++++ openssl-0.9.8k/crypto/sha/sha.h 2009-07-19 11:36:28.000000000 +0200
+@@ -59,6 +59,7 @@
+ #ifndef HEADER_SHA_H
+ #define HEADER_SHA_H
+
++#include <stddef.h>
+ #include <openssl/e_os2.h>
+ #include <stddef.h>
+
diff --git a/openssl0.9.8/patches/valgrind.patch b/openssl0.9.8/patches/valgrind.patch
new file mode 100644
index 0000000..e9f86ea
--- /dev/null
+++ b/openssl0.9.8/patches/valgrind.patch
@@ -0,0 +1,15 @@
+Index: openssl-0.9.8k/crypto/rand/md_rand.c
+===================================================================
+--- openssl-0.9.8k.orig/crypto/rand/md_rand.c 2008-09-16 13:50:05.000000000 +0200
++++ openssl-0.9.8k/crypto/rand/md_rand.c 2009-07-19 11:36:05.000000000 +0200
+@@ -477,8 +477,10 @@
+ MD_Update(&m,local_md,MD_DIGEST_LENGTH);
+ MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
+ #ifndef PURIFY
++#if 0 /* Don't add uninitialised data. */
+ MD_Update(&m,buf,j); /* purify complains */
+ #endif
++#endif
+ k=(st_idx+MD_DIGEST_LENGTH/2)-st_num;
+ if (k > 0)
+ {
diff --git a/openssl0.9.8/wrapper-opensslconf.h b/openssl0.9.8/wrapper-opensslconf.h
new file mode 100644
index 0000000..7179c4c
--- /dev/null
+++ b/openssl0.9.8/wrapper-opensslconf.h
@@ -0,0 +1,11 @@
+#if defined(__sparcv9)
+#ifndef OPENSSL_SYSNAME_ULTRASPARC
+# define OPENSSL_SYSNAME_ULTRASPARC
+#endif
+#endif
+
+#if defined(__sparcv9) || defined(__x86_64)
+# include <openssl/opensslconf.64.h>
+#else
+# include <openssl/opensslconf.32.h>
+#endif