summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anchor.c50
-rw-r--r--ckpem.h239
-rw-r--r--ckpemver.c59
-rw-r--r--constants.c77
-rw-r--r--nssckbi.h90
-rw-r--r--nsspem.h75
-rw-r--r--pargs.c162
-rw-r--r--pfind.c588
-rw-r--r--pinst.c602
-rw-r--r--pobject.c1175
-rw-r--r--prsa.c615
-rw-r--r--psession.c452
-rw-r--r--pslot.c184
-rw-r--r--ptoken.c333
-rw-r--r--rsawrapr.c924
-rw-r--r--util.c288
16 files changed, 5913 insertions, 0 deletions
diff --git a/anchor.c b/anchor.c
new file mode 100644
index 0000000..621f919
--- /dev/null
+++ b/anchor.c
@@ -0,0 +1,50 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * anchor.c
+ *
+ * This file "anchors" the actual cryptoki entry points in this module's
+ * shared library, which is required for dynamic loading. See the
+ * comments in nssck.api for more information.
+ */
+
+#include "ckpem.h"
+
+#define MODULE_NAME pem
+#define INSTANCE_NAME (NSSCKMDInstance *)&pem_mdInstance
+#include "nssck.api"
diff --git a/ckpem.h b/ckpem.h
new file mode 100644
index 0000000..5587333
--- /dev/null
+++ b/ckpem.h
@@ -0,0 +1,239 @@
+#include "nssckmdt.h"
+#include "nssckfw.h"
+#include "ckfwtm.h"
+#include "ckfw.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "blapit.h"
+#include "softoken.h"
+
+/*
+ * I'm including this for access to the arena functions.
+ * Looks like we should publish that API.
+ */
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+/*
+ * This is where the Netscape extensions live, at least for now.
+ */
+#ifndef CKT_H
+#include "ckt.h"
+#endif /* CKT_H */
+
+#define NUM_SLOTS 8
+
+/*
+ * statically defined raw objects. Allows us to data description objects
+ * to this PKCS #11 module.
+ */
+struct pemRawObjectStr {
+ CK_ULONG n;
+ const CK_ATTRIBUTE_TYPE *types;
+ const NSSItem *items;
+};
+typedef struct pemRawObjectStr pemRawObject;
+
+/*
+ * common values needed for both bare keys and cert referenced keys.
+ */
+struct pemKeyParamsStr {
+ NSSItem modulus;
+ NSSItem exponent;
+ NSSItem privateExponent;
+ NSSItem prime1;
+ NSSItem prime2;
+ NSSItem exponent1;
+ NSSItem exponent2;
+ NSSItem coefficient;
+ unsigned char publicExponentData[sizeof(CK_ULONG)];
+ SECItem *privateKey;
+ void *pubKey;
+};
+typedef struct pemKeyParamsStr pemKeyParams;
+/*
+ * Key objects. Handles bare keys which do not yet have certs associated
+ * with them. These are usually short lived, but may exist for several days
+ * while the CA is issuing the certificate.
+ */
+struct pemKeyObjectStr {
+ char *provName;
+ char *containerName;
+ pemKeyParams key;
+ char *ivstring;
+ int cipher;
+};
+typedef struct pemKeyObjectStr pemKeyObject;
+
+/*
+ * Certificate and certificate referenced keys.
+ */
+struct pemCertObjectStr {
+ const char *certStore;
+ NSSItem label;
+ NSSItem subject;
+ NSSItem issuer;
+ NSSItem serial;
+ NSSItem derCert;
+ unsigned char sha1_hash[SHA1_LENGTH];
+ unsigned char md5_hash[MD5_LENGTH];
+ pemKeyParams key;
+ unsigned char *labelData;
+ /* static data: to do, make this dynamic like labelData */
+ unsigned char derSerial[128];
+};
+typedef struct pemCertObjectStr pemCertObject;
+
+/*
+ * Trust
+ */
+struct pemTrustObjectStr {
+ char *nickname;
+};
+typedef struct pemTrustObjectStr pemTrustObject;
+
+typedef enum {
+ pemRaw,
+ pemCert,
+ pemBareKey,
+ pemTrust
+} pemObjectType;
+
+/*
+ * all the various types of objects are abstracted away in cobject and
+ * cfind as pemInternalObjects.
+ */
+struct pemInternalObjectStr {
+ pemObjectType type;
+ union {
+ pemRawObject raw;
+ pemCertObject cert;
+ pemKeyObject key;
+ pemTrustObject trust;
+ } u;
+ CK_OBJECT_CLASS objClass;
+ NSSItem hashKey;
+ NSSItem id;
+ void *idData;
+ unsigned char hashKeyData[128];
+ SECItem *derCert;
+ char *nickname;
+ NSSCKMDObject mdObject;
+ CK_SLOT_ID slotID;
+};
+typedef struct pemInternalObjectStr pemInternalObject;
+
+struct pemTokenStr {
+ PRBool logged_in;
+};
+typedef struct pemTokenStr pemToken;
+
+/* our raw object data array */
+NSS_EXTERN_DATA pemInternalObject nss_pem_data[];
+NSS_EXTERN_DATA const PRUint32 nss_pem_nObjects;
+
+ PRBool logged_in;
+
+/* our raw object data array */
+NSS_EXTERN_DATA pemInternalObject nss_pem_data[];
+NSS_EXTERN_DATA const PRUint32 nss_pem_nObjects;
+
+NSS_EXTERN_DATA pemInternalObject pem_data[];
+NSS_EXTERN_DATA const PRUint32 pem_nObjects;
+
+NSS_EXTERN_DATA const CK_VERSION pem_CryptokiVersion;
+NSS_EXTERN_DATA const NSSUTF8 * pem_ManufacturerID;
+NSS_EXTERN_DATA const NSSUTF8 * pem_LibraryDescription;
+NSS_EXTERN_DATA const CK_VERSION pem_LibraryVersion;
+NSS_EXTERN_DATA const NSSUTF8 * pem_SlotDescription;
+NSS_EXTERN_DATA const CK_VERSION pem_HardwareVersion;
+NSS_EXTERN_DATA const CK_VERSION pem_FirmwareVersion;
+NSS_EXTERN_DATA const NSSUTF8 * pem_TokenLabel;
+NSS_EXTERN_DATA const NSSUTF8 * pem_TokenModel;
+NSS_EXTERN_DATA const NSSUTF8 * pem_TokenSerialNumber;
+
+NSS_EXTERN_DATA const NSSCKMDInstance pem_mdInstance;
+NSS_EXTERN_DATA const NSSCKMDSlot pem_mdSlot;
+NSS_EXTERN_DATA const NSSCKMDToken pem_mdToken;
+NSS_EXTERN_DATA const NSSCKMDMechanism pem_mdMechanismRSA;
+
+NSS_EXTERN NSSCKMDSession *
+pem_CreateSession
+(
+ NSSCKFWSession *fwSession,
+ CK_RV *pError
+);
+
+NSS_EXTERN NSSCKMDFindObjects *
+pem_FindObjectsInit
+(
+ NSSCKFWSession *fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+);
+
+NSS_EXTERN NSSCKMDObject *
+pem_CreateMDObject
+(
+ NSSArena *arena,
+ pemInternalObject *io,
+ CK_RV *pError
+);
+
+#define NSS_PEM_ARRAY_SIZE(x) ((sizeof (x))/(sizeof ((x)[0])))
+
+typedef enum {
+ pemLOWKEYNullKey = 0,
+ pemLOWKEYRSAKey = 1,
+ pemLOWKEYDSAKey = 2,
+ pemLOWKEYDHKey = 4,
+ pemLOWKEYECKey = 5
+} pemLOWKEYType;
+
+/*
+** Low Level private key object
+** This is only used by the raw Crypto engines (crypto), keydb (keydb),
+** and PKCS #11. Everyone else uses the high level key structure.
+*/
+struct pemLOWKEYPrivateKeyStr {
+ PLArenaPool *arena;
+ pemLOWKEYType keyType;
+ union {
+ RSAPrivateKey rsa;
+ DSAPrivateKey dsa;
+ DHPrivateKey dh;
+ ECPrivateKey ec;
+ } u;
+};
+typedef struct pemLOWKEYPrivateKeyStr pemLOWKEYPrivateKey;
+
+SECStatus ReadDERFromFile(SECItem ***derlist, char *filename, PRBool ascii, int *cipher, char **ivstring, PRBool certsonly);
+const NSSItem * pem_FetchAttribute ( pemInternalObject *io, CK_ATTRIBUTE_TYPE type);
+void pem_PopulateModulusExponent(pemInternalObject *io);
+NSSCKMDObject * pem_CreateObject(NSSCKFWInstance *fwInstance, NSSCKFWSession *fwSession, NSSCKMDToken *mdToken, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_RV *pError);
+NSSCKMDSlot *pem_NewSlot( NSSCKFWInstance *fwInstance, CK_RV *pError);
+
+
+PRBool pem_ParseString(const char* inputstring, const char delimiter,
+ PRInt32* numStrings, char*** returnedstrings);
+PRBool pem_FreeParsedStrings(PRInt32 numStrings, char** instrings);
+
+pemInternalObject *
+CreateObject(CK_OBJECT_CLASS objClass, pemObjectType type, SECItem *certDER,
+ SECItem *keyDER, char *filename, int objid, CK_SLOT_ID slotID);
+
+
+/* prsa.c */
+unsigned int pem_PrivateModulusLen(pemLOWKEYPrivateKey *privk);
+
+/* ptoken.c */
+NSSCKMDToken * pem_NewToken(NSSCKFWInstance *fwInstance, CK_RV *pError);
+
+void open_log();
+void close_log();
+void plog(const char *fmt, ...);
+
+#define PEM_H 1
diff --git a/ckpemver.c b/ckpemver.c
new file mode 100644
index 0000000..76ab5df
--- /dev/null
+++ b/ckpemver.c
@@ -0,0 +1,59 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ * Portions created by Red Hat, Inc, are Copyright (C) 2005
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* Library identity and versioning */
+
+#include "nsspem.h"
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_ckpem_rcsid[] = "$Header: NSS Access to Flat Files in PEM format"
+ NSS_CKPEM_LIBRARY_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__ " $";
+const char __nss_ckcapi_sccsid[] = "@(#)NSS Access to Flag Files in PEM format "
+ NSS_CKPEM_LIBRARY_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__;
diff --git a/constants.c b/constants.c
new file mode 100644
index 0000000..d030867
--- /dev/null
+++ b/constants.c
@@ -0,0 +1,77 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * constants.c
+ *
+ * Identification and other constants, all collected here in one place.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef NSSCKT_H
+#include "nssckt.h"
+#endif /* NSSCKT_H */
+
+#ifndef NSSCKBI_H
+#include "nssckbi.h"
+#endif /* NSSCKBI_H */
+
+NSS_IMPLEMENT_DATA const CK_VERSION
+pem_CryptokiVersion = { 2, 1 };
+
+NSS_IMPLEMENT_DATA const NSSUTF8 *
+pem_ManufacturerID = (NSSUTF8 *) "Red Hat, Inc.";
+
+NSS_IMPLEMENT_DATA const NSSUTF8 *
+pem_LibraryDescription = (NSSUTF8 *) "PEM Reader Cryptoki Module";
+
+NSS_IMPLEMENT_DATA const CK_VERSION
+pem_LibraryVersion = { 1, 0 };
+
+NSS_IMPLEMENT_DATA const CK_VERSION
+pem_HardwareVersion = { 1, 0 };
+
+NSS_IMPLEMENT_DATA const CK_VERSION
+pem_FirmwareVersion = { 1, 0 };
+
+NSS_IMPLEMENT_DATA const NSSUTF8 *
+pem_TokenModel = (NSSUTF8 *) "1";
+
+NSS_IMPLEMENT_DATA const NSSUTF8 *
+pem_TokenSerialNumber = (NSSUTF8 *) "1";
diff --git a/nssckbi.h b/nssckbi.h
new file mode 100644
index 0000000..9397c27
--- /dev/null
+++ b/nssckbi.h
@@ -0,0 +1,90 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef NSSCKBI_H
+#define NSSCKBI_H
+
+/*
+ * NSS BUILTINS Version numbers.
+ *
+ * These are the version numbers for the builtins module packaged with
+ * this release on NSS. To determine the version numbers of the builtin
+ * module you are using, use the appropriate PKCS #11 calls.
+ *
+ * These version numbers detail changes to the PKCS #11 interface. They map
+ * to the PKCS #11 spec versions.
+ */
+#define NSS_BUILTINS_CRYPTOKI_VERSION_MAJOR 2
+#define NSS_BUILTINS_CRYPTOKI_VERSION_MINOR 20
+
+/* These version numbers detail the changes
+ * to the list of trusted certificates.
+ *
+ * The NSS_BUILTINS_LIBRARY_VERSION_MINOR macro needs to be bumped
+ * for each NSS minor release AND whenever we change the list of
+ * trusted certificates. 10 minor versions are allocated for each
+ * NSS 3.x branch as follows, allowing us to change the list of
+ * trusted certificates up to 9 times on each branch.
+ * - NSS 3.5 branch: 3-9
+ * - NSS 3.6 branch: 10-19
+ * - NSS 3.7 branch: 20-29
+ * - NSS 3.8 branch: 30-39
+ * - NSS 3.9 branch: 40-49
+ * - NSS 3.10 branch: 50-59
+ * - NSS 3.11 branch: 60-69
+ * ...
+ * - NSS 3.14 branch: 90-99
+ * ...
+ * - NSS 3.30 branch: 250-255
+ *
+ * NSS_BUILTINS_LIBRARY_VERSION_MINOR is a CK_BYTE. It's not clear
+ * whether we may use its full range (0-255) or only 0-99 because
+ * of the comment in the CK_VERSION type definition.
+ */
+#define NSS_BUILTINS_LIBRARY_VERSION_MAJOR 1
+#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 62
+#define NSS_BUILTINS_LIBRARY_VERSION "1.62"
+
+/* These version numbers detail the semantic changes to the ckfw engine. */
+#define NSS_BUILTINS_HARDWARE_VERSION_MAJOR 1
+#define NSS_BUILTINS_HARDWARE_VERSION_MINOR 0
+
+/* These version numbers detail the semantic changes to ckbi itself
+ * (new PKCS #11 objects), etc. */
+#define NSS_BUILTINS_FIRMWARE_VERSION_MAJOR 1
+#define NSS_BUILTINS_FIRMWARE_VERSION_MINOR 0
+
+#endif /* NSSCKBI_H */
diff --git a/nsspem.h b/nsspem.h
new file mode 100644
index 0000000..1547bf4
--- /dev/null
+++ b/nsspem.h
@@ -0,0 +1,75 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ * Portions created by Red Hat, Inc, are Copyright (C) 2005
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef NSSPEM_H
+#define NSSPEM_H
+
+/*
+ * NSS CKPEM Version numbers.
+ *
+ * These are the version numbers for the capi module packaged with
+ * this release on NSS. To determine the version numbers of the builtin
+ * module you are using, use the appropriate PKCS #11 calls.
+ *
+ * These version numbers detail changes to the PKCS #11 interface. They map
+ * to the PKCS #11 spec versions.
+ */
+#define NSS_CKPEM_CRYPTOKI_VERSION_MAJOR 2
+#define NSS_CKPEM_CRYPTOKI_VERSION_MINOR 20
+
+/* These version numbers detail the changes
+ * to the list of trusted certificates.
+ *
+ * NSS_CKPEM_LIBRARY_VERSION_MINOR is a CK_BYTE. It's not clear
+ * whether we may use its full range (0-255) or only 0-99 because
+ * of the comment in the CK_VERSION type definition.
+ */
+#define NSS_CKPEM_LIBRARY_VERSION_MAJOR 1
+#define NSS_CKPEM_LIBRARY_VERSION_MINOR 1
+#define NSS_CKPEM_LIBRARY_VERSION "1.1"
+
+/* These version numbers detail the semantic changes to the ckfw engine. */
+#define NSS_CKPEM_HARDWARE_VERSION_MAJOR 1
+#define NSS_CKPEM_HARDWARE_VERSION_MINOR 0
+
+/* These version numbers detail the semantic changes to ckbi itself
+ * (new PKCS #11 objects), etc. */
+#define NSS_CKPEM_FIRMWARE_VERSION_MAJOR 1
+#define NSS_CKPEM_FIRMWARE_VERSION_MINOR 0
+
+#endif /* NSSCKBI_H */
diff --git a/pargs.c b/pargs.c
new file mode 100644
index 0000000..f292a8b
--- /dev/null
+++ b/pargs.c
@@ -0,0 +1,162 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+#include <nspr.h>
+
+void *pem_Malloc(const PRInt32 sz)
+{
+ return PR_Malloc(sz);
+}
+
+char *pem_StrNdup(const char *instr, PRInt32 inlen)
+{
+ if (!instr) {
+ return NULL;
+ }
+
+ size_t len = inlen;
+ if (!len) {
+ return NULL;
+ }
+ char *buffer = (char *) pem_Malloc(len + 1);
+ if (!buffer) {
+ return NULL;
+ }
+ memcpy(buffer, instr, len);
+ buffer[len] = 0; /* NULL termination */
+ return buffer;
+}
+
+char *pem_Strdup(const char *instr)
+{
+ if (!instr) {
+ return NULL;
+ }
+
+ size_t len = strlen(instr);
+ return pem_StrNdup(instr, len);
+}
+
+void pem_Free(char *instr)
+{
+ if (!instr) {
+ PR_ASSERT(0);
+ }
+ PR_Free(instr);
+}
+
+void
+addString(char ***returnedstrings, char *newstring, PRInt32 stringcount)
+{
+ char **stringarray = NULL;
+ if (!returnedstrings || !newstring) {
+ return;
+ }
+ if (!stringcount) {
+ /* first string to be added, allocate buffer */
+ *returnedstrings =
+ (char **) PR_Malloc(sizeof(char *) * (stringcount + 1));
+ stringarray = *returnedstrings;
+ } else {
+ stringarray = (char **) PR_Realloc(*returnedstrings,
+ sizeof(char *) * (stringcount + 1));
+ if (stringarray) {
+ *returnedstrings = stringarray;
+ }
+ }
+ if (stringarray) {
+ stringarray[stringcount] = newstring;
+ }
+}
+
+PRBool
+pem_ParseString(const char *inputstring, const char delimiter,
+ PRInt32 * numStrings, char ***returnedstrings)
+{
+ if (!inputstring || !delimiter || !numStrings || !returnedstrings) {
+ /* we need a string and a non-zero delimiter, as well as
+ * a valid place to return the strings and count
+ */
+ return PR_FALSE;
+ }
+ char nextchar;
+ char *instring = (char *) inputstring;
+ *numStrings = 0;
+ *returnedstrings = NULL;
+
+ while ((nextchar = *instring)) {
+ unsigned long len = 0;
+ char *next = (char *) strchr(instring, delimiter);
+ if (next) {
+ /* current string string */
+ len = next - instring;
+ } else {
+ /* last string length */
+ len = strlen(instring);
+ }
+
+ if (len > 0) {
+ char *newstring = pem_StrNdup(instring, len);
+
+ addString(returnedstrings, newstring, (*numStrings)++);
+
+ instring += len;
+ }
+
+ if (delimiter == *instring) {
+ instring++; /* skip past next delimiter */
+ }
+ }
+ return PR_TRUE;
+}
+
+PRBool pem_FreeParsedStrings(PRInt32 numStrings, char **instrings)
+{
+ if (!numStrings || !instrings) {
+ return PR_FALSE;
+ }
+ PRInt32 counter;
+ for (counter = 0; counter < numStrings; counter++) {
+ char *astring = instrings[counter];
+ if (astring) {
+ pem_Free(astring);
+ }
+ }
+ PR_Free((void *) instrings);
+ return PR_TRUE;
+}
diff --git a/pfind.c b/pfind.c
new file mode 100644
index 0000000..0c6a9a7
--- /dev/null
+++ b/pfind.c
@@ -0,0 +1,588 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+
+/*
+ * pfind.c
+ *
+ * This file implements the NSSCKMDFindObjects object for the
+ * "PEM objects" cryptoki module.
+ */
+
+NSS_EXTERN_DATA pemInternalObject **gobj;
+NSS_EXTERN_DATA int pem_nobjs;
+
+struct pemFOStr {
+ NSSArena *arena;
+ CK_ULONG n;
+ CK_ULONG i;
+ pemInternalObject **objs;
+};
+
+#define PEM_ITEM_CHUNK 512
+
+#define PUT_Object(obj,err) \
+ { \
+ if (count >= size) { \
+ *listp = *listp ? \
+ nss_ZREALLOCARRAY(*listp, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) : \
+ nss_ZNEWARRAY(NULL, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) ; \
+ if ((pemInternalObject **)NULL == *listp) { \
+ err = CKR_HOST_MEMORY; \
+ goto loser; \
+ } \
+ size += PEM_ITEM_CHUNK; \
+ } \
+ (*listp)[ count ] = (obj); \
+ count++; \
+ }
+
+static void
+pem_mdFindObjects_Final
+(
+ NSSCKMDFindObjects * mdFindObjects,
+ NSSCKFWFindObjects * fwFindObjects,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ struct pemFOStr *fo = (struct pemFOStr *) mdFindObjects->etc;
+ NSSArena *arena = fo->arena;
+
+ nss_ZFreeIf(fo->objs);
+ nss_ZFreeIf(fo);
+ nss_ZFreeIf(mdFindObjects);
+ if ((NSSArena *) NULL != arena) {
+ NSSArena_Destroy(arena);
+ }
+
+ return;
+}
+
+static NSSCKMDObject *
+pem_mdFindObjects_Next
+(
+ NSSCKMDFindObjects * mdFindObjects,
+ NSSCKFWFindObjects * fwFindObjects,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSArena * arena,
+ CK_RV * pError
+)
+{
+ struct pemFOStr *fo = (struct pemFOStr *) mdFindObjects->etc;
+ pemInternalObject *io;
+
+ plog("pem_FindObjects_Next: ");
+
+ if (fo->i == fo->n) {
+ plog("Done creating objects\n");
+ *pError = CKR_OK;
+ return (NSSCKMDObject *) NULL;
+ }
+
+ io = fo->objs[fo->i];
+ fo->i++;
+
+ plog("Creating object for type %d\n", io->type);
+
+ return pem_CreateMDObject(arena, io, pError);
+}
+
+#if 0
+static int
+pem_derUnwrapInt(unsigned char *src, int size, unsigned char **dest)
+{
+ unsigned char *start = src;
+ int len = 0;
+
+ if (*src++ != 2) {
+ return 0;
+ }
+ len = *src++;
+ if (len & 0x80) {
+ int count = len & 0x7f;
+ len = 0;
+
+ if (count + 2 > size) {
+ return 0;
+ }
+ while (count-- > 0) {
+ len = (len << 8) | *src++;
+ }
+ }
+ if (len + (src - start) != size) {
+ return 0;
+ }
+ *dest = src;
+ return len;
+}
+#endif
+
+static char * pem_attr_name(CK_ATTRIBUTE_TYPE type) {
+ switch(type) {
+ case CKA_CLASS:
+ return "CKA_CLASS";
+ case CKA_TOKEN:
+ return "CKA_TOKEN";
+ case CKA_PRIVATE:
+ return "CKA_PRIVATE";
+ case CKA_LABEL:
+ return "CKA_LABEL";
+ case CKA_APPLICATION:
+ return "CKA_APPLICATION";
+ case CKA_VALUE:
+ return "CKA_VALUE";
+ case CKA_OBJECT_ID:
+ return "CKA_OBJECT_ID";
+ case CKA_CERTIFICATE_TYPE:
+ return "CKA_CERTIFICATE_TYPE";
+ case CKA_ISSUER:
+ return "CKA_ISSUER";
+ case CKA_SERIAL_NUMBER:
+ return "CKA_SERIAL_NUMBER";
+ case CKA_ID:
+ return "CKA_ID";
+ default:
+ return "unknown";
+ }
+}
+
+static CK_BBOOL
+pem_attrmatch(CK_ATTRIBUTE_PTR a, pemInternalObject * o) {
+ PRBool prb;
+ const NSSItem *b;
+
+ b = pem_FetchAttribute(o, a->type);
+ if (b == NULL) {
+ plog("pem_attrmatch %s %08x: CK_FALSE attr not found\n", pem_attr_name(a->type), a->type);
+ return CK_FALSE;
+ }
+
+ if (a->ulValueLen != b->size) {
+ plog("pem_attrmatch %s %08x: CK_FALSE size mismatch %d vs %d\n", pem_attr_name(a->type), a->type, a->ulValueLen, b->size);
+ return CK_FALSE;
+ }
+
+ prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *) NULL);
+
+ if (PR_TRUE == prb) {
+ plog("pem_attrmatch %s %08x: CK_TRUE\n", pem_attr_name(a->type), a->type);
+ return CK_TRUE;
+ } else {
+ plog("pem_attrmatch %s %08x: CK_FALSE\n", pem_attr_name(a->type), a->type);
+ plog("type: %08x, label: %s a->pValue %08x, b->data %08x\n", o->objClass, o->u.cert.label.data, a->pValue, b->data);
+ return CK_FALSE;
+ }
+}
+
+static CK_BBOOL
+pem_match
+(
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ pemInternalObject * o
+)
+{
+ CK_ULONG i;
+
+ for (i = 0; i < ulAttributeCount; i++) {
+ if (CK_FALSE == pem_attrmatch(&pTemplate[i], o)) {
+ plog("pem_match: CK_FALSE\n");
+ return CK_FALSE;
+ }
+ }
+
+ /* Every attribute passed */
+ plog("pem_match: CK_TRUE\n");
+ return CK_TRUE;
+}
+
+CK_OBJECT_CLASS
+pem_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount)
+{
+ CK_ULONG i;
+
+ for (i = 0; i < ulAttributeCount; i++) {
+ if (pTemplate[i].type == CKA_CLASS) {
+ return *(CK_OBJECT_CLASS *) pTemplate[i].pValue;
+ }
+ }
+ /* need to return a value that says 'fetch them all' */
+ return CK_INVALID_HANDLE;
+}
+
+static PRUint32
+collect_objects(CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ pemInternalObject *** listp,
+ CK_RV * pError, CK_SLOT_ID slotID)
+{
+ PRUint32 i;
+ PRUint32 count = 0;
+ PRUint32 size = 0;
+ CK_OBJECT_CLASS objClass;
+
+ plog("collect_objects slot #%ld, ", slotID);
+ plog("%d attributes, ", ulAttributeCount);
+ plog("%d objects to look through.\n", pem_nobjs);
+ plog("Looking for: ");
+ /*
+ * now handle the various object types
+ */
+ objClass = pem_GetObjectClass(pTemplate, ulAttributeCount);
+ *pError = CKR_OK;
+ switch (objClass) {
+ case CKO_CERTIFICATE:
+ plog("CKO_CERTIFICATE\n");
+ for (i = 0; i < pem_nobjs; i++) {
+ plog(" %d type = %d\n", i, gobj[i]->type);
+ if (gobj[i]->type != pemCert)
+ continue;
+ if ((slotID == gobj[i]->slotID)
+ && (CK_TRUE ==
+ pem_match(pTemplate, ulAttributeCount, gobj[i]))) {
+
+ pemInternalObject *o = NULL;
+
+ o = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == o) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&o->u.cert, 0, sizeof(o->u.cert));
+ o->objClass = objClass;
+ o->type = pemCert;
+ o->derCert = nss_ZNEW(NULL, SECItem);
+ o->derCert->data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len);
+ o->derCert->len = gobj[i]->derCert->len;
+ nsslibc_memcpy(o->derCert->data, gobj[i]->derCert->data,
+ gobj[i]->derCert->len);
+
+ o->u.cert.subject.data =
+ (void *) nss_ZAlloc(NULL,
+ gobj[i]->u.cert.subject.size);
+ o->u.cert.subject.size = gobj[i]->u.cert.subject.size;
+ nsslibc_memcpy(o->u.cert.subject.data,
+ gobj[i]->u.cert.subject.data,
+ gobj[i]->u.cert.subject.size);
+
+ o->u.cert.issuer.data =
+ (void *) nss_ZAlloc(NULL,
+ gobj[i]->u.cert.issuer.size);
+ o->u.cert.issuer.size = gobj[i]->u.cert.issuer.size;
+ nsslibc_memcpy(o->u.cert.issuer.data,
+ gobj[i]->u.cert.issuer.data,
+ gobj[i]->u.cert.issuer.size);
+
+ o->u.cert.serial.data =
+ (void *) nss_ZAlloc(NULL,
+ gobj[i]->u.cert.serial.size);
+ o->u.cert.serial.size = gobj[i]->u.cert.serial.size;
+ nsslibc_memcpy(o->u.cert.serial.data,
+ gobj[i]->u.cert.serial.data,
+ gobj[i]->u.cert.serial.size);
+
+ o->nickname =
+ (char *) nss_ZAlloc(NULL,
+ strlen(gobj[i]->nickname) + 1);
+ strcpy(o->nickname, gobj[i]->nickname);
+ o->id.data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->id.size);
+ (void) nsslibc_memcpy(o->id.data, gobj[i]->id.data,
+ gobj[i]->id.size);
+ o->id.size = gobj[i]->id.size;
+ PUT_Object(o, *pError);
+ } /* match */
+ } /* for */
+ break;
+ case CKO_PUBLIC_KEY:
+#if 0
+ for (i = 0; i < pem_nobjs; i++) {
+ if (gobj[i]->type != pemBareKey)
+ continue;
+ if (CK_TRUE == pem_match(pTemplate, ulAttributeCount, gobj[i])) {
+ pemInternalObject *o;
+
+ o = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == o) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&o->u.key, 0, sizeof(o->u.key));
+ o->objClass = objClass;
+ o->type = pemBareKey;
+ o->derCert = nss_ZNEW(NULL, SECItem);
+ o->derCert->data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len);
+ o->derCert->len = gobj[i]->derCert->len;
+ o->id.data =
+ (void *) nss_ZAlloc(NULL,
+ sizeof(gobj[i]->id.data));
+ o->id.data = gobj[i]->id.data;
+ o->id.size = gobj[i]->id.size;
+ nsslibc_memcpy(o->derCert->data, gobj[i]->derCert->data,
+ gobj[i]->derCert->len);
+ o->nickname =
+ (char *) nss_ZAlloc(NULL,
+ strlen(gobj[i]->nickname) + 1);
+ strcpy(o->nickname, gobj[i]->nickname);
+ o->u.key.key.privateKey = nss_ZNEW(NULL, SECItem);
+ o->u.key.key.privateKey->data =
+ (void *) nss_ZAlloc(NULL,
+ gobj[i]->u.key.key.privateKey->
+ len);
+ o->u.key.key.privateKey->len =
+ gobj[i]->u.key.key.privateKey->len;
+ nsslibc_memcpy(o->u.key.key.privateKey->data,
+ gobj[i]->u.key.key.privateKey->data,
+ gobj[i]->u.key.key.privateKey->len);
+
+ PUT_Object(o, *pError);
+ } // match
+ } // for
+ goto done;
+ break;
+#endif
+ case CKO_PRIVATE_KEY:
+ plog("CKO_PRIVATE_KEY\n");
+ for (i = 0; i < pem_nobjs; i++) {
+ if (gobj[i]->type != pemBareKey)
+ continue;
+ if ((slotID == gobj[i]->slotID)
+ && (CK_TRUE ==
+ pem_match(pTemplate, ulAttributeCount, gobj[i]))) {
+ pemInternalObject *o;
+
+ o = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == o) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&o->u.key, 0, sizeof(o->u.key));
+ o->objClass = objClass;
+ o->type = pemBareKey;
+ o->derCert = nss_ZNEW(NULL, SECItem);
+ o->derCert->data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len);
+ o->derCert->len = gobj[i]->derCert->len;
+ o->id.data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->id.size);
+ (void) nsslibc_memcpy(o->id.data, gobj[i]->id.data,
+ gobj[i]->id.size);
+ o->id.size = gobj[i]->id.size;
+ nsslibc_memcpy(o->derCert->data, gobj[i]->derCert->data,
+ gobj[i]->derCert->len);
+ o->nickname =
+ (char *) nss_ZAlloc(NULL,
+ strlen(gobj[i]->nickname) + 1);
+ strcpy(o->nickname, gobj[i]->nickname);
+ o->u.key.key.privateKey = nss_ZNEW(NULL, SECItem);
+ o->u.key.key.privateKey->data =
+ (void *) nss_ZAlloc(NULL,
+ gobj[i]->u.key.key.privateKey->
+ len);
+ o->u.key.key.privateKey->len =
+ gobj[i]->u.key.key.privateKey->len;
+ nsslibc_memcpy(o->u.key.key.privateKey->data,
+ gobj[i]->u.key.key.privateKey->data,
+ gobj[i]->u.key.key.privateKey->len);
+
+ PUT_Object(o, *pError);
+ } /* match */
+ } /* for */
+ goto done;
+ break;
+ case CKO_NETSCAPE_TRUST:
+ plog("CKO_NETSCAPE_TRUST\n");
+ for (i = 0; i < pem_nobjs; i++) {
+ if (gobj[i]->type != pemTrust)
+ continue;
+ if ((slotID == gobj[i]->slotID)
+ && (CK_TRUE ==
+ pem_match(pTemplate, ulAttributeCount, gobj[i]))) {
+ pemInternalObject *o;
+
+ o = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == o) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&o->u.trust, 0, sizeof(o->u.trust));
+ o->objClass = objClass;
+ o->type = pemTrust;
+ o->derCert = nss_ZNEW(NULL, SECItem);
+ o->derCert->data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len);
+ o->derCert->len = gobj[i]->derCert->len;
+ nsslibc_memcpy(o->derCert->data, gobj[i]->derCert->data,
+ gobj[i]->derCert->len);
+ o->nickname =
+ (char *) nss_ZAlloc(NULL,
+ strlen(gobj[i]->nickname) + 1);
+ strcpy(o->nickname, gobj[i]->nickname);
+ o->id.data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->id.size);
+ (void) nsslibc_memcpy(o->id.data, gobj[i]->id.data,
+ gobj[i]->id.size);
+ o->id.size = gobj[i]->id.size;
+
+ PUT_Object(o, *pError);
+ } /* match */
+ } /* for */
+ goto done;
+ case CKO_NETSCAPE_CRL:
+ plog("CKO_NETSCAPE_CRL\n");
+ break;
+ case CKO_NETSCAPE_SMIME:
+ plog("CKO_NETSCAPE_SMIME\n");
+ break;
+ case CKO_NETSCAPE_BUILTIN_ROOT_LIST:
+ plog("CKO_NETSCAPE_BUILTIN_ROOT_LIST\n");
+ break;
+ case CK_INVALID_HANDLE:
+ plog("CK_INVALID_HANDLE\n");
+ break;
+ default:
+ plog("no other object types %08x\n", objClass);
+ goto done; /* no other object types we understand in this module */
+ }
+
+ if (CKR_OK != *pError) {
+ goto loser;
+ }
+
+ done:
+ plog("collect_objects: Found %d\n", count);
+ return count;
+ loser:
+ nss_ZFreeIf(*listp);
+ return 0;
+
+}
+
+NSS_IMPLEMENT NSSCKMDFindObjects *
+pem_FindObjectsInit
+(
+ NSSCKFWSession * fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV * pError
+)
+{
+ NSSArena *arena;
+ NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *) NULL;
+ struct pemFOStr *fo = (struct pemFOStr *) NULL;
+ pemInternalObject **temp = (pemInternalObject **) NULL;
+ NSSCKFWSlot *fwSlot;
+ CK_SLOT_ID slotID;
+
+ plog("pem_FindObjectsInit\n");
+ fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+ if ((NSSCKFWSlot *) NULL == fwSlot) {
+ goto loser;
+ }
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ arena = NSSArena_Create();
+ if ((NSSArena *) NULL == arena) {
+ goto loser;
+ }
+
+ rv = nss_ZNEW(arena, NSSCKMDFindObjects);
+ if ((NSSCKMDFindObjects *) NULL == rv) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+
+ fo = nss_ZNEW(arena, struct pemFOStr);
+ if ((struct pemFOStr *) NULL == fo) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+
+ fo->arena = arena;
+ /* fo->n and fo->i are already zero */
+
+ rv->etc = (void *) fo;
+ rv->Final = pem_mdFindObjects_Final;
+ rv->Next = pem_mdFindObjects_Next;
+ rv->null = (void *) NULL;
+
+ fo->n =
+ collect_objects(pTemplate, ulAttributeCount, &temp, pError,
+ slotID);
+ if (*pError != CKR_OK) {
+ goto loser;
+ }
+
+ fo->objs = nss_ZNEWARRAY(arena, pemInternalObject *, fo->n);
+ if ((pemInternalObject **) NULL == fo->objs) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+
+ (void) nsslibc_memcpy(fo->objs, temp,
+ sizeof(pemInternalObject *) * fo->n);
+
+ nss_ZFreeIf(temp);
+ temp = (pemInternalObject **) NULL;
+
+ return rv;
+
+ loser:
+ nss_ZFreeIf(temp);
+ nss_ZFreeIf(fo);
+ nss_ZFreeIf(rv);
+ if ((NSSArena *) NULL != arena) {
+ NSSArena_Destroy(arena);
+ }
+ return (NSSCKMDFindObjects *) NULL;
+}
diff --git a/pinst.c b/pinst.c
new file mode 100644
index 0000000..17ffff0
--- /dev/null
+++ b/pinst.c
@@ -0,0 +1,602 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include <stdlib.h>
+#include "ckpem.h"
+#include "blapi.h"
+
+/*
+ * pinstance.c
+ *
+ * This file implements the NSSCKMDInstance object for the
+ * "PEM objects" cryptoki module.
+ */
+
+static PRBool pemInitialized = PR_FALSE;
+
+pemInternalObject **gobj;
+int pem_nobjs = 0;
+int token_needsLogin[NUM_SLOTS];
+
+PRInt32 size = 0;
+PRInt32 count = 0;
+
+#define PEM_ITEM_CHUNK 512
+
+#define PUT_Object(obj,err) \
+ { \
+ if (count >= size) { \
+ gobj = gobj ? \
+ nss_ZREALLOCARRAY(gobj, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) : \
+ nss_ZNEWARRAY(NULL, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) ; \
+ if ((pemInternalObject **)NULL == gobj) { \
+ err = CKR_HOST_MEMORY; \
+ goto loser; \
+ } \
+ size += PEM_ITEM_CHUNK; \
+ } \
+ (gobj)[ count ] = (obj); \
+ count++; \
+ }
+
+/*
+ * simple cert decoder to avoid the cost of asn1 engine
+ */
+static unsigned char *
+dataStart(unsigned char *buf, unsigned int length,
+ unsigned int *data_length,
+ PRBool includeTag, unsigned char *rettag)
+{
+ unsigned char tag;
+ unsigned int used_length = 0;
+
+ tag = buf[used_length++];
+
+ if (rettag) {
+ *rettag = tag;
+ }
+
+ /* blow out when we come to the end */
+ if (tag == 0) {
+ return NULL;
+ }
+
+ *data_length = buf[used_length++];
+
+ if (*data_length & 0x80) {
+ int len_count = *data_length & 0x7f;
+
+ *data_length = 0;
+
+ while (len_count-- > 0) {
+ *data_length = (*data_length << 8) | buf[used_length++];
+ }
+ }
+
+ if (*data_length > (length - used_length)) {
+ *data_length = length - used_length;
+ return NULL;
+ }
+ if (includeTag)
+ *data_length += used_length;
+
+ return (buf + (includeTag ? 0 : used_length));
+}
+
+static int
+GetCertFields(unsigned char *cert, int cert_length,
+ SECItem * issuer, SECItem * serial, SECItem * derSN,
+ SECItem * subject, SECItem * valid, SECItem * subjkey)
+{
+ unsigned char *buf;
+ unsigned int buf_length;
+ unsigned char *dummy;
+ unsigned int dummylen;
+
+ /* get past the signature wrap */
+ buf = dataStart(cert, cert_length, &buf_length, PR_FALSE, NULL);
+ if (buf == NULL)
+ return SECFailure;
+ /* get into the raw cert data */
+ buf = dataStart(buf, buf_length, &buf_length, PR_FALSE, NULL);
+ if (buf == NULL)
+ return SECFailure;
+ /* skip past any optional version number */
+ if ((buf[0] & 0xa0) == 0xa0) {
+ dummy = dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
+ if (dummy == NULL)
+ return SECFailure;
+ buf_length -= (dummy - buf) + dummylen;
+ buf = dummy + dummylen;
+ }
+ /* serial number */
+ if (derSN) {
+ derSN->data =
+ dataStart(buf, buf_length, &derSN->len, PR_TRUE, NULL);
+ }
+ serial->data =
+ dataStart(buf, buf_length, &serial->len, PR_FALSE, NULL);
+ if (serial->data == NULL)
+ return SECFailure;
+ buf_length -= (serial->data - buf) + serial->len;
+ buf = serial->data + serial->len;
+ /* skip the OID */
+ dummy = dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
+ if (dummy == NULL)
+ return SECFailure;
+ buf_length -= (dummy - buf) + dummylen;
+ buf = dummy + dummylen;
+ /* issuer */
+ issuer->data = dataStart(buf, buf_length, &issuer->len, PR_TRUE, NULL);
+ if (issuer->data == NULL)
+ return SECFailure;
+ buf_length -= (issuer->data - buf) + issuer->len;
+ buf = issuer->data + issuer->len;
+
+ /* only wanted issuer/SN */
+ if (valid == NULL) {
+ return SECSuccess;
+ }
+ /* validity */
+ valid->data = dataStart(buf, buf_length, &valid->len, PR_FALSE, NULL);
+ if (valid->data == NULL)
+ return SECFailure;
+ buf_length -= (valid->data - buf) + valid->len;
+ buf = valid->data + valid->len;
+ /*subject */
+ subject->data =
+ dataStart(buf, buf_length, &subject->len, PR_TRUE, NULL);
+ if (subject->data == NULL)
+ return SECFailure;
+ buf_length -= (subject->data - buf) + subject->len;
+ buf = subject->data + subject->len;
+ /* subject key info */
+ subjkey->data =
+ dataStart(buf, buf_length, &subjkey->len, PR_TRUE, NULL);
+ if (subjkey->data == NULL)
+ return SECFailure;
+ buf_length -= (subjkey->data - buf) + subjkey->len;
+ buf = subjkey->data + subjkey->len;
+ return SECSuccess;
+}
+
+pemInternalObject *
+CreateObject(CK_OBJECT_CLASS objClass,
+ pemObjectType type, SECItem * certDER,
+ SECItem * keyDER, char *filename,
+ int objid, CK_SLOT_ID slotID)
+{
+ pemInternalObject *o;
+ SECItem subject;
+ SECItem issuer;
+ SECItem serial;
+ SECItem derSN;
+ SECItem valid;
+ SECItem subjkey;
+ char id[16];
+ char *nickname;
+ int len;
+
+ o = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == o) {
+ return NULL;
+ }
+
+ nickname = strrchr(filename, '/');
+ if (nickname)
+ nickname++;
+ else
+ nickname = filename;
+
+ switch (objClass) {
+ case CKO_CERTIFICATE:
+ plog("Creating cert nick %s id %d in slot %ld\n", nickname, objid, slotID);
+ memset(&o->u.cert, 0, sizeof(o->u.cert));
+ break;
+ case CKO_PRIVATE_KEY:
+ plog("Creating key id %d in slot %ld\n", objid, slotID);
+ memset(&o->u.key, 0, sizeof(o->u.key));
+ break;
+ case CKO_NETSCAPE_TRUST:
+ plog("Creating trust nick %s id %d in slot %ld\n", nickname, objid, slotID);
+ memset(&o->u.trust, 0, sizeof(o->u.trust));
+ break;
+ }
+ o->objClass = objClass;
+ o->type = type;
+ o->slotID = slotID;
+ o->derCert = nss_ZNEW(NULL, SECItem);
+ o->derCert->data = (void *) nss_ZAlloc(NULL, certDER->len);
+ o->derCert->len = certDER->len;
+ nsslibc_memcpy(o->derCert->data, certDER->data, certDER->len);
+
+ switch (objClass) {
+ case CKO_CERTIFICATE:
+ case CKO_NETSCAPE_TRUST:
+ GetCertFields(o->derCert->data,
+ o->derCert->len, &issuer, &serial,
+ &derSN, &subject, &valid, &subjkey);
+
+ o->u.cert.subject.data = (void *) nss_ZAlloc(NULL, subject.len);
+ o->u.cert.subject.size = subject.len;
+ nsslibc_memcpy(o->u.cert.subject.data, subject.data, subject.len);
+
+ o->u.cert.issuer.data = (void *) nss_ZAlloc(NULL, issuer.len);
+ o->u.cert.issuer.size = issuer.len;
+ nsslibc_memcpy(o->u.cert.issuer.data, issuer.data, issuer.len);
+
+ o->u.cert.serial.data = (void *) nss_ZAlloc(NULL, serial.len);
+ o->u.cert.serial.size = serial.len;
+ nsslibc_memcpy(o->u.cert.serial.data, serial.data, serial.len);
+ break;
+ case CKO_PRIVATE_KEY:
+ o->u.key.key.privateKey = nss_ZNEW(NULL, SECItem);
+ o->u.key.key.privateKey->data =
+ (void *) nss_ZAlloc(NULL, keyDER->len);
+ o->u.key.key.privateKey->len = keyDER->len;
+ nsslibc_memcpy(o->u.key.key.privateKey->data, keyDER->data,
+ keyDER->len);
+ }
+
+ o->nickname = (char *) nss_ZAlloc(NULL, strlen(nickname) + 1);
+ strcpy(o->nickname, nickname);
+
+ sprintf(id, "%d", objid);
+
+ len = strlen(id) + 1; /* zero terminate */
+ o->id.data = (void *) nss_ZAlloc(NULL, len);
+ (void) nsslibc_memcpy(o->id.data, id, len);
+ o->id.size = len;
+
+ return o;
+}
+
+CK_RV
+AddCertificate(char *certfile, char *keyfile, PRBool cacert,
+ CK_SLOT_ID slotID)
+{
+ pemInternalObject *o;
+ SECItem certDER;
+ CK_RV error = 0;
+ int objid, i;
+ int nobjs = 0;
+ SECItem **objs = NULL;
+ char *ivstring = NULL;
+ int cipher;
+
+ certDER.data = NULL;
+ nobjs = ReadDERFromFile(&objs, certfile, PR_TRUE, &cipher, &ivstring, PR_TRUE /* certs only */);
+ if (nobjs <= 0) {
+ nss_ZFreeIf(objs);
+ return CKR_GENERAL_ERROR;
+ }
+
+ /* For now load as many certs as are in the file for CAs only */
+ if (cacert) {
+ for (i = 0; i < nobjs; i++) {
+ char nickname[1024];
+ objid = pem_nobjs + 1;
+
+ snprintf(nickname, 1024, "%s - %d", certfile, i);
+
+ o = CreateObject(CKO_CERTIFICATE, pemCert, objs[i], NULL,
+ nickname, 0, slotID);
+ if (o == NULL) {
+ error = CKR_GENERAL_ERROR;
+ goto loser;
+ }
+ PUT_Object(o, error);
+ if (error != CKR_OK)
+ goto loser;
+ o = NULL;
+ pem_nobjs++;
+
+ /* Add the CA trust object */
+ o = CreateObject(CKO_NETSCAPE_TRUST, pemTrust, objs[i], NULL,
+ nickname, 0, slotID);
+ if (o == NULL) {
+ error = CKR_GENERAL_ERROR;
+ goto loser;
+ }
+ PUT_Object(o, error);
+ pem_nobjs++;
+ } /* for */
+ } else {
+ objid = pem_nobjs + 1;
+ o = CreateObject(CKO_CERTIFICATE, pemCert, objs[0], NULL, certfile,
+ objid, slotID);
+ if (o == NULL) {
+ error = CKR_GENERAL_ERROR;
+ goto loser;
+ }
+
+ PUT_Object(o, error);
+
+ if (error != CKR_OK)
+ goto loser;
+
+ o = NULL;
+ pem_nobjs++;
+
+ if (keyfile) { /* add the private key */
+ SECItem **keyobjs = NULL;
+ int kobjs = 0;
+ kobjs =
+ ReadDERFromFile(&keyobjs, keyfile, PR_TRUE, &cipher,
+ &ivstring, PR_FALSE);
+ if (kobjs < 1) {
+ error = CKR_GENERAL_ERROR;
+ goto loser;
+ }
+ o = CreateObject(CKO_PRIVATE_KEY, pemBareKey, objs[0],
+ keyobjs[0], certfile, objid, slotID);
+ if (o == NULL) {
+ error = CKR_GENERAL_ERROR;
+ goto loser;
+ }
+
+ PUT_Object(o, error);
+ pem_nobjs++;
+ }
+ }
+
+ nss_ZFreeIf(objs);
+ return CKR_OK;
+
+ loser:
+ nss_ZFreeIf(objs);
+ nss_ZFreeIf(o);
+ return error;
+}
+
+CK_RV
+pem_Initialize
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSUTF8 * configurationData
+)
+{
+ CK_RV rv;
+ /* parse the initialization string and initialize CRLInstances */
+ char **certstrings = NULL;
+ PRInt32 numcerts = 0;
+ PRBool status, error = PR_FALSE;
+ int i;
+
+ if (pemInitialized) {
+ return CKR_OK;
+ }
+ RNG_RNGInit();
+
+ open_log();
+
+ plog("pem_Initialize\n");
+
+ unsigned char *modparms = NULL;
+ if (!fwInstance) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ CK_C_INITIALIZE_ARGS_PTR modArgs =
+ NSSCKFWInstance_GetInitArgs(fwInstance);
+ if (!modArgs) {
+ goto done;
+ }
+ if (modArgs->LibraryParameters) {
+ modparms = (unsigned char *) modArgs->LibraryParameters;
+ }
+ if (modparms)
+ plog("Initialized with %s\n", modparms);
+
+ /*
+ * The initialization string format is a space-delimited file of
+ * pairs of paths which are delimited by a semi-colon. The first
+ * entry of the pair is the path to the certificate file. The
+ * second is the path to the key file.
+ *
+ * CA certificates do not need the semi-colon.
+ *
+ * Example:
+ * /etc/certs/server.pem;/etc/certs/server.key /etc/certs/ca.pem
+ *
+ */
+ status =
+ pem_ParseString((const char *) modparms, ' ', &numcerts,
+ &certstrings);
+ if (status == PR_FALSE) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ for (i = 0; i < numcerts && error != PR_TRUE; i++) {
+ char *cert = certstrings[i];
+ PRInt32 attrcount = 0;
+ char **certattrs = NULL;
+ status = pem_ParseString(cert, ';', &attrcount, &certattrs);
+ if (status == PR_FALSE) {
+ error = PR_TRUE;
+ break;
+ }
+
+ if (error == PR_FALSE) {
+ if (attrcount == 1) /* CA certificate */
+ rv = AddCertificate(certattrs[0], NULL, PR_TRUE, 0);
+ else
+ rv = AddCertificate(certattrs[0], certattrs[1], PR_FALSE,
+ 0);
+
+ if (rv != CKR_OK) {
+ error = PR_TRUE;
+ status = PR_FALSE;
+ }
+ }
+ pem_FreeParsedStrings(attrcount, certattrs);
+ }
+ pem_FreeParsedStrings(numcerts, certstrings);
+
+ if (status == PR_FALSE) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ for (i = 0; i < NUM_SLOTS; i++)
+ token_needsLogin[i] = PR_FALSE;
+
+ done:
+
+ PR_AtomicSet(&pemInitialized, PR_TRUE);
+
+ return CKR_OK;
+}
+
+void
+pem_Finalize
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ plog("pem_Finalize\n");
+ if (!pemInitialized)
+ return;
+
+ PR_AtomicSet(&pemInitialized, PR_FALSE);
+
+ return;
+}
+
+/*
+ * NSSCKMDInstance methods
+ */
+
+static CK_ULONG
+pem_mdInstance_GetNSlots
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (CK_ULONG) NUM_SLOTS;
+}
+
+static CK_VERSION
+pem_mdInstance_GetCryptokiVersion
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_CryptokiVersion;
+}
+
+static NSSUTF8 *
+pem_mdInstance_GetManufacturerID
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_ManufacturerID;
+}
+
+static NSSUTF8 *
+pem_mdInstance_GetLibraryDescription
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_LibraryDescription;
+}
+
+static CK_VERSION
+pem_mdInstance_GetLibraryVersion
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_LibraryVersion;
+}
+
+static CK_RV
+pem_mdInstance_GetSlots
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSCKMDSlot * slots[]
+)
+{
+ int i;
+ CK_RV pError;
+
+ for (i = 0; i < NUM_SLOTS; i++) {
+ slots[i] = (NSSCKMDSlot *) pem_NewSlot(fwInstance, &pError);
+ if (pError != CKR_OK)
+ return pError;
+ }
+ return CKR_OK;
+}
+
+CK_BBOOL
+pem_mdInstance_ModuleHandlesSessionObjects
+(
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return CK_TRUE;
+}
+
+NSS_IMPLEMENT_DATA const NSSCKMDInstance
+pem_mdInstance = {
+ (void *) NULL, /* etc */
+ pem_Initialize, /* Initialize */
+ pem_Finalize, /* Finalize */
+ pem_mdInstance_GetNSlots,
+ pem_mdInstance_GetCryptokiVersion,
+ pem_mdInstance_GetManufacturerID,
+ pem_mdInstance_GetLibraryDescription,
+ pem_mdInstance_GetLibraryVersion,
+ pem_mdInstance_ModuleHandlesSessionObjects,
+ pem_mdInstance_GetSlots,
+ NULL, /* WaitForSlotEvent */
+ (void *) NULL /* null terminator */
+};
diff --git a/pobject.c b/pobject.c
new file mode 100644
index 0000000..2fcc9c8
--- /dev/null
+++ b/pobject.c
@@ -0,0 +1,1175 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+#include "secasn1.h"
+#include "certt.h"
+#include "pk11pub.h"
+
+/*
+ * pobject.c
+ *
+ * This file implements the NSSCKMDObject object for the
+ * "PEM objects" cryptoki module.
+ */
+
+NSS_EXTERN_DATA pemInternalObject **gobj;
+NSS_EXTERN_DATA int pem_nobjs;
+NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS];
+
+#define PEM_ITEM_CHUNK 512
+#define PUT_Object(obj,err) \
+ { \
+ if (count >= size) { \
+ gobj = gobj ? \
+ nss_ZREALLOCARRAY(gobj, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) : \
+ nss_ZNEWARRAY(NULL, pemInternalObject *, \
+ (size+PEM_ITEM_CHUNK) ) ; \
+ if ((pemInternalObject **)NULL == gobj) { \
+ err = CKR_HOST_MEMORY; \
+ goto loser; \
+ } \
+ size += PEM_ITEM_CHUNK; \
+ } \
+ (gobj)[ count ] = (obj); \
+ count++; \
+ }
+
+const CK_ATTRIBUTE_TYPE certAttrs[] = {
+ CKA_CLASS,
+ CKA_TOKEN,
+ CKA_PRIVATE,
+ CKA_MODIFIABLE,
+ CKA_LABEL,
+ CKA_CERTIFICATE_TYPE,
+ CKA_SUBJECT,
+ CKA_ISSUER,
+ CKA_SERIAL_NUMBER,
+ CKA_VALUE
+};
+const PRUint32 certAttrsCount = NSS_PEM_ARRAY_SIZE(certAttrs);
+
+/* private keys, for now only support RSA */
+const CK_ATTRIBUTE_TYPE privKeyAttrs[] = {
+ CKA_CLASS,
+ CKA_TOKEN,
+ CKA_PRIVATE,
+ CKA_MODIFIABLE,
+ CKA_LABEL,
+ CKA_KEY_TYPE,
+ CKA_DERIVE,
+ CKA_LOCAL,
+ CKA_SUBJECT,
+ CKA_SENSITIVE,
+ CKA_DECRYPT,
+ CKA_SIGN,
+ CKA_SIGN_RECOVER,
+ CKA_UNWRAP,
+ CKA_EXTRACTABLE,
+ CKA_ALWAYS_SENSITIVE,
+ CKA_NEVER_EXTRACTABLE,
+ CKA_MODULUS,
+ CKA_PUBLIC_EXPONENT,
+};
+const PRUint32 privKeyAttrsCount = NSS_PEM_ARRAY_SIZE(privKeyAttrs);
+
+/* public keys, for now only support RSA */
+const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = {
+ CKA_CLASS,
+ CKA_TOKEN,
+ CKA_PRIVATE,
+ CKA_MODIFIABLE,
+ CKA_LABEL,
+ CKA_KEY_TYPE,
+ CKA_DERIVE,
+ CKA_LOCAL,
+ CKA_SUBJECT,
+ CKA_ENCRYPT,
+ CKA_VERIFY,
+ CKA_VERIFY_RECOVER,
+ CKA_WRAP,
+ CKA_MODULUS,
+ CKA_PUBLIC_EXPONENT,
+};
+const PRUint32 pubKeyAttrsCount = NSS_PEM_ARRAY_SIZE(pubKeyAttrs);
+
+/* Trust */
+const CK_ATTRIBUTE_TYPE trustAttrs[] = {
+ CKA_CLASS,
+ CKA_TOKEN,
+ CKA_LABEL,
+ CKA_CERT_SHA1_HASH,
+ CKA_CERT_MD5_HASH,
+ CKA_ISSUER,
+ CKA_SUBJECT,
+ CKA_TRUST_SERVER_AUTH,
+ CKA_TRUST_CLIENT_AUTH,
+ CKA_TRUST_EMAIL_PROTECTION,
+ CKA_TRUST_CODE_SIGNING
+};
+const PRUint32 trustAttrsCount = NSS_PEM_ARRAY_SIZE(trustAttrs);
+
+static const CK_BBOOL ck_true = CK_TRUE;
+static const CK_BBOOL ck_false = CK_FALSE;
+static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509;
+static const CK_KEY_TYPE ckk_rsa = CKK_RSA;
+static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
+static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
+static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
+static const CK_OBJECT_CLASS cko_trust = CKO_NETSCAPE_TRUST;
+static const CK_TRUST ckt_netscape_trusted = CKT_NETSCAPE_TRUSTED_DELEGATOR;
+static const NSSItem pem_trueItem = {
+ (void *) &ck_true, (PRUint32) sizeof(CK_BBOOL)
+};
+static const NSSItem pem_falseItem = {
+ (void *) &ck_false, (PRUint32) sizeof(CK_BBOOL)
+};
+static const NSSItem pem_x509Item = {
+ (void *) &ckc_x509, (PRUint32) sizeof(CKC_X_509)
+};
+static const NSSItem pem_rsaItem = {
+ (void *) &ckk_rsa, (PRUint32) sizeof(CK_KEY_TYPE)
+};
+static const NSSItem pem_certClassItem = {
+ (void *) &cko_certificate, (PRUint32) sizeof(CK_OBJECT_CLASS)
+};
+static const NSSItem pem_privKeyClassItem = {
+ (void *) &cko_private_key, (PRUint32) sizeof(CK_OBJECT_CLASS)
+};
+static const NSSItem pem_pubKeyClassItem = {
+ (void *) &cko_public_key, (PRUint32) sizeof(CK_OBJECT_CLASS)
+};
+static const NSSItem pem_trustClassItem = {
+ (void *) &cko_trust, (PRUint32) sizeof(CK_OBJECT_CLASS)
+};
+static const NSSItem pem_emptyItem = {
+ (void *) &ck_true, 0
+};
+static const NSSItem pem_trusted = {
+ (void *) &ckt_netscape_trusted, (PRUint32) sizeof(CK_TRUST)
+};
+
+/*
+ * Template for skipping a subitem.
+ *
+ * Note that it only makes sense to use this for decoding (when you want
+ * to decode something where you are only interested in one or two of
+ * the fields); you cannot encode a SKIP!
+ */
+const SEC_ASN1Template SEC_SkipTemplate[] = {
+ {SEC_ASN1_SKIP}
+};
+
+/*
+ * Find the subjectName in a DER encoded certificate
+ */
+const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
+ {SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECItem)} ,
+ {SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0, SEC_SkipTemplate} , /* version */
+ {SEC_ASN1_SKIP}, /* serial number */
+ {SEC_ASN1_SKIP}, /* signature algorithm */
+ {SEC_ASN1_SKIP}, /* issuer */
+ {SEC_ASN1_SKIP}, /* validity */
+ {SEC_ASN1_ANY, 0, NULL}, /* subject */
+ {SEC_ASN1_SKIP_REST},
+ {0}
+};
+
+void
+pem_FetchLabel
+(
+ pemInternalObject * io
+)
+{
+ pemCertObject *co = &io->u.cert;
+
+ co->label.data = io->nickname;
+ co->label.size = strlen(io->nickname);
+}
+
+const NSSItem
+*pem_FetchCertAttribute
+(
+ pemInternalObject * io,
+ CK_ATTRIBUTE_TYPE type
+)
+{
+ switch (type) {
+ case CKA_CLASS:
+ plog(" fetch cert CKA_CLASS\n");
+ return &pem_certClassItem;
+ case CKA_TOKEN:
+ plog(" fetch cert CKA_TOKEN\n");
+ return &pem_trueItem;
+ case CKA_PRIVATE:
+ return &pem_falseItem;
+ case CKA_CERTIFICATE_TYPE:
+ plog(" fetch cert CKA_CERTIFICATE_TYPE\n");
+ return &pem_x509Item;
+ case CKA_LABEL:
+ if (0 == io->u.cert.label.size) {
+ pem_FetchLabel(io);
+ }
+ plog(" fetch cert CKA_LABEL %s\n", io->u.cert.label.data);
+ return &io->u.cert.label;
+ case CKA_SUBJECT:
+ plog(" fetch cert CKA_SUBJECT size %d\n", io->u.cert.subject.size);
+ return &io->u.cert.subject;
+ case CKA_ISSUER:
+ plog(" fetch cert CKA_ISSUER size %d\n", io->u.cert.issuer.size);
+ return &io->u.cert.issuer;
+ case CKA_SERIAL_NUMBER:
+ plog(" fetch cert CKA_SERIAL_NUMBER size %d value %08x\n", io->u.cert.serial.size, io->u.cert.serial.data);
+ return &io->u.cert.serial;
+ case CKA_VALUE:
+ if (0 == io->u.cert.derCert.size) {
+ io->u.cert.derCert.data = io->derCert->data;
+ io->u.cert.derCert.size = io->derCert->len;
+ }
+ plog(" fetch cert CKA_VALUE\n");
+ return &io->u.cert.derCert;
+ case CKA_ID:
+ plog(" fetch cert CKA_ID val=%s size=%d\n", (char *) io->id.data,
+ io->id.size);
+ return &io->id;
+ case CKA_TRUSTED:
+ plog(" fetch cert CKA_TRUSTED: returning NULL\n");
+ return NULL;
+ default:
+ plog(" fetching cert unknown type %d\n", type);
+ break;
+ }
+ return NULL;
+}
+
+const NSSItem *
+pem_FetchPrivKeyAttribute
+(
+ pemInternalObject * io,
+ CK_ATTRIBUTE_TYPE type
+)
+{
+ PRBool isCertType = (pemCert == io->type);
+ pemKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
+
+ switch (type) {
+ case CKA_CLASS:
+ return &pem_privKeyClassItem;
+ case CKA_TOKEN:
+ case CKA_LOCAL:
+ case CKA_SIGN:
+ case CKA_DECRYPT:
+ case CKA_SIGN_RECOVER:
+ return &pem_trueItem;
+ case CKA_SENSITIVE:
+ case CKA_PRIVATE: /* should move in the future */
+ case CKA_MODIFIABLE:
+ case CKA_DERIVE:
+ case CKA_UNWRAP:
+ case CKA_EXTRACTABLE: /* will probably move in the future */
+ case CKA_ALWAYS_SENSITIVE:
+ case CKA_NEVER_EXTRACTABLE:
+ return &pem_falseItem;
+ case CKA_KEY_TYPE:
+ return &pem_rsaItem;
+ case CKA_LABEL:
+ if (!isCertType) {
+ return &pem_emptyItem;
+ }
+ if (0 == io->u.cert.label.size) {
+ pem_FetchLabel(io);
+ }
+ plog(" fetch key CKA_LABEL %s\n", io->u.cert.label.data);
+ return &io->u.cert.label;
+ case CKA_SUBJECT:
+ if (!isCertType) {
+ return &pem_emptyItem;
+ }
+ plog(" fetch key CKA_SUBJECT %s\n", io->u.cert.label.data);
+ return &io->u.cert.subject;
+ case CKA_MODULUS:
+ if (0 == kp->modulus.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_MODULUS\n");
+ return &kp->modulus;
+ case CKA_PUBLIC_EXPONENT:
+ if (0 == kp->modulus.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_PUBLIC_EXPONENT\n");
+ return &kp->exponent;
+ case CKA_PRIVATE_EXPONENT:
+ if (0 == kp->privateExponent.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_PRIVATE_EXPONENT\n");
+ return &kp->privateExponent;
+ case CKA_PRIME_1:
+ if (0 == kp->prime1.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_PRIME_1\n");
+ return &kp->prime1;
+ case CKA_PRIME_2:
+ if (0 == kp->prime2.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_PRIME_2\n");
+ return &kp->prime2;
+ case CKA_EXPONENT_1:
+ if (0 == kp->exponent1.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_EXPONENT_1\n");
+ return &kp->exponent1;
+ case CKA_EXPONENT_2:
+ if (0 == kp->exponent2.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_EXPONENT_2\n");
+ return &kp->exponent2;
+ case CKA_COEFFICIENT:
+ if (0 == kp->coefficient.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ plog(" fetch key CKA_COEFFICIENT_2\n");
+ return &kp->coefficient;
+ case CKA_ID:
+ plog(" fetch key CKA_ID val=%s size=%d\n", (char *) io->id.data,
+ io->id.size);
+ return &io->id;
+ default:
+ return NULL;
+ }
+}
+
+const NSSItem *
+pem_FetchPubKeyAttribute
+(
+ pemInternalObject * io,
+ CK_ATTRIBUTE_TYPE type
+)
+{
+ PRBool isCertType = (pemCert == io->type);
+ pemKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
+
+ switch (type) {
+ case CKA_CLASS:
+ return &pem_pubKeyClassItem;
+ case CKA_TOKEN:
+ case CKA_LOCAL:
+ case CKA_ENCRYPT:
+ case CKA_VERIFY:
+ case CKA_VERIFY_RECOVER:
+ return &pem_trueItem;
+ case CKA_PRIVATE:
+ case CKA_MODIFIABLE:
+ case CKA_DERIVE:
+ case CKA_WRAP:
+ return &pem_falseItem;
+ case CKA_KEY_TYPE:
+ return &pem_rsaItem;
+ case CKA_LABEL:
+ if (!isCertType) {
+ return &pem_emptyItem;
+ }
+ if (0 == io->u.cert.label.size) {
+ pem_FetchLabel(io);
+ }
+ return &io->u.cert.label;
+ case CKA_SUBJECT:
+ if (!isCertType) {
+ return &pem_emptyItem;
+ }
+ return &io->u.cert.subject;
+ case CKA_MODULUS:
+ if (0 == kp->modulus.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ return &kp->modulus;
+ case CKA_PUBLIC_EXPONENT:
+ if (0 == kp->modulus.size) {
+ pem_PopulateModulusExponent(io);
+ }
+ return &kp->exponent;
+ case CKA_ID:
+ return &io->id;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+const NSSItem *
+pem_FetchTrustAttribute
+(
+ pemInternalObject * io,
+ CK_ATTRIBUTE_TYPE type
+)
+{
+ static NSSItem hash;
+ SECStatus rv;
+
+ switch (type) {
+ case CKA_CLASS:
+ return &pem_trustClassItem;
+ case CKA_TOKEN:
+ return &pem_trueItem;
+ case CKA_PRIVATE:
+ return &pem_falseItem;
+ case CKA_CERTIFICATE_TYPE:
+ return &pem_x509Item;
+ case CKA_LABEL:
+ if (0 == io->u.cert.label.size) {
+ pem_FetchLabel(io);
+ }
+ plog(" fetch trust CKA_LABEL %s\n", io->u.cert.label.data);
+ return &io->u.cert.label;
+ case CKA_SUBJECT:
+ plog(" fetch trust CKA_SUBJECT\n");
+ return NULL;
+ case CKA_ISSUER:
+ plog(" fetch trust CKA_ISSUER\n");
+ return &io->u.cert.issuer;
+ case CKA_SERIAL_NUMBER:
+ plog(" fetch trust CKA_SERIAL_NUMBER size %d value %08x\n", io->u.cert.serial.size, io->u.cert.serial.data);
+ return &io->u.cert.serial;
+ case CKA_VALUE:
+ return &pem_trueItem;
+ case CKA_ID:
+ plog(" fetch trust CKA_ID val=%s size=%d\n", (char *) io->id.data,
+ io->id.size);
+ return &io->id;
+ case CKA_TRUSTED:
+ return &pem_trusted;
+ case CKA_TRUST_SERVER_AUTH:
+ return &pem_trusted;
+ case CKA_TRUST_CLIENT_AUTH:
+ return &pem_trusted;
+ case CKA_TRUST_CODE_SIGNING:
+ return &pem_trusted;
+ case CKA_TRUST_EMAIL_PROTECTION:
+ return &pem_trusted;
+ case CKA_TRUST_IPSEC_END_SYSTEM:
+ return &pem_trusted;
+ case CKA_TRUST_IPSEC_TUNNEL:
+ return &pem_trusted;
+ case CKA_TRUST_IPSEC_USER:
+ return &pem_trusted;
+ case CKA_TRUST_TIME_STAMPING:
+ return &pem_trusted;
+ case CKA_TRUST_STEP_UP_APPROVED:
+ return &pem_falseItem;
+ case CKA_CERT_SHA1_HASH:
+ hash.size = 0;
+ hash.data = NULL;
+ nsslibc_memset(io->u.cert.sha1_hash, 0, SHA1_LENGTH);
+ rv = SHA1_HashBuf(io->u.cert.sha1_hash, io->derCert->data,
+ io->derCert->len);
+ if (rv == SECSuccess) {
+ hash.data = io->u.cert.sha1_hash;
+ hash.size = sizeof(io->u.cert.sha1_hash);
+ }
+ return &hash;
+ case CKA_CERT_MD5_HASH:
+ hash.size = 0;
+ hash.data = NULL;
+ nsslibc_memset(io->u.cert.sha1_hash, 0, MD5_LENGTH);
+ rv = MD5_HashBuf(io->u.cert.sha1_hash, io->derCert->data,
+ io->derCert->len);
+ if (rv == SECSuccess) {
+ hash.data = io->u.cert.sha1_hash;
+ hash.size = sizeof(io->u.cert.sha1_hash);
+ }
+ return &hash;
+ default:
+ return &pem_trusted;
+ break;
+ }
+ return NULL;
+}
+
+const NSSItem *
+pem_FetchAttribute
+(
+ pemInternalObject * io,
+ CK_ATTRIBUTE_TYPE type
+)
+{
+ CK_ULONG i;
+
+ if (io->type == pemRaw) {
+ for (i = 0; i < io->u.raw.n; i++) {
+ if (type == io->u.raw.types[i]) {
+ return &io->u.raw.items[i];
+ }
+ }
+ return NULL;
+ }
+ /* deal with the common attributes */
+ switch (io->objClass) {
+ case CKO_CERTIFICATE:
+ return pem_FetchCertAttribute(io, type);
+ case CKO_PRIVATE_KEY:
+ return pem_FetchPrivKeyAttribute(io, type);
+ case CKO_NETSCAPE_TRUST:
+ return pem_FetchTrustAttribute(io, type);
+ case CKO_PUBLIC_KEY:
+ return pem_FetchPubKeyAttribute(io, type);
+ }
+ return NULL;
+}
+
+void
+pem_DestroyInternalObject
+(
+ pemInternalObject * io
+)
+{
+ switch (io->type) {
+ case pemRaw:
+ return;
+ case pemCert:
+ nss_ZFreeIf(io->u.cert.labelData);
+ nss_ZFreeIf(io->u.cert.key.privateKey);
+ nss_ZFreeIf(io->u.cert.key.pubKey);
+ nss_ZFreeIf(io->idData);
+ nss_ZFreeIf(io->nickname);
+ nss_ZFreeIf(io->derCert);
+ if (io->u.cert.subject.size > 0) {
+ PR_Free(io->u.cert.subject.data);
+ }
+ if (io->u.cert.issuer.size > 0) {
+ PR_Free(io->u.cert.issuer.data);
+ }
+ if (io->u.cert.serial.size > 0) {
+ PR_Free(io->u.cert.serial.data);
+ }
+ break;
+ case pemBareKey:
+ nss_ZFreeIf(io->u.key.key.privateKey);
+ nss_ZFreeIf(io->u.key.key.pubKey);
+ nss_ZFreeIf(io->idData);
+ nss_ZFreeIf(io->nickname);
+ nss_ZFreeIf(io->derCert);
+
+ /* strdup'd in ReadDERFromFile */
+ if (io->u.key.ivstring)
+ free(io->u.key.ivstring);
+ break;
+ case pemTrust:
+ nss_ZFreeIf(io->idData);
+ nss_ZFreeIf(io->nickname);
+ nss_ZFreeIf(io->derCert);
+ }
+ nss_ZFreeIf(io);
+ return;
+}
+
+/*
+ * Finalize - unneeded
+ * Destroy - CKR_SESSION_READ_ONLY
+ * IsTokenObject - CK_TRUE
+ * GetAttributeCount
+ * GetAttributeTypes
+ * GetAttributeSize
+ * GetAttribute
+ * SetAttribute - unneeded
+ * GetObjectSize
+ */
+
+static CK_RV
+pem_mdObject_Destroy
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+
+ pem_DestroyInternalObject(io);
+ return CKR_OK;
+}
+
+static CK_BBOOL
+pem_mdObject_IsTokenObject
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return CK_TRUE;
+}
+
+static CK_ULONG
+pem_mdObject_GetAttributeCount
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+
+ if (pemRaw == io->type) {
+ return io->u.raw.n;
+ }
+ switch (io->objClass) {
+ case CKO_CERTIFICATE:
+ return certAttrsCount;
+ case CKO_PUBLIC_KEY:
+ return pubKeyAttrsCount;
+ case CKO_PRIVATE_KEY:
+ return privKeyAttrsCount;
+ case CKO_NETSCAPE_TRUST:
+ return trustAttrsCount;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static CK_RV
+pem_mdObject_GetAttributeTypes
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_ATTRIBUTE_TYPE_PTR typeArray,
+ CK_ULONG ulCount
+)
+{
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+ CK_ULONG i;
+ CK_RV error = CKR_OK;
+ const CK_ATTRIBUTE_TYPE *attrs = NULL;
+ CK_ULONG size =
+ pem_mdObject_GetAttributeCount(mdObject, fwObject, mdSession,
+ fwSession, mdToken, fwToken, mdInstance,
+ fwInstance, &error);
+
+ if (size != ulCount) {
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ if (io->type == pemRaw) {
+ attrs = io->u.raw.types;
+ } else
+ switch (io->objClass) {
+ case CKO_CERTIFICATE:
+ attrs = certAttrs;
+ break;
+ case CKO_PUBLIC_KEY:
+ attrs = pubKeyAttrs;
+ break;
+ case CKO_PRIVATE_KEY:
+ attrs = privKeyAttrs;
+ break;
+ default:
+ return CKR_OK;
+ }
+
+ for (i = 0; i < size; i++) {
+ typeArray[i] = attrs[i];
+ }
+
+ return CKR_OK;
+}
+
+static CK_ULONG
+pem_mdObject_GetAttributeSize
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_ATTRIBUTE_TYPE attribute,
+ CK_RV * pError
+)
+{
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+
+ const NSSItem *b;
+
+ b = pem_FetchAttribute(io, attribute);
+
+ if ((const NSSItem *) NULL == b) {
+ *pError = CKR_ATTRIBUTE_TYPE_INVALID;
+ return 0;
+ }
+ return b->size;
+}
+
+static NSSCKFWItem
+pem_mdObject_GetAttribute
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_ATTRIBUTE_TYPE attribute,
+ CK_RV * pError
+)
+{
+ NSSCKFWItem mdItem;
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+
+ mdItem.needsFreeing = PR_FALSE;
+ mdItem.item = (NSSItem *) pem_FetchAttribute(io, attribute);
+
+ if ((NSSItem *) NULL == mdItem.item) {
+ *pError = CKR_ATTRIBUTE_TYPE_INVALID;
+ }
+
+ return mdItem;
+}
+
+/*
+ * get an attribute from a template. Value is returned in NSS item.
+ * data for the item is owned by the template.
+ */
+CK_RV
+pem_GetAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE * template,
+ CK_ULONG templateSize,
+ NSSItem * item
+)
+{
+ CK_ULONG i;
+
+ for (i = 0; i < templateSize; i++) {
+ if (template[i].type == type) {
+ item->data = template[i].pValue;
+ item->size = template[i].ulValueLen;
+ return CKR_OK;
+ }
+ }
+ return CKR_TEMPLATE_INCOMPLETE;
+}
+
+/*
+ * get an attribute which is type CK_ULONG.
+ */
+CK_ULONG
+pem_GetULongAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE * template,
+ CK_ULONG templateSize,
+ CK_RV * pError
+)
+{
+ NSSItem item;
+
+ *pError = pem_GetAttribute(type, template, templateSize, &item);
+ if (CKR_OK != *pError) {
+ return (CK_ULONG) 0;
+ }
+ if (item.size != sizeof(CK_ULONG)) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (CK_ULONG) 0;
+ }
+ return *(CK_ULONG *) item.data;
+}
+
+/*
+ * get an attribute which is type CK_BBOOL.
+ */
+CK_BBOOL
+pem_GetBoolAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE * template,
+ CK_ULONG templateSize,
+ CK_RV * pError
+)
+{
+ NSSItem item;
+
+ *pError = pem_GetAttribute(type, template, templateSize, &item);
+ if (CKR_OK != *pError) {
+ return (CK_BBOOL) 0;
+ }
+ if (item.size != sizeof(CK_BBOOL)) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (CK_BBOOL) 0;
+ }
+ return *(CK_BBOOL *) item.data;
+}
+
+/*
+ * Get a string attribute. Caller needs to free this.
+ */
+char *
+pem_GetStringAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE * template,
+ CK_ULONG templateSize,
+ CK_RV * pError
+)
+{
+ NSSItem item;
+ char *str;
+
+ /* get the attribute */
+ *pError = pem_GetAttribute(type, template, templateSize, &item);
+ if (CKR_OK != *pError) {
+ return (char *) NULL;
+ }
+ /* make sure it is null terminated */
+ str = nss_ZNEWARRAY(NULL, char, item.size + 1);
+ if ((char *) NULL == str) {
+ *pError = CKR_HOST_MEMORY;
+ return (char *) NULL;
+ }
+
+ nsslibc_memcpy(str, item.data, item.size);
+ str[item.size] = 0;
+
+ return str;
+}
+
+static CK_ULONG
+pem_mdObject_GetObjectSize
+(
+ NSSCKMDObject * mdObject,
+ NSSCKFWObject * fwObject,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ pemInternalObject *io = (pemInternalObject *) mdObject->etc;
+ CK_ULONG rv = 1;
+
+ /* size is irrelevant to this token */
+ return rv;
+}
+
+static const NSSCKMDObject
+pem_prototype_mdObject = {
+ (void *) NULL, /* etc */
+ NULL, /* Finalize */
+ pem_mdObject_Destroy,
+ pem_mdObject_IsTokenObject,
+ pem_mdObject_GetAttributeCount,
+ pem_mdObject_GetAttributeTypes,
+ pem_mdObject_GetAttributeSize,
+ pem_mdObject_GetAttribute,
+ NULL, /* FreeAttribute */
+ NULL, /* SetAttribute */
+ pem_mdObject_GetObjectSize,
+ (void *) NULL /* null terminator */
+};
+
+NSS_IMPLEMENT NSSCKMDObject *
+pem_CreateMDObject
+(
+ NSSArena * arena,
+ pemInternalObject * io,
+ CK_RV * pError
+)
+{
+ if ((void *) NULL == io->mdObject.etc) {
+ (void) nsslibc_memcpy(&io->mdObject, &pem_prototype_mdObject,
+ sizeof(pem_prototype_mdObject));
+ io->mdObject.etc = (void *) io;
+ }
+
+ return &io->mdObject;
+}
+
+/*
+ * Each object has an identifier. For a certificate and key pair this id
+ * needs to be the same so we use the right combination. If the target object
+ * is a key we first look to see if its certificate was already added and if
+ * so, use that id. The same thing is done when a key is added.
+ */
+NSS_EXTERN NSSCKMDObject *
+pem_CreateObject
+(
+ NSSCKFWInstance * fwInstance,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV * pError
+)
+{
+ CK_OBJECT_CLASS objClass;
+ pemInternalObject *io = NULL;
+ CK_BBOOL isToken;
+ NSSCKFWSlot *fwSlot;
+ CK_SLOT_ID slotID;
+ CK_BBOOL cacert;
+ char *filename;
+ SECItem **derlist = NULL;
+ int nobjs, i;
+ int objid, count, size;
+ pemToken *token;
+ int cipher;
+ char *ivstring = NULL;
+
+ count = pem_nobjs;
+ if (count > 0)
+ size = ((count / PEM_ITEM_CHUNK) + 1) * PEM_ITEM_CHUNK;
+ else
+ size = 0;
+
+ /*
+ * only create token objects
+ */
+ isToken = pem_GetBoolAttribute(CKA_TOKEN, pTemplate,
+ ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (NSSCKMDObject *) NULL;
+ }
+ if (!isToken) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (NSSCKMDObject *) NULL;
+ }
+
+ /* What slot are we adding the object to? */
+ fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+ if ((NSSCKFWSlot *) NULL == fwSlot) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ *pError = CKR_GENERAL_ERROR;
+ return (NSSCKMDObject *) NULL;
+
+ }
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ token = (pemToken *) mdToken->etc;
+
+ /*
+ * only create keys and certs.
+ */
+ objClass = pem_GetULongAttribute(CKA_CLASS, pTemplate,
+ ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (NSSCKMDObject *) NULL;
+ }
+
+ cacert = pem_GetBoolAttribute(CKA_TRUST, pTemplate,
+ ulAttributeCount, pError);
+
+ filename = pem_GetStringAttribute(CKA_LABEL, pTemplate,
+ ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (NSSCKMDObject *) NULL;
+ }
+
+#ifdef notdef
+ if (objClass == CKO_PUBLIC_KEY) {
+ return CKR_OK; /* fake public key creation, happens as a side effect of
+ * private key creation */
+ }
+#endif
+ if (objClass == CKO_CERTIFICATE) {
+ int i;
+
+ nobjs = ReadDERFromFile(&derlist, filename, PR_TRUE, &cipher, &ivstring, PR_TRUE /* certs only */);
+ if (nobjs < 1)
+ return (NSSCKMDObject *) NULL;
+
+ objid = -1;
+ /* Brute force: find the id of the key, if any, in this slot */
+ for (i = 0; i < pem_nobjs; i++) {
+ if ((slotID == gobj[i]->slotID)
+ && (gobj[i]->type == pemBareKey)) {
+ objid = atoi(gobj[i]->id.data);
+ }
+ }
+
+ if (objid == -1) {
+ /* We're just adding a cert, we'll assume the key is next */
+ objid = pem_nobjs + 1;
+ }
+
+ if (cacert) {
+ /* Add the certificate. There may be more than one */
+ int c;
+ for (c = 0; c < nobjs; c++) {
+ char nickname[1024];
+ objid = pem_nobjs + 1;
+
+ snprintf(nickname, 1024, "%s - %d", filename, c);
+
+ io = (pemInternalObject *) CreateObject(CKO_CERTIFICATE,
+ pemCert, derlist[c],
+ NULL, nickname, 0,
+ slotID);
+ if (io == NULL)
+ goto loser;
+ PUT_Object(io, *pError);
+ pem_nobjs++;
+
+ /* Add the trust object */
+ io = CreateObject(CKO_NETSCAPE_TRUST, pemTrust, derlist[c],
+ NULL, nickname, 0, slotID);
+ if (io == NULL)
+ goto loser;
+
+ PUT_Object(io, *pError);
+ pem_nobjs++;
+ }
+ } else {
+ io = (pemInternalObject *) CreateObject(CKO_CERTIFICATE,
+ pemCert, derlist[0],
+ NULL, filename, objid,
+ slotID);
+ if (io == NULL)
+ goto loser;
+ PUT_Object(io, *pError);
+ pem_nobjs++;
+ }
+ } else if (objClass == CKO_PRIVATE_KEY) {
+ /* Brute force: find the id of the certificate, if any, in this slot */
+ int i;
+ SECItem certDER;
+ CK_SESSION_HANDLE hSession;
+
+ nobjs = ReadDERFromFile(&derlist, filename, PR_TRUE, &cipher, &ivstring, PR_FALSE /* keys only */);
+ if (nobjs < 1)
+ return (NSSCKMDObject *) NULL;
+
+ certDER.len = 0; /* in case there is no equivalent cert */
+
+ objid = -1;
+ for (i = 0; i < pem_nobjs; i++) {
+ if ((slotID == gobj[i]->slotID) && (gobj[i]->type == pemCert)) {
+ objid = atoi(gobj[i]->id.data);
+ certDER.data =
+ (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len);
+ certDER.len = gobj[i]->derCert->len;
+ nsslibc_memcpy(certDER.data, gobj[i]->derCert->data,
+ gobj[i]->derCert->len);
+ }
+ }
+
+ /* We're just adding a key, we'll assume the cert is next */
+ if (objid == -1)
+ objid = pem_nobjs + 1;
+
+ io = (pemInternalObject *) CreateObject(CKO_PRIVATE_KEY,
+ pemBareKey, &certDER,
+ derlist[0], filename,
+ objid, slotID);
+ if (io == NULL)
+ goto loser;
+ io->u.key.ivstring = ivstring;
+ io->u.key.cipher = cipher;
+ PUT_Object(io, *pError);
+ pem_nobjs++;
+ nss_ZFreeIf(certDER.data);
+
+ /* If the key was encrypted then free the session to make it appear that
+ * the token was removed so we can force a login.
+ */
+ if (cipher) {
+ PRIntervalTime onesec = PR_SecondsToInterval(1);
+ token_needsLogin[slotID - 1] = PR_TRUE;
+
+ /* We have to sleep so that NSS will notice that the token was
+ * removed.
+ */
+ PR_Sleep(onesec);
+ hSession =
+ nssCKFWInstance_FindSessionHandle(fwInstance, fwSession);
+ nssCKFWInstance_DestroySessionHandle(fwInstance, hSession);
+ } else {
+ *pError = CKR_KEY_UNEXTRACTABLE;
+ }
+ } else {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+
+ loser:
+
+ for (i = 0; i < nobjs; i++) {
+ free(derlist[i]->data);
+ free(derlist[i]);
+ }
+ nss_ZFreeIf(filename);
+ nss_ZFreeIf(derlist);
+ if ((pemInternalObject *) NULL == io) {
+ return (NSSCKMDObject *) NULL;
+ }
+ return pem_CreateMDObject(NULL, io, pError);
+}
diff --git a/prsa.c b/prsa.c
new file mode 100644
index 0000000..1391dd3
--- /dev/null
+++ b/prsa.c
@@ -0,0 +1,615 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+#include "secdert.h"
+#include "secoid.h"
+#include "nssckmdt.h"
+
+#define SSL3_SHAMD5_HASH_SIZE 36 /* LEN_MD5 (16) + LEN_SHA1 (20) */
+
+/*
+ * prsa.c
+ *
+ * This file implements the NSSCKMDMechnaism and NSSCKMDCryptoOperation objects
+ * for the RSA operation.
+ */
+
+const SEC_ASN1Template pem_RSAPrivateKeyTemplate[] = {
+ {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(pemLOWKEYPrivateKey)} ,
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.version)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.modulus)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.publicExponent)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.privateExponent)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.prime1)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.prime2)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.exponent1)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.exponent2)},
+ {SEC_ASN1_INTEGER, offsetof(pemLOWKEYPrivateKey, u.rsa.coefficient)},
+ {0}
+};
+
+/* Declarations */
+SECStatus pem_RSA_Sign(pemLOWKEYPrivateKey * key, unsigned char *output,
+ unsigned int *outputLen, unsigned int maxOutputLen,
+ unsigned char *input, unsigned int inputLen);
+SECStatus pem_RSA_DecryptBlock(pemLOWKEYPrivateKey * key,
+ unsigned char *output, unsigned int *outputLen,
+ unsigned int maxOutputLen, unsigned char *input,
+ unsigned int inputLen);
+
+void prepare_low_rsa_priv_key_for_asn1(pemLOWKEYPrivateKey * key)
+{
+ key->u.rsa.modulus.type = siUnsignedInteger;
+ key->u.rsa.publicExponent.type = siUnsignedInteger;
+ key->u.rsa.privateExponent.type = siUnsignedInteger;
+ key->u.rsa.prime1.type = siUnsignedInteger;
+ key->u.rsa.prime2.type = siUnsignedInteger;
+ key->u.rsa.exponent1.type = siUnsignedInteger;
+ key->u.rsa.exponent2.type = siUnsignedInteger;
+ key->u.rsa.coefficient.type = siUnsignedInteger;
+}
+
+unsigned int
+pem_PrivateModulusLen(pemLOWKEYPrivateKey * privk)
+{
+
+ unsigned char b0;
+
+ switch (privk->keyType) {
+ case pemLOWKEYRSAKey:
+ b0 = privk->u.rsa.modulus.data[0];
+ return b0 ? privk->u.rsa.modulus.len : privk->u.rsa.modulus.len -
+ 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+struct SFTKHashSignInfoStr {
+ SECOidTag hashOid;
+ pemLOWKEYPrivateKey *key;
+};
+typedef struct SFTKHashSignInfoStr SFTKHashSignInfo;
+
+void
+pem_DestroyPrivateKey(pemLOWKEYPrivateKey * privk)
+{
+ if (privk && privk->arena) {
+ PORT_FreeArena(privk->arena, PR_TRUE);
+ }
+}
+
+void
+pem_PopulateModulusExponent(pemInternalObject * io)
+{
+ const NSSItem *classItem = pem_FetchAttribute(io, CKA_CLASS);
+ const NSSItem *keyType = pem_FetchAttribute(io, CKA_KEY_TYPE);
+ pemLOWKEYPrivateKey *lpk = NULL;
+ PLArenaPool *arena;
+ SECStatus rv;
+
+ arena = PORT_NewArena(2048);
+ if (!arena) {
+ return;
+ }
+
+ /* make sure we have the right objects */
+ if (((const NSSItem *) NULL == classItem) ||
+ (sizeof(CK_OBJECT_CLASS) != classItem->size) ||
+ (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *) classItem->data) ||
+ ((const NSSItem *) NULL == keyType) ||
+ (sizeof(CK_KEY_TYPE) != keyType->size) ||
+ (CKK_RSA != *(CK_KEY_TYPE *) keyType->data)) {
+ return;
+ }
+
+ lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL,
+ sizeof(pemLOWKEYPrivateKey));
+ if (lpk == NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return;
+ }
+
+ lpk->arena = arena;
+ lpk->keyType = pemLOWKEYRSAKey;
+ prepare_low_rsa_priv_key_for_asn1(lpk);
+
+ /* decode the private key and any algorithm parameters */
+ rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate,
+ io->u.key.key.privateKey);
+
+ if (rv != SECSuccess) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return;
+ }
+
+ io->u.key.key.modulus.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len);
+ io->u.key.key.modulus.size = lpk->u.rsa.modulus.len;
+ nsslibc_memcpy(io->u.key.key.modulus.data, lpk->u.rsa.modulus.data,
+ lpk->u.rsa.modulus.len);
+
+ io->u.key.key.exponent.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.publicExponent.len);
+ io->u.key.key.exponent.size = lpk->u.rsa.publicExponent.len;
+ nsslibc_memcpy(io->u.key.key.exponent.data,
+ lpk->u.rsa.publicExponent.data,
+ lpk->u.rsa.publicExponent.len);
+
+ io->u.key.key.privateExponent.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.privateExponent.len);
+ io->u.key.key.privateExponent.size = lpk->u.rsa.privateExponent.len;
+ nsslibc_memcpy(io->u.key.key.privateExponent.data,
+ lpk->u.rsa.privateExponent.data,
+ lpk->u.rsa.privateExponent.len);
+
+ io->u.key.key.prime1.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.prime1.len);
+ io->u.key.key.prime1.size = lpk->u.rsa.prime1.len;
+ nsslibc_memcpy(io->u.key.key.prime1.data, lpk->u.rsa.prime1.data,
+ lpk->u.rsa.prime1.len);
+
+ io->u.key.key.prime2.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.prime2.len);
+ io->u.key.key.prime2.size = lpk->u.rsa.prime2.len;
+ nsslibc_memcpy(io->u.key.key.prime2.data, lpk->u.rsa.prime2.data,
+ lpk->u.rsa.prime2.len);
+
+ io->u.key.key.exponent1.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.exponent1.len);
+ io->u.key.key.exponent1.size = lpk->u.rsa.exponent1.len;
+ nsslibc_memcpy(io->u.key.key.exponent1.data, lpk->u.rsa.exponent1.data,
+ lpk->u.rsa.exponent1.len);
+
+ io->u.key.key.exponent2.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.exponent2.len);
+ io->u.key.key.exponent2.size = lpk->u.rsa.exponent2.len;
+ nsslibc_memcpy(io->u.key.key.exponent2.data, lpk->u.rsa.exponent2.data,
+ lpk->u.rsa.exponent2.len);
+
+ io->u.key.key.coefficient.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.coefficient.len);
+ io->u.key.key.coefficient.size = lpk->u.rsa.coefficient.len;
+ nsslibc_memcpy(io->u.key.key.coefficient.data,
+ lpk->u.rsa.coefficient.data,
+ lpk->u.rsa.coefficient.len);
+
+ pem_DestroyPrivateKey(lpk);
+ return;
+}
+
+typedef struct pemInternalCryptoOperationRSAPrivStr
+ pemInternalCryptoOperationRSAPriv;
+struct pemInternalCryptoOperationRSAPrivStr
+{
+ NSSCKMDCryptoOperation mdOperation;
+ NSSCKMDMechanism *mdMechanism;
+ pemInternalObject *iKey;
+ pemLOWKEYPrivateKey *lpk;
+ NSSItem *buffer;
+};
+
+/*
+ * pem_mdCryptoOperationRSAPriv_Create
+ */
+static NSSCKMDCryptoOperation *
+pem_mdCryptoOperationRSAPriv_Create
+(
+ const NSSCKMDCryptoOperation * proto,
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKMDObject * mdKey,
+ CK_RV * pError
+)
+{
+ pemInternalObject *iKey = (pemInternalObject *) mdKey->etc;
+ const NSSItem *classItem = pem_FetchAttribute(iKey, CKA_CLASS);
+ const NSSItem *keyType = pem_FetchAttribute(iKey, CKA_KEY_TYPE);
+ pemInternalCryptoOperationRSAPriv *iOperation;
+ pemLOWKEYPrivateKey *lpk = NULL;
+ PLArenaPool *arena;
+ SECStatus rv;
+
+ arena = PORT_NewArena(2048);
+ if (!arena) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDCryptoOperation *) NULL;
+ }
+
+ /* make sure we have the right objects */
+ if (((const NSSItem *) NULL == classItem) ||
+ (sizeof(CK_OBJECT_CLASS) != classItem->size) ||
+ (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *) classItem->data) ||
+ ((const NSSItem *) NULL == keyType) ||
+ (sizeof(CK_KEY_TYPE) != keyType->size) ||
+ (CKK_RSA != *(CK_KEY_TYPE *) keyType->data)) {
+ *pError = CKR_KEY_TYPE_INCONSISTENT;
+ return (NSSCKMDCryptoOperation *) NULL;
+ }
+
+ lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL,
+ sizeof (pemLOWKEYPrivateKey));
+ if (lpk == NULL) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDCryptoOperation *) NULL;
+ }
+ lpk->arena = arena;
+ lpk->keyType = pemLOWKEYRSAKey;
+ prepare_low_rsa_priv_key_for_asn1(lpk);
+ iKey->u.key.key.modulus.data =
+ (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len);
+ iKey->u.key.key.modulus.size = lpk->u.rsa.modulus.len;
+ nsslibc_memcpy(iKey->u.key.key.modulus.data, lpk->u.rsa.modulus.data,
+ lpk->u.rsa.modulus.len);
+
+ /* decode the private key and any algorithm parameters */
+ rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate,
+ iKey->u.key.key.privateKey);
+
+ if (rv != SECSuccess) {
+ PORT_FreeArena(arena, PR_FALSE);
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDCryptoOperation *) NULL;
+ }
+
+ iOperation = nss_ZNEW(NULL, pemInternalCryptoOperationRSAPriv);
+ if ((pemInternalCryptoOperationRSAPriv *) NULL == iOperation) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDCryptoOperation *) NULL;
+ }
+ iOperation->mdMechanism = mdMechanism;
+ iOperation->iKey = iKey;
+ iOperation->lpk = lpk;
+
+ nsslibc_memcpy(&iOperation->mdOperation,
+ proto, sizeof(NSSCKMDCryptoOperation));
+ iOperation->mdOperation.etc = iOperation;
+
+ return &iOperation->mdOperation;
+}
+
+static CK_RV
+pem_mdCryptoOperationRSAPriv_Destroy
+(
+ NSSCKMDCryptoOperation * mdOperation,
+ NSSCKFWCryptoOperation * fwOperation,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ pemInternalCryptoOperationRSAPriv *iOperation =
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc;
+
+ if (iOperation->buffer) {
+ nssItem_Destroy(iOperation->buffer);
+ }
+ nss_ZFreeIf(iOperation);
+ return CKR_OK;
+}
+
+static CK_ULONG
+pem_mdCryptoOperationRSA_GetFinalLength
+(
+ NSSCKMDCryptoOperation * mdOperation,
+ NSSCKFWCryptoOperation * fwOperation,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ pemInternalCryptoOperationRSAPriv *iOperation =
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc;
+ const NSSItem *modulus =
+ pem_FetchAttribute(iOperation->iKey, CKA_MODULUS);
+
+ return modulus->size;
+}
+
+
+/*
+ * pem_mdCryptoOperationRSADecrypt_GetOperationLength
+ * we won't know the length until we actually decrypt the
+ * input block. Since we go to all the work to decrypt the
+ * the block, we'll save if for when the block is asked for
+ */
+static CK_ULONG
+pem_mdCryptoOperationRSADecrypt_GetOperationLength
+(
+ NSSCKMDCryptoOperation * mdOperation,
+ NSSCKFWCryptoOperation * fwOperation,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ const NSSItem * input,
+ CK_RV * pError
+)
+{
+ pemInternalCryptoOperationRSAPriv *iOperation =
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc;
+ SECStatus rv;
+
+ /* FIXME: Just because Microsoft is broken doesn't mean I have to be.
+ * but this is faster to do for now */
+
+ /* Microsoft's Decrypt operation works in place. Since we don't want
+ * to trash our input buffer, we make a copy of it */
+ iOperation->buffer = nssItem_Duplicate((NSSItem *) input, NULL, NULL);
+ if ((NSSItem *) NULL == iOperation->buffer) {
+ *pError = CKR_HOST_MEMORY;
+ return 0;
+ }
+
+ rv = pem_RSA_DecryptBlock(iOperation->lpk, iOperation->buffer->data,
+ &iOperation->buffer->size,
+ iOperation->buffer->size, input->data,
+ input->size);
+
+ if (rv != SECSuccess) {
+ return 0;
+ }
+
+ return iOperation->buffer->size;
+}
+
+/*
+ * pem_mdCryptoOperationRSADecrypt_UpdateFinal
+ *
+ * NOTE: pem_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to
+ * have been called previously.
+ */
+static CK_RV
+pem_mdCryptoOperationRSADecrypt_UpdateFinal
+(
+ NSSCKMDCryptoOperation * mdOperation,
+ NSSCKFWCryptoOperation * fwOperation,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ const NSSItem * input,
+ NSSItem * output
+)
+{
+ pemInternalCryptoOperationRSAPriv *iOperation =
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc;
+ NSSItem *buffer = iOperation->buffer;
+
+ if ((NSSItem *) NULL == buffer) {
+ return CKR_GENERAL_ERROR;
+ }
+ nsslibc_memcpy(output->data, buffer->data, buffer->size);
+ output->size = buffer->size;
+ return CKR_OK;
+}
+
+/*
+ * pem_mdCryptoOperationRSASign_UpdateFinal
+ *
+ */
+static CK_RV
+pem_mdCryptoOperationRSASign_UpdateFinal
+(
+ NSSCKMDCryptoOperation * mdOperation,
+ NSSCKFWCryptoOperation * fwOperation,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ const NSSItem * input,
+ NSSItem * output
+)
+{
+ pemInternalCryptoOperationRSAPriv *iOperation =
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc;
+ CK_RV error = CKR_OK;
+ SECStatus rv = SECSuccess;
+
+ rv = pem_RSA_Sign(iOperation->lpk, output->data, &output->size,
+ output->size, input->data, input->size);
+
+ if (rv != SECSuccess) {
+ error = CKR_GENERAL_ERROR;
+ }
+
+ return error;
+}
+
+NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
+pem_mdCryptoOperationRSADecrypt_proto = {
+ NULL, /* etc */
+ pem_mdCryptoOperationRSAPriv_Destroy,
+ NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */
+ pem_mdCryptoOperationRSADecrypt_GetOperationLength,
+ NULL, /* Final - not needed for one shot operation */
+ NULL, /* Update - not needed for one shot operation */
+ NULL, /* DigestUpdate - not needed for one shot operation */
+ pem_mdCryptoOperationRSADecrypt_UpdateFinal,
+ NULL, /* UpdateCombo - not needed for one shot operation */
+ NULL, /* DigestKey - not needed for one shot operation */
+ (void *) NULL /* null terminator */
+};
+
+NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
+pem_mdCryptoOperationRSASign_proto = {
+ NULL, /* etc */
+ pem_mdCryptoOperationRSAPriv_Destroy,
+ pem_mdCryptoOperationRSA_GetFinalLength,
+ NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */
+ NULL, /* Final - not needed for one shot operation */
+ NULL, /* Update - not needed for one shot operation */
+ NULL, /* DigestUpdate - not needed for one shot operation */
+ pem_mdCryptoOperationRSASign_UpdateFinal,
+ NULL, /* UpdateCombo - not needed for one shot operation */
+ NULL, /* DigestKey - not needed for one shot operation */
+ (void *) NULL /* null terminator */
+};
+
+/********** NSSCKMDMechansim functions ***********************/
+/*
+ * pem_mdMechanismRSA_Destroy
+ */
+static void
+pem_mdMechanismRSA_Destroy
+(
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKFWMechanism * fwMechanism,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ nss_ZFreeIf(fwMechanism);
+}
+
+/*
+ * pem_mdMechanismRSA_GetMinKeySize
+ */
+static CK_ULONG
+pem_mdMechanismRSA_GetMinKeySize
+(
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKFWMechanism * fwMechanism,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return 384;
+}
+
+/*
+ * pem_mdMechanismRSA_GetMaxKeySize
+ */
+static CK_ULONG
+pem_mdMechanismRSA_GetMaxKeySize
+(
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKFWMechanism * fwMechanism,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return 16384;
+}
+
+/*
+ * pem_mdMechanismRSA_DecryptInit
+ */
+static NSSCKMDCryptoOperation *
+pem_mdMechanismRSA_DecryptInit
+(
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKFWMechanism * fwMechanism,
+ CK_MECHANISM * pMechanism,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSCKMDObject * mdKey,
+ NSSCKFWObject * fwKey,
+ CK_RV * pError
+)
+{
+ return pem_mdCryptoOperationRSAPriv_Create
+ (&pem_mdCryptoOperationRSADecrypt_proto, mdMechanism, mdKey,
+ pError);
+}
+
+/*
+ * pem_mdMechanismRSA_SignInit
+ */
+static NSSCKMDCryptoOperation *
+pem_mdMechanismRSA_SignInit
+(
+ NSSCKMDMechanism * mdMechanism,
+ NSSCKFWMechanism * fwMechanism,
+ CK_MECHANISM * pMechanism,
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSCKMDObject * mdKey,
+ NSSCKFWObject * fwKey,
+ CK_RV * pError
+)
+{
+ return pem_mdCryptoOperationRSAPriv_Create
+ (&pem_mdCryptoOperationRSASign_proto, mdMechanism, mdKey, pError);
+}
+
+NSS_IMPLEMENT_DATA const NSSCKMDMechanism
+pem_mdMechanismRSA = {
+ (void *) NULL, /* etc */
+ pem_mdMechanismRSA_Destroy,
+ pem_mdMechanismRSA_GetMinKeySize,
+ pem_mdMechanismRSA_GetMaxKeySize,
+ NULL, /* GetInHardware - default false */
+ NULL, /* EncryptInit - default errs */
+ pem_mdMechanismRSA_DecryptInit,
+ NULL, /* DigestInit - default errs */
+ pem_mdMechanismRSA_SignInit,
+ NULL, /* VerifyInit - default errs */
+ pem_mdMechanismRSA_SignInit, /* SignRecoverInit */
+ NULL, /* VerifyRecoverInit - default errs */
+ NULL, /* GenerateKey - default errs */
+ NULL, /* GenerateKeyPair - default errs */
+ NULL, /* GetWrapKeyLength - default errs */
+ NULL, /* WrapKey - default errs */
+ NULL, /* UnwrapKey - default errs */
+ NULL, /* DeriveKey - default errs */
+ (void *) NULL /* null terminator */
+};
diff --git a/psession.c b/psession.c
new file mode 100644
index 0000000..472e0b1
--- /dev/null
+++ b/psession.c
@@ -0,0 +1,452 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+#include "secmodt.h"
+#include "pk11pub.h"
+#include "base64.h"
+#include "blapi.h"
+
+/*
+ * psession.c
+ *
+ * This file implements the NSSCKMDSession object for the
+ * "PEM objects" cryptoki module.
+ */
+
+NSS_EXTERN_DATA pemInternalObject **gobj;
+NSS_EXTERN_DATA int pem_nobjs;
+NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS];
+NSS_EXTERN_DATA const SEC_ASN1Template pem_RSAPrivateKeyTemplate[];
+
+void prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey * key);
+void pem_DestroyPrivateKey(NSSLOWKEYPrivateKey * privk);
+
+/*
+ * Convert a hex string into bytes.
+ */
+static unsigned char *convert_iv(char *src, int num)
+{
+ int i;
+ char conv[3];
+ unsigned char *c;
+
+ c = (unsigned char *) malloc((num) + 1);
+ if (c == NULL)
+ return NULL;
+
+ conv[2] = '\0';
+ memset(c, 0, num);
+ for (i = 0; i < num; i++) {
+ conv[0] = src[(i * 2)];
+ conv[1] = src[(i * 2) + 1];
+ c[i] = strtol(conv, NULL, 16);
+ }
+ return c;
+}
+
+/*
+ * The key is a 24-bit hash. The first 16 bits are the MD5 hash of the
+ * password and the IV (salt). This has is then re-hashed with the
+ * password and IV again and the first 8 bytes of that are the remaining
+ * bytes of the 24-bit key.
+ */
+static int
+make_key(const unsigned char *salt, const unsigned char *data, int len,
+ unsigned char *key)
+{
+ int nkey = 0;
+ MD5Context *Md5Ctx = MD5_NewContext();
+ unsigned int digestLen;
+ int count, i;
+ char H[25];
+
+ nkey = 24;
+ count = 0;
+
+ while (nkey > 0) {
+ MD5_Begin(Md5Ctx);
+ if (count)
+ MD5_Update(Md5Ctx, (const unsigned char *) H, digestLen);
+ MD5_Update(Md5Ctx, (const unsigned char *) data, len);
+ MD5_Update(Md5Ctx, (const unsigned char *) salt, 8);
+ MD5_End(Md5Ctx, (unsigned char *) H, &digestLen, sizeof(H));
+
+ i = 0;
+ while (nkey && (i != digestLen)) {
+ *(key++) = H[i];
+ nkey--;
+ i++;
+ }
+ count++;
+ }
+
+ return 24;
+}
+
+static NSSCKMDFindObjects *
+pem_mdSession_FindObjectsInit
+(
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV * pError
+)
+{
+ plog("mdSession_FindObjectsInit\n");
+ return pem_FindObjectsInit(fwSession, pTemplate, ulAttributeCount,
+ pError);
+}
+
+static NSSCKMDObject *
+pem_mdSession_CreateObject
+(
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSArena * arena,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV * pError
+)
+{
+ plog("mdSession_CreateObject\n");
+ return pem_CreateObject(fwInstance, fwSession, mdToken, pTemplate,
+ ulAttributeCount, pError);
+}
+
+NSSCKMDObject *
+pem_mdSession_CopyObject
+(
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSCKFWObject * mdOldObject,
+ NSSCKFWObject * fwOldObject,
+ NSSArena * arena,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV * pError
+)
+{
+ CK_OBJECT_CLASS objClass;
+ pemInternalObject *new;
+ NSSCKMDObject *mdObject = nssCKFWObject_GetMDObject(fwOldObject);
+ pemInternalObject *old = (pemInternalObject *) mdObject->etc;
+ CK_RV error = CKR_OK;
+
+ plog("pem_mdSession_CopyObject: ");
+ /*
+ * now handle the various object types
+ */
+ *pError = CKR_OK;
+ switch (old->type) {
+ case pemCert:
+ plog("pemCert\n");
+ if ((pemInternalObject *) NULL == 0) {
+ new = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == new) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&new->u.cert, 0, sizeof(new->u.cert));
+ new->objClass = objClass;
+ new->type = pemCert;
+ new->derCert = nss_ZNEW(NULL, SECItem);
+ new->derCert->data =
+ (void *) nss_ZAlloc(NULL, old->derCert->len);
+ new->derCert->len = old->derCert->len;
+ nsslibc_memcpy(new->derCert->data, old->derCert->data,
+ old->derCert->len);
+ new->nickname =
+ (char *) nss_ZAlloc(NULL, strlen(old->nickname) + 1);
+ strcpy(new->nickname, old->nickname);
+ new->id.data = (void *) nss_ZAlloc(NULL, old->id.size);
+ (void) nsslibc_memcpy(new->id.data, old->id.data,
+ old->id.size);
+ new->id.size = old->id.size;
+ }
+ break;
+ case pemBareKey:
+ plog("pemBareKey\n");
+ if ((pemInternalObject *) NULL == 0) {
+ new = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == new) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&new->u.key, 0, sizeof(new->u.key));
+ new->objClass = CKO_PRIVATE_KEY;
+ new->type = pemBareKey;
+ new->derCert = nss_ZNEW(NULL, SECItem);
+ new->derCert->data =
+ (void *) nss_ZAlloc(NULL, old->derCert->len);
+ new->derCert->len = old->derCert->len;
+ new->id.data = (void *) nss_ZAlloc(NULL, old->id.size);
+ (void) nsslibc_memcpy(new->id.data, old->id.data,
+ old->id.size);
+ new->id.size = old->id.size;
+ nsslibc_memcpy(new->derCert->data, old->derCert->data,
+ old->derCert->len);
+ new->nickname =
+ (char *) nss_ZAlloc(NULL, strlen(old->nickname) + 1);
+ strcpy(new->nickname, old->nickname);
+ new->u.key.key.privateKey = nss_ZNEW(NULL, SECItem);
+ new->u.key.key.privateKey->data =
+ (void *) nss_ZAlloc(NULL, old->u.key.key.privateKey->len);
+ new->u.key.key.privateKey->len =
+ old->u.key.key.privateKey->len;
+ nsslibc_memcpy(new->u.key.key.privateKey->data,
+ old->u.key.key.privateKey->data,
+ old->u.key.key.privateKey->len);
+ }
+ goto done;
+ break;
+ case pemTrust:
+ plog("pemTrust\n");
+ if ((pemInternalObject *) NULL == 0) {
+ new = nss_ZNEW(NULL, pemInternalObject);
+ if ((pemInternalObject *) NULL == new) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ memset(&new->u.trust, 0, sizeof(new->u.trust));
+ new->objClass = objClass;
+ new->type = pemTrust;
+ new->derCert = nss_ZNEW(NULL, SECItem);
+ new->derCert->data =
+ (void *) nss_ZAlloc(NULL, old->derCert->len);
+ new->derCert->len = old->derCert->len;
+ nsslibc_memcpy(new->derCert->data, old->derCert->data,
+ old->derCert->len);
+ new->nickname =
+ (char *) nss_ZAlloc(NULL, strlen(old->nickname) + 1);
+ strcpy(new->nickname, old->nickname);
+ new->id.data = (void *) nss_ZAlloc(NULL, old->id.size);
+ (void) nsslibc_memcpy(new->id.data, old->id.data,
+ old->id.size);
+ new->id.size = old->id.size;
+ }
+ goto done;
+ default:
+ plog("Unknown: %08x\n", old->type);
+ goto done; /* no other object types we understand in this module */
+ }
+ if (CKR_OK != *pError) {
+ goto loser;
+ }
+
+ done:
+ *pError = CKR_OK;
+ return (NSSCKMDObject *) pem_CreateMDObject(arena, new, &error);
+
+ loser:
+ *pError = CKR_GENERAL_ERROR;
+ return (NSSCKMDObject *) NULL;
+
+}
+
+CK_RV
+pem_mdSession_Login
+(
+ NSSCKMDSession * mdSession,
+ NSSCKFWSession * fwSession,
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_USER_TYPE userType,
+ NSSItem * pin,
+ CK_STATE oldState,
+ CK_STATE newState
+)
+{
+ NSSCKFWSlot *fwSlot;
+ CK_SLOT_ID slotID;
+ pemInternalObject *io;
+ unsigned char *iv;
+ unsigned char mykey[32];
+ unsigned char *output;
+ DESContext *cx = NULL;
+ SECStatus rv;
+ unsigned int len = 0;
+ NSSLOWKEYPrivateKey *lpk = NULL;
+ PLArenaPool *arena;
+ int i;
+
+ fwSlot = NSSCKFWToken_GetFWSlot(fwToken);
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ arena = PORT_NewArena(2048);
+ if (!arena) {
+ goto loser;
+ }
+
+ plog("pem_mdSession_Login '%s'\n", (char *) pin->data);
+
+ token_needsLogin[slotID - 1] = PR_FALSE;
+
+ /* Find the right key object */
+ for (i = 0; i < pem_nobjs; i++) {
+ if ((slotID == gobj[i]->slotID) && (gobj[i]->type == pemBareKey)) {
+ io = gobj[i];
+ break;
+ }
+ }
+
+ /* Convert the IV from hex into an array of bytes */
+ iv = convert_iv(io->u.key.ivstring, 8);
+
+ /* Convert the PIN and IV into a DES key */
+ make_key(iv, pin->data, 8, mykey);
+
+ output =
+ (unsigned char *) nss_ZAlloc(NULL,
+ (io->u.key.key.privateKey->len + 1));
+
+ cx = DES_CreateContext((const unsigned char *) mykey, iv,
+ io->u.key.cipher, PR_FALSE);
+
+ rv = DES_Decrypt(cx, output, &len, io->u.key.key.privateKey->len,
+ io->u.key.key.privateKey->data,
+ io->u.key.key.privateKey->len);
+ DES_DestroyContext(cx, PR_TRUE);
+
+ if (iv) {
+ free(iv);
+ iv = NULL;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ lpk = (NSSLOWKEYPrivateKey *) nss_ZAlloc(NULL,
+ sizeof (NSSLOWKEYPrivateKey));
+ if (lpk == NULL) {
+ goto loser;
+ }
+
+ lpk->arena = arena;
+ lpk->keyType = NSSLOWKEYRSAKey;
+ prepare_low_rsa_priv_key_for_asn1(lpk);
+
+ nss_ZFreeIf(io->u.key.key.privateKey->data);
+ io->u.key.key.privateKey->len = len - output[len - 1];
+ io->u.key.key.privateKey->data =
+ (void *) nss_ZAlloc(NULL, io->u.key.key.privateKey->len);
+ memcpy(io->u.key.key.privateKey->data, output, len - output[len - 1]);
+
+ /* Decode the resulting blob and see if it is a decodable DER that fits
+ * our private key template. If so we declare success and move on. If not
+ * then we return an error.
+ */
+ rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate,
+ io->u.key.key.privateKey);
+ pem_DestroyPrivateKey(lpk);
+ arena = NULL;
+ if (rv != SECSuccess)
+ goto loser;
+
+ return CKR_OK;
+
+ loser:
+ if (arena)
+ PORT_FreeArena(arena, PR_FALSE);
+ if (iv)
+ free(iv);
+ nss_ZFreeIf(output);
+
+ return CKR_PIN_INCORRECT;
+}
+
+NSS_IMPLEMENT NSSCKMDSession *
+pem_CreateSession
+(
+ NSSCKFWSession * fwSession,
+ CK_RV * pError
+)
+{
+ NSSArena *arena;
+ NSSCKMDSession *rv;
+
+ plog("pem_CreateSession returning new session\n");
+ arena = NSSCKFWSession_GetArena(fwSession, pError);
+ if ((NSSArena *) NULL == arena) {
+ return (NSSCKMDSession *) NULL;
+ }
+
+ rv = nss_ZNEW(arena, NSSCKMDSession);
+ if ((NSSCKMDSession *) NULL == rv) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDSession *) NULL;
+ }
+
+ /*
+ * rv was zeroed when allocated, so we only
+ * need to set the non-zero members.
+ */
+
+ rv->etc = (void *) fwSession;
+ /* rv->Close */
+ /* rv->GetDeviceError */
+ rv->Login = pem_mdSession_Login;
+ /* rv->Logout */
+ /* rv->InitPIN */
+ /* rv->SetPIN */
+ /* rv->GetOperationStateLen */
+ /* rv->GetOperationState */
+ /* rv->SetOperationState */
+ rv->CreateObject = pem_mdSession_CreateObject;
+ rv->CopyObject = pem_mdSession_CopyObject;
+ rv->FindObjectsInit = pem_mdSession_FindObjectsInit;
+ /* rv->SeedRandom */
+ /* rv->GetRandom */
+ /* rv->null */
+
+ return rv;
+}
diff --git a/pslot.c b/pslot.c
new file mode 100644
index 0000000..587e237
--- /dev/null
+++ b/pslot.c
@@ -0,0 +1,184 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+
+/*
+ * pslot.c
+ *
+ * This file implements the NSSCKMDSlot object for the
+ * "PEM objects" cryptoki module.
+ */
+
+static NSSUTF8 *
+pem_mdSlot_GetSlotDescription
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ CK_SLOT_ID slotID;
+ NSSArena *arena;
+ char *slotid;
+
+ arena = NSSCKFWInstance_GetArena(fwInstance, pError);
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ slotid = (char *) nss_ZAlloc(arena, 256);
+ snprintf(slotid, 256, "PEM Slot #%ld", slotID);
+
+ return (NSSUTF8 *) slotid;
+}
+
+static NSSUTF8 *
+pem_mdSlot_GetManufacturerID
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_ManufacturerID;
+}
+
+static CK_VERSION
+pem_mdSlot_GetHardwareVersion
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_HardwareVersion;
+}
+
+static CK_VERSION
+pem_mdSlot_GetFirmwareVersion
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_FirmwareVersion;
+}
+
+static NSSCKMDToken *
+pem_mdSlot_GetToken
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSCKMDToken *) mdSlot->etc;
+}
+
+CK_BBOOL
+pem_mdSlot_GetRemovableDevice
+(
+ NSSCKMDSlot * mdSlot,
+ NSSCKFWSlot * fwSlot,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return CK_TRUE;
+}
+
+NSSCKMDSlot *
+pem_NewSlot
+(
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ NSSArena *arena;
+ NSSCKMDSlot *mdSlot;
+ pemToken *token = NULL;
+
+ plog("pem_NewSlot\n");
+ arena = NSSCKFWInstance_GetArena(fwInstance, pError);
+ if ((NSSArena *) NULL == arena) {
+ if (CKR_OK == *pError) {
+ *pError = CKR_GENERAL_ERROR;
+ }
+ }
+
+ mdSlot = nss_ZNEW(arena, NSSCKMDSlot);
+ if ((NSSCKMDSlot *) NULL == mdSlot) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDSlot *) NULL;
+ }
+
+ token = pem_NewToken(fwInstance, pError);
+
+ mdSlot->etc = token;
+ mdSlot->GetSlotDescription = pem_mdSlot_GetSlotDescription;
+ mdSlot->GetManufacturerID = pem_mdSlot_GetManufacturerID;
+ mdSlot->GetHardwareVersion = pem_mdSlot_GetHardwareVersion;
+ mdSlot->GetFirmwareVersion = pem_mdSlot_GetFirmwareVersion;
+ mdSlot->GetRemovableDevice = pem_mdSlot_GetRemovableDevice;
+ mdSlot->GetToken = pem_mdSlot_GetToken;
+
+ return mdSlot;
+}
+
+NSS_IMPLEMENT_DATA const NSSCKMDSlot
+pem_mdSlot = {
+ (void *) NULL, /* etc */
+ NULL, /* Initialize */
+ NULL, /* Destroy */
+ pem_mdSlot_GetSlotDescription,
+ pem_mdSlot_GetManufacturerID,
+ NULL, /* GetTokenPresent -- defaults to true */
+ pem_mdSlot_GetRemovableDevice,
+ NULL, /* GetHardwareSlot -- defaults to false */
+ pem_mdSlot_GetHardwareVersion,
+ pem_mdSlot_GetFirmwareVersion,
+ pem_mdSlot_GetToken,
+ (void *) NULL /* null terminator */
+};
diff --git a/ptoken.c b/ptoken.c
new file mode 100644
index 0000000..67b5f10
--- /dev/null
+++ b/ptoken.c
@@ -0,0 +1,333 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckpem.h"
+
+/*
+ * ptoken.c
+ *
+ * This file implements the NSSCKMDToken object for the
+ * "PEM objects" cryptoki module.
+ */
+
+NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS];
+
+static NSSUTF8 *
+pem_mdToken_GetLabel
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ NSSCKFWSlot *fwSlot;
+ CK_SLOT_ID slotID;
+ NSSArena *arena;
+ char *tokenid;
+
+ arena = NSSCKFWInstance_GetArena(fwInstance, pError);
+ fwSlot = NSSCKFWToken_GetFWSlot(fwToken);
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ tokenid = (char *) nss_ZAlloc(arena, 256);
+ snprintf(tokenid, 256, "PEM Token #%ld", slotID);
+
+ return (NSSUTF8 *) tokenid;
+}
+
+static NSSUTF8 *
+pem_mdToken_GetManufacturerID
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_ManufacturerID;
+}
+
+static NSSUTF8 *
+pem_mdToken_GetModel
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_TokenModel;
+}
+
+static NSSUTF8 *
+pem_mdToken_GetSerialNumber
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ return (NSSUTF8 *) pem_TokenSerialNumber;
+}
+
+static CK_BBOOL
+pem_mdToken_GetIsWriteProtected
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return CK_TRUE;
+}
+
+static CK_VERSION
+pem_mdToken_GetHardwareVersion
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_HardwareVersion;
+}
+
+static CK_VERSION
+pem_mdToken_GetFirmwareVersion
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return pem_FirmwareVersion;
+}
+
+static NSSCKMDSession *pem_mdToken_OpenSession
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ NSSCKFWSession * fwSession,
+ CK_BBOOL rw,
+ CK_RV * pError
+)
+{
+ plog("pem_mdToken_OpenSession\n");
+ return pem_CreateSession(fwSession, pError);
+}
+
+static CK_ULONG
+pem_mdToken_GetMechanismCount
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ return (CK_ULONG) 1;
+}
+
+static CK_RV
+pem_mdToken_GetMechanismTypes
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_MECHANISM_TYPE types[]
+)
+{
+ types[0] = CKM_RSA_PKCS;
+ return CKR_OK;
+}
+
+static NSSCKMDMechanism *
+pem_mdToken_GetMechanism
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance,
+ CK_MECHANISM_TYPE which,
+ CK_RV * pError
+)
+{
+ if (which != CKM_RSA_PKCS) {
+ *pError = CKR_MECHANISM_INVALID;
+ return (NSSCKMDMechanism *) NULL;
+ }
+ return (NSSCKMDMechanism *) & pem_mdMechanismRSA;
+}
+
+static CK_BBOOL
+pem_mdToken_GetUserPinInitialized
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ plog("pem_mdToken_GetUserPinInitialized: always TRUE\n");
+ return CK_TRUE;
+}
+
+static CK_BBOOL
+pem_mdToken_GetLoginRequired
+(
+ NSSCKMDToken * mdToken,
+ NSSCKFWToken * fwToken,
+ NSSCKMDInstance * mdInstance,
+ NSSCKFWInstance * fwInstance
+)
+{
+ char *label;
+ CK_RV pError;
+ NSSCKFWSlot *fwSlot;
+ CK_SLOT_ID slotID;
+
+ fwSlot = NSSCKFWToken_GetFWSlot(fwToken);
+ slotID = nssCKFWSlot_GetSlotID(fwSlot);
+
+ label = pem_mdToken_GetLabel(mdToken, fwToken, mdInstance, fwInstance,
+ &pError);
+
+ plog("pem_mdToken_GetLoginRequired %s: %d\n", label,
+ token_needsLogin[slotID - 1]);
+
+ if (token_needsLogin[slotID - 1] == PR_TRUE)
+ return CK_TRUE;
+ else
+ return CK_FALSE;
+}
+
+NSSCKMDToken *
+pem_NewToken
+(
+ NSSCKFWInstance * fwInstance,
+ CK_RV * pError
+)
+{
+ NSSArena *arena;
+ NSSCKMDToken *mdToken;
+ pemToken *token;
+
+ arena = NSSCKFWInstance_GetArena(fwInstance, pError);
+ if ((NSSArena *) NULL == arena) {
+ if (CKR_OK == *pError) {
+ *pError = CKR_GENERAL_ERROR;
+ }
+ }
+
+ mdToken = nss_ZNEW(arena, NSSCKMDToken);
+ if ((NSSCKMDToken *) NULL == mdToken) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDToken *) NULL;
+ }
+
+ token = nss_ZNEW(arena, struct pemTokenStr);
+ if ((struct pemTokenStr *) NULL == token) {
+ *pError = CKR_HOST_MEMORY;
+ return (NSSCKMDToken *) NULL;
+ }
+
+ mdToken->etc = (void *) token;
+ mdToken->GetLabel = pem_mdToken_GetLabel;
+ mdToken->GetManufacturerID = pem_mdToken_GetManufacturerID;
+ mdToken->GetModel = pem_mdToken_GetModel;
+ mdToken->GetSerialNumber = pem_mdToken_GetSerialNumber;
+ mdToken->GetIsWriteProtected = pem_mdToken_GetIsWriteProtected;
+ mdToken->GetLoginRequired = pem_mdToken_GetLoginRequired;
+ mdToken->GetUserPinInitialized = pem_mdToken_GetUserPinInitialized;
+ mdToken->GetHardwareVersion = pem_mdToken_GetHardwareVersion;
+ mdToken->GetFirmwareVersion = pem_mdToken_GetFirmwareVersion;
+ mdToken->OpenSession = pem_mdToken_OpenSession;
+ mdToken->GetMechanismCount = pem_mdToken_GetMechanismCount;
+ mdToken->GetMechanismTypes = pem_mdToken_GetMechanismTypes;
+ mdToken->GetMechanism = pem_mdToken_GetMechanism;
+
+ return mdToken;
+}
+
+#if 0
+NSS_IMPLEMENT_DATA const NSSCKMDToken pem_mdToken = {
+ (void *) NULL, /* etc */
+ NULL, /* Setup */
+ NULL, /* Invalidate */
+ NULL, /* InitToken -- default errs */
+ pem_mdToken_GetLabel,
+ pem_mdToken_GetManufacturerID,
+ pem_mdToken_GetModel,
+ pem_mdToken_GetSerialNumber,
+ NULL, /* GetHasRNG -- default is false */
+ pem_mdToken_GetIsWriteProtected,
+ pem_mdToken_GetLoginRequired,
+ pem_mdToken_GetUserPinInitialized,
+ NULL, /* GetRestoreKeyNotNeeded -- irrelevant */
+ NULL, /* GetHasClockOnToken -- default is false */
+ NULL, /* GetHasProtectedAuthenticationPath -- default is false */
+ NULL, /* GetSupportsDualCryptoOperations -- default is false */
+ NULL, /* GetMaxSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
+ NULL, /* GetMaxRwSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
+ NULL, /* GetMaxPinLen -- irrelevant */
+ NULL, /* GetMinPinLen -- irrelevant */
+ NULL, /* GetTotalPublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
+ NULL, /* GetFreePublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
+ NULL, /* GetTotalPrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
+ NULL, /* GetFreePrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
+ pem_mdToken_GetHardwareVersion,
+ pem_mdToken_GetFirmwareVersion,
+ NULL, /* GetUTCTime -- no clock */
+ pem_mdToken_OpenSession,
+ pem_mdToken_GetMechanismCount,
+ pem_mdToken_GetMechanismTypes,
+ pem_mdToken_GetMechanism,
+ (void *) NULL /* null terminator */
+};
+#endif
diff --git a/rsawrapr.c b/rsawrapr.c
new file mode 100644
index 0000000..5ac4f39
--- /dev/null
+++ b/rsawrapr.c
@@ -0,0 +1,924 @@
+/*
+ * PKCS#1 encoding and decoding functions.
+ * This file is believed to contain no code licensed from other parties.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id: $ */
+
+#include "ckpem.h"
+#include "blapi.h"
+#include "softoken.h"
+#include "sechash.h"
+#include "base.h"
+
+#include "secerr.h"
+
+#define RSA_BLOCK_MIN_PAD_LEN 8
+#define RSA_BLOCK_FIRST_OCTET 0x00
+#define RSA_BLOCK_PRIVATE0_PAD_OCTET 0x00
+#define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff
+#define RSA_BLOCK_AFTER_PAD_OCTET 0x00
+
+#define OAEP_SALT_LEN 8
+#define OAEP_PAD_LEN 8
+#define OAEP_PAD_OCTET 0x00
+
+#define FLAT_BUFSIZE 512 /* bytes to hold flattened SHA1Context. */
+
+unsigned
+pem_PublicModulusLen(NSSLOWKEYPublicKey *pubk)
+{
+ unsigned char b0;
+
+ /* interpret modulus length as key strength... in
+ * fortezza that's the public key length */
+
+ switch (pubk->keyType) {
+ case pemLOWKEYRSAKey:
+ b0 = pubk->u.rsa.modulus.data[0];
+ return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static SHA1Context *SHA1_CloneContext(SHA1Context * original)
+{
+ SHA1Context *clone = NULL;
+ unsigned char *pBuf;
+ int sha1ContextSize = SHA1_FlattenSize(original);
+ SECStatus frv;
+ unsigned char buf[FLAT_BUFSIZE];
+
+ PORT_Assert(sizeof buf >= sha1ContextSize);
+ if (sizeof buf >= sha1ContextSize) {
+ pBuf = buf;
+ } else {
+ pBuf = nss_ZAlloc(NULL, sha1ContextSize);
+ if (!pBuf)
+ goto done;
+ }
+
+ frv = SHA1_Flatten(original, pBuf);
+ if (frv == SECSuccess) {
+ clone = SHA1_Resurrect(pBuf, NULL);
+ memset(pBuf, 0, sha1ContextSize);
+ }
+ done:
+ if (pBuf != buf)
+ nss_ZFreeIf(pBuf);
+ return clone;
+}
+
+/*
+ * Modify data by XORing it with a special hash of salt.
+ */
+static SECStatus
+oaep_xor_with_h1(unsigned char *data, unsigned int datalen,
+ unsigned char *salt, unsigned int saltlen)
+{
+ SHA1Context *sha1cx;
+ unsigned char *dp, *dataend;
+ unsigned char end_octet;
+
+ sha1cx = SHA1_NewContext();
+ if (sha1cx == NULL) {
+ return SECFailure;
+ }
+
+ /*
+ * Get a hash of salt started; we will use it several times,
+ * adding in a different end octet (x00, x01, x02, ...).
+ */
+ SHA1_Begin(sha1cx);
+ SHA1_Update(sha1cx, salt, saltlen);
+ end_octet = 0;
+
+ dp = data;
+ dataend = data + datalen;
+
+ while (dp < dataend) {
+ SHA1Context *sha1cx_h1;
+ unsigned int sha1len, sha1off;
+ unsigned char sha1[SHA1_LENGTH];
+
+ /*
+ * Create hash of (salt || end_octet)
+ */
+ sha1cx_h1 = SHA1_CloneContext(sha1cx);
+ SHA1_Update(sha1cx_h1, &end_octet, 1);
+ SHA1_End(sha1cx_h1, sha1, &sha1len, sizeof(sha1));
+ SHA1_DestroyContext(sha1cx_h1, PR_TRUE);
+ PORT_Assert(sha1len == SHA1_LENGTH);
+
+ /*
+ * XOR that hash with the data.
+ * When we have fewer than SHA1_LENGTH octets of data
+ * left to xor, use just the low-order ones of the hash.
+ */
+ sha1off = 0;
+ if ((dataend - dp) < SHA1_LENGTH)
+ sha1off = SHA1_LENGTH - (dataend - dp);
+ while (sha1off < SHA1_LENGTH)
+ *dp++ ^= sha1[sha1off++];
+
+ /*
+ * Bump for next hash chunk.
+ */
+ end_octet++;
+ }
+
+ SHA1_DestroyContext(sha1cx, PR_TRUE);
+ return SECSuccess;
+}
+
+/*
+ * Modify salt by XORing it with a special hash of data.
+ */
+static SECStatus
+oaep_xor_with_h2(unsigned char *salt, unsigned int saltlen,
+ unsigned char *data, unsigned int datalen)
+{
+ unsigned char sha1[SHA1_LENGTH];
+ unsigned char *psalt, *psha1, *saltend;
+ SECStatus rv;
+
+ /*
+ * Create a hash of data.
+ */
+ rv = SHA1_HashBuf(sha1, data, datalen);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ /*
+ * XOR the low-order octets of that hash with salt.
+ */
+ PORT_Assert(saltlen <= SHA1_LENGTH);
+ saltend = salt + saltlen;
+ psalt = salt;
+ psha1 = sha1 + SHA1_LENGTH - saltlen;
+ while (psalt < saltend) {
+ *psalt++ ^= *psha1++;
+ }
+
+ return SECSuccess;
+}
+
+/*
+ * Format one block of data for public/private key encryption using
+ * the rules defined in PKCS #1.
+ */
+static unsigned char *rsa_FormatOneBlock(unsigned modulusLen,
+ RSA_BlockType blockType,
+ SECItem * data)
+{
+ unsigned char *block;
+ unsigned char *bp;
+ int padLen;
+ int i;
+ SECStatus rv;
+
+ block = (unsigned char *) nss_ZAlloc(NULL, modulusLen);
+ if (block == NULL)
+ return NULL;
+
+ bp = block;
+
+ /*
+ * All RSA blocks start with two octets:
+ * 0x00 || BlockType
+ */
+ *bp++ = RSA_BLOCK_FIRST_OCTET;
+ *bp++ = (unsigned char) blockType;
+
+ switch (blockType) {
+
+ /*
+ * Blocks intended for private-key operation.
+ */
+ case RSA_BlockPrivate0: /* essentially unused */
+ case RSA_BlockPrivate: /* preferred method */
+ /*
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ * 1 1 padLen 1 data->len
+ * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
+ */
+ padLen = modulusLen - data->len - 3;
+ PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
+ if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+ nsslibc_memset(bp,
+ blockType == RSA_BlockPrivate0
+ ? RSA_BLOCK_PRIVATE0_PAD_OCTET
+ : RSA_BLOCK_PRIVATE_PAD_OCTET, padLen);
+ bp += padLen;
+ *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
+ nsslibc_memcpy(bp, data->data, data->len);
+ break;
+
+ /*
+ * Blocks intended for public-key operation.
+ */
+ case RSA_BlockPublic:
+
+ /*
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ * 1 1 padLen 1 data->len
+ * Pad is all non-zero random bytes.
+ */
+ padLen = modulusLen - data->len - 3;
+ PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
+ if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+ for (i = 0; i < padLen; i++) {
+ /* Pad with non-zero random data. */
+ do {
+ rv = RNG_GenerateGlobalRandomBytes(bp + i, 1);
+ } while (rv == SECSuccess
+ && bp[i] == RSA_BLOCK_AFTER_PAD_OCTET);
+ if (rv != SECSuccess) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+ }
+ bp += padLen;
+ *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
+ nsslibc_memcpy(bp, data->data, data->len);
+
+ break;
+
+ /*
+ * Blocks intended for public-key operation, using
+ * Optimal Asymmetric Encryption Padding (OAEP).
+ */
+ case RSA_BlockOAEP:
+ /*
+ * 0x00 || BT || Modified2(Salt) || Modified1(PaddedData)
+ * 1 1 OAEP_SALT_LEN OAEP_PAD_LEN + data->len [+ N]
+ *
+ * where:
+ * PaddedData is "Pad1 || ActualData [|| Pad2]"
+ * Salt is random data.
+ * Pad1 is all zeros.
+ * Pad2, if present, is random data.
+ * (The "modified" fields are all the same length as the original
+ * unmodified values; they are just xor'd with other values.)
+ *
+ * Modified1 is an XOR of PaddedData with a special octet
+ * string constructed of iterated hashing of Salt (see below).
+ * Modified2 is an XOR of Salt with the low-order octets of
+ * the hash of Modified1 (see farther below ;-).
+ *
+ * Whew!
+ */
+
+
+ /*
+ * Salt
+ */
+ rv = RNG_GenerateGlobalRandomBytes(bp, OAEP_SALT_LEN);
+ if (rv != SECSuccess) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+ bp += OAEP_SALT_LEN;
+
+ /*
+ * Pad1
+ */
+ nsslibc_memset(bp, OAEP_PAD_OCTET, OAEP_PAD_LEN);
+ bp += OAEP_PAD_LEN;
+
+ /*
+ * Data
+ */
+ nsslibc_memcpy(bp, data->data, data->len);
+ bp += data->len;
+
+ /*
+ * Pad2
+ */
+ if (bp < (block + modulusLen)) {
+ rv = RNG_GenerateGlobalRandomBytes(bp,
+ block - bp + modulusLen);
+ if (rv != SECSuccess) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+ }
+
+ /*
+ * Now we have the following:
+ * 0x00 || BT || Salt || PaddedData
+ * (From this point on, "Pad1 || Data [|| Pad2]" is treated
+ * as the one entity PaddedData.)
+ *
+ * We need to turn PaddedData into Modified1.
+ */
+ if (oaep_xor_with_h1(block + 2 + OAEP_SALT_LEN,
+ modulusLen - 2 - OAEP_SALT_LEN,
+ block + 2, OAEP_SALT_LEN) != SECSuccess) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+
+ /*
+ * Now we have:
+ * 0x00 || BT || Salt || Modified1(PaddedData)
+ *
+ * The remaining task is to turn Salt into Modified2.
+ */
+ if (oaep_xor_with_h2(block + 2, OAEP_SALT_LEN,
+ block + 2 + OAEP_SALT_LEN,
+ modulusLen - 2 - OAEP_SALT_LEN) !=
+ SECSuccess) {
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+
+ break;
+
+ default:
+ PORT_Assert(0);
+ nss_ZFreeIf(block);
+ return NULL;
+ }
+
+ return block;
+}
+
+static SECStatus
+rsa_FormatBlock(SECItem * result, unsigned modulusLen,
+ RSA_BlockType blockType, SECItem * data)
+{
+ /*
+ * XXX For now assume that the data length fits in a single
+ * XXX encryption block; the ASSERTs below force this.
+ * XXX To fix it, each case will have to loop over chunks whose
+ * XXX lengths satisfy the assertions, until all data is handled.
+ * XXX (Unless RSA has more to say about how to handle data
+ * XXX which does not fit in a single encryption block?)
+ * XXX And I do not know what the result is supposed to be,
+ * XXX so the interface to this function may need to change
+ * XXX to allow for returning multiple blocks, if they are
+ * XXX not wanted simply concatenated one after the other.
+ */
+
+ switch (blockType) {
+ case RSA_BlockPrivate0:
+ case RSA_BlockPrivate:
+ case RSA_BlockPublic:
+ /*
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ *
+ * The "3" below is the first octet + the second octet + the 0x00
+ * octet that always comes just before the ActualData.
+ */
+ PORT_Assert(data->len <=
+ (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
+
+ result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
+ if (result->data == NULL) {
+ result->len = 0;
+ return SECFailure;
+ }
+ result->len = modulusLen;
+
+ break;
+
+ case RSA_BlockOAEP:
+ /*
+ * 0x00 || BT || M1(Salt) || M2(Pad1||ActualData[||Pad2])
+ *
+ * The "2" below is the first octet + the second octet.
+ * (The other fields do not contain the clear values, but are
+ * the same length as the clear values.)
+ */
+ PORT_Assert(data->len <= (modulusLen - (2 + OAEP_SALT_LEN
+ + OAEP_PAD_LEN)));
+
+ result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
+ if (result->data == NULL) {
+ result->len = 0;
+ return SECFailure;
+ }
+ result->len = modulusLen;
+
+ break;
+
+ case RSA_BlockRaw:
+ /*
+ * Pad || ActualData
+ * Pad is zeros. The application is responsible for recovering
+ * the actual data.
+ */
+ if (data->len > modulusLen) {
+ return SECFailure;
+ }
+ result->data = (unsigned char *) nss_ZAlloc(NULL, modulusLen);
+ result->len = modulusLen;
+ nsslibc_memcpy(result->data + (modulusLen - data->len), data->data,
+ data->len);
+ break;
+
+ default:
+ PORT_Assert(0);
+ result->data = NULL;
+ result->len = 0;
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+pem_RSA_Sign(pemLOWKEYPrivateKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int maxOutputLen,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv = SECSuccess;
+ unsigned int modulus_len = pem_PrivateModulusLen(key);
+ SECItem formatted;
+ SECItem unformatted;
+
+ if (maxOutputLen < modulus_len)
+ return SECFailure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ return SECFailure;
+
+ unformatted.len = input_len;
+ unformatted.data = input;
+ formatted.data = NULL;
+ rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPrivate,
+ &unformatted);
+ if (rv != SECSuccess)
+ goto done;
+
+ rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output,
+ formatted.data);
+ *output_len = modulus_len;
+
+ goto done;
+
+ done:
+ if (formatted.data != NULL)
+ nss_ZFreeIf(formatted.data);
+ return rv;
+}
+
+#if 0
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSign(NSSLOWKEYPublicKey * key,
+ unsigned char *sign,
+ unsigned int sign_len,
+ unsigned char *hash, unsigned int hash_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+ unsigned int i;
+ unsigned char *buffer;
+
+ modulus_len = pem_PublicModulusLen(key);
+ if (sign_len != modulus_len)
+ goto failure;
+ /*
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ *
+ * The "3" below is the first octet + the second octet + the 0x00
+ * octet that always comes just before the ActualData.
+ */
+ if (hash_len > modulus_len - (3 + RSA_BLOCK_MIN_PAD_LEN))
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ buffer = (unsigned char *) nss_ZAlloc(NULL, modulus_len + 1);
+ if (!buffer)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+ if (rv != SECSuccess)
+ goto loser;
+
+ /*
+ * check the padding that was used
+ */
+ if (buffer[0] != 0 || buffer[1] != 1)
+ goto loser;
+ for (i = 2; i < modulus_len - hash_len - 1; i++) {
+ if (buffer[i] != 0xff)
+ goto loser;
+ }
+ if (buffer[i] != 0)
+ goto loser;
+
+ /*
+ * make sure we get the same results
+ */
+ if (memcmp(buffer + modulus_len - hash_len, hash, hash_len) != 0)
+ goto loser;
+
+ nss_ZFreeIf(buffer);
+ return SECSuccess;
+
+ loser:
+ nss_ZFreeIf(buffer);
+ failure:
+ return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRecover(NSSLOWKEYPublicKey * key,
+ unsigned char *data,
+ unsigned int *data_len,
+ unsigned int max_output_len,
+ unsigned char *sign, unsigned int sign_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+ unsigned int i;
+ unsigned char *buffer;
+
+ if (sign_len != modulus_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ buffer = (unsigned char *) nss_ZAlloc(NULL, modulus_len + 1);
+ if (!buffer)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+ if (rv != SECSuccess)
+ goto loser;
+ *data_len = 0;
+
+ /*
+ * check the padding that was used
+ */
+ if (buffer[0] != 0 || buffer[1] != 1)
+ goto loser;
+ for (i = 2; i < modulus_len; i++) {
+ if (buffer[i] == 0) {
+ *data_len = modulus_len - i - 1;
+ break;
+ }
+ if (buffer[i] != 0xff)
+ goto loser;
+ }
+ if (*data_len == 0)
+ goto loser;
+ if (*data_len > max_output_len)
+ goto loser;
+
+ /*
+ * make sure we get the same results
+ */
+ nsslibc_memcpy(data, buffer + modulus_len - *data_len, *data_len);
+
+ nss_ZFreeIf(buffer);
+ return SECSuccess;
+
+ loser:
+ nss_ZFreeIf(buffer);
+ failure:
+ return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_EncryptBlock(NSSLOWKEYPublicKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int max_output_len,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+ SECItem formatted;
+ SECItem unformatted;
+
+ formatted.data = NULL;
+ if (max_output_len < modulus_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ unformatted.len = input_len;
+ unformatted.data = input;
+ formatted.data = NULL;
+ rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPublic,
+ &unformatted);
+ if (rv != SECSuccess)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
+ if (rv != SECSuccess)
+ goto failure;
+
+ nss_ZFreeIf(formatted.data);
+ *output_len = modulus_len;
+ return SECSuccess;
+
+ failure:
+ if (formatted.data != NULL)
+ nss_ZFreeIf(formatted.data);
+ return SECFailure;
+}
+#endif
+
+/* XXX Doesn't set error code */
+SECStatus
+pem_RSA_DecryptBlock(pemLOWKEYPrivateKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int max_output_len,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PrivateModulusLen(key);
+ unsigned int i;
+ unsigned char *buffer;
+
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+ if (input_len != modulus_len)
+ goto failure;
+
+ buffer = (unsigned char *) nss_ZAlloc(NULL, modulus_len + 1);
+ if (!buffer)
+ goto failure;
+
+ rv = RSA_PrivateKeyOp(&key->u.rsa, buffer, input);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ if (buffer[0] != 0 || buffer[1] != 2)
+ goto loser;
+ *output_len = 0;
+ for (i = 2; i < modulus_len; i++) {
+ if (buffer[i] == 0) {
+ *output_len = modulus_len - i - 1;
+ break;
+ }
+ }
+ if (*output_len == 0)
+ goto loser;
+ if (*output_len > max_output_len)
+ goto loser;
+
+ nsslibc_memcpy(output, buffer + modulus_len - *output_len, *output_len);
+
+ nss_ZFreeIf(buffer);
+ return SECSuccess;
+
+ loser:
+ nss_ZFreeIf(buffer);
+ failure:
+ return SECFailure;
+}
+
+#if 0
+/* XXX Doesn't set error code */
+/*
+ * added to make pkcs #11 happy
+ * RAW is RSA_X_509
+ */
+SECStatus
+pem_RSA_SignRaw(pemLOWKEYPrivateKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int maxOutputLen,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv = SECSuccess;
+ unsigned int modulus_len = pem_PrivateModulusLen(key);
+ SECItem formatted;
+ SECItem unformatted;
+
+ if (maxOutputLen < modulus_len)
+ return SECFailure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ return SECFailure;
+
+ unformatted.len = input_len;
+ unformatted.data = input;
+ formatted.data = NULL;
+ rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw,
+ &unformatted);
+ if (rv != SECSuccess)
+ goto done;
+
+ rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output,
+ formatted.data);
+ *output_len = modulus_len;
+
+ done:
+ if (formatted.data != NULL)
+ nss_ZFreeIf(formatted.data);
+ return rv;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRaw(NSSLOWKEYPublicKey * key,
+ unsigned char *sign,
+ unsigned int sign_len,
+ unsigned char *hash, unsigned int hash_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+ unsigned char *buffer;
+
+ if (sign_len != modulus_len)
+ goto failure;
+ if (hash_len > modulus_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ buffer = (unsigned char *) nss_ZAlloc(NULL, modulus_len + 1);
+ if (!buffer)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
+ if (rv != SECSuccess)
+ goto loser;
+
+ /*
+ * make sure we get the same results
+ */
+ /* NOTE: should we verify the leading zeros? */
+ if (memcmp(buffer + (modulus_len - hash_len), hash, hash_len) !=
+ 0)
+ goto loser;
+
+ nss_ZFreeIf(buffer);
+ return SECSuccess;
+
+ loser:
+ nss_ZFreeIf(buffer);
+ failure:
+ return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_CheckSignRecoverRaw(NSSLOWKEYPublicKey * key,
+ unsigned char *data,
+ unsigned int *data_len,
+ unsigned int max_output_len,
+ unsigned char *sign, unsigned int sign_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+
+ if (sign_len != modulus_len)
+ goto failure;
+ if (max_output_len < modulus_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, data, sign);
+ if (rv != SECSuccess)
+ goto failure;
+
+ *data_len = modulus_len;
+ return SECSuccess;
+
+ failure:
+ return SECFailure;
+}
+
+
+/* XXX Doesn't set error code */
+SECStatus
+RSA_EncryptRaw(NSSLOWKEYPublicKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int max_output_len,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PublicModulusLen(key);
+ SECItem formatted;
+ SECItem unformatted;
+
+ formatted.data = NULL;
+ if (max_output_len < modulus_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+
+ unformatted.len = input_len;
+ unformatted.data = input;
+ formatted.data = NULL;
+ rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw,
+ &unformatted);
+ if (rv != SECSuccess)
+ goto failure;
+
+ rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
+ if (rv != SECSuccess)
+ goto failure;
+
+ nss_ZFreeIf(formatted.data);
+ *output_len = modulus_len;
+ return SECSuccess;
+
+ failure:
+ if (formatted.data != NULL)
+ nss_ZFreeIf(formatted.data);
+ return SECFailure;
+}
+
+/* XXX Doesn't set error code */
+SECStatus
+pem_RSA_DecryptRaw(pemLOWKEYPrivateKey * key,
+ unsigned char *output,
+ unsigned int *output_len,
+ unsigned int max_output_len,
+ unsigned char *input, unsigned int input_len)
+{
+ SECStatus rv;
+ unsigned int modulus_len = pem_PrivateModulusLen(key);
+
+ if (modulus_len <= 0)
+ goto failure;
+ if (modulus_len > max_output_len)
+ goto failure;
+ PORT_Assert(key->keyType == pemLOWKEYRSAKey);
+ if (key->keyType != pemLOWKEYRSAKey)
+ goto failure;
+ if (input_len != modulus_len)
+ goto failure;
+
+ rv = RSA_PrivateKeyOp(&key->u.rsa, output, input);
+ if (rv != SECSuccess) {
+ goto failure;
+ }
+
+ *output_len = modulus_len;
+ return SECSuccess;
+
+ failure:
+ return SECFailure;
+}
+#endif
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..338b89d
--- /dev/null
+++ b/util.c
@@ -0,0 +1,288 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rob Crittenden (rcritten@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* cribbed from secutil.c */
+
+#include "prtypes.h"
+#include "prtime.h"
+#include "prlong.h"
+#include "prerror.h"
+#include "prprf.h"
+#include "plgetopt.h"
+#include "prenv.h"
+#include "prnetdb.h"
+#include "base.h"
+#include "base64.h"
+
+#include "cryptohi.h"
+#include "secpkcs7.h"
+#include "secerr.h"
+#include <stdarg.h>
+
+#define CHUNK_SIZE 512
+#define PUT_Object(obj,err) \
+ { \
+ if (count >= size) { \
+ *derlist = *derlist ? \
+ nss_ZREALLOCARRAY(*derlist, SECItem *, \
+ (size+CHUNK_SIZE) ) : \
+ nss_ZNEWARRAY(NULL, SECItem *, \
+ (size+CHUNK_SIZE) ) ; \
+ if ((SECItem **)NULL == *derlist) { \
+ err = CKR_HOST_MEMORY; \
+ goto loser; \
+ } \
+ size += CHUNK_SIZE; \
+ } \
+ (*derlist)[ count ] = (obj); \
+ count++; \
+ }
+
+/* Read certificates from a flat file */
+
+static SECItem *AllocItem(SECItem * item, unsigned int len)
+{
+ SECItem *result = NULL;
+
+ if (item == NULL) {
+ result = nss_ZAlloc(NULL, sizeof(SECItem));
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(item->data == NULL);
+ result = item;
+ }
+
+ result->len = len;
+ if (len) {
+ result->data = nss_ZAlloc(NULL, len);
+ }
+
+ return (result);
+
+ loser:
+ if (result != NULL) {
+ SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ return (NULL);
+}
+
+static SECStatus FileToItem(SECItem * dst, PRFileDesc * src)
+{
+ PRFileInfo info;
+ PRInt32 numBytes;
+ PRStatus prStatus;
+
+ prStatus = PR_GetOpenFileInfo(src, &info);
+
+ if (prStatus != PR_SUCCESS) {
+ return SECFailure;
+ }
+
+ /* XXX workaround for 3.1, not all utils zero dst before sending */
+ dst->data = 0;
+ if (!AllocItem(dst, info.size+1))
+ goto loser;
+
+ numBytes = PR_Read(src, dst->data, info.size);
+ if (numBytes != info.size) {
+ goto loser;
+ }
+
+ return SECSuccess;
+ loser:
+ SECITEM_FreeItem(dst, PR_FALSE);
+ nss_ZFreeIf(dst);
+ return SECFailure;
+}
+
+int
+ReadDERFromFile(SECItem *** derlist, char *filename, PRBool ascii,
+ int *cipher, char **ivstring, PRBool certsonly)
+{
+ SECStatus rv;
+ PRFileDesc *inFile;
+ int count = 0, size = 0;
+ SECItem *der;
+ int error;
+ SECItem filedata;
+ char *c, *iv;
+
+ inFile = PR_Open(filename, PR_RDONLY, 0);
+ if (!inFile)
+ return -1;
+
+ if (ascii) {
+ /* First convert ascii to binary */
+ char *asc, *body;
+
+ /* Read in ascii data */
+ rv = FileToItem(&filedata, inFile);
+ asc = (char *) filedata.data;
+ if (!asc) {
+ PR_Close(inFile);
+ return -1;
+ }
+
+ /* check for headers and trailers and remove them */
+ if ((body = strstr(asc, "-----BEGIN")) != NULL) {
+ int key = 0;
+ while ((asc) && ((body = strstr(asc, "-----BEGIN")) != NULL)) {
+ key = 0;
+ if (strncmp(body, "-----BEGIN RSA PRIVATE KEY", 25) == 0) {
+ key = 1;
+ c = body;
+ body = strchr(body, '\n');
+ body++;
+ if (strncmp(body, "Proc-Type: 4,ENCRYPTED", 22) == 0) {
+ body = strchr(body, '\n');
+ body++;
+ if (strncmp(body, "DEK-Info: ", 10) == 0) {
+ body += 10;
+ c = body;
+ body = strchr(body, ',');
+ if (body == NULL)
+ goto loser;
+ *body = '\0';
+ if (!strcasecmp(c, "DES-EDE3-CBC"))
+ *cipher = NSS_DES_EDE3_CBC;
+ else if (!strcasecmp(c, "DES-CBC"))
+ *cipher = NSS_DES_CBC;
+ else {
+ *cipher = -1;
+ goto loser;
+ }
+ body++;
+ iv = body;
+ body = strchr(body, '\n');
+ if (body == NULL)
+ goto loser;
+ *body = '\0';
+ body++;
+ *ivstring = strdup(iv);
+ }
+ } else { /* Else the private key is not encrypted */
+ *cipher = 0;
+ body = c;
+ }
+ }
+ der = (SECItem *) malloc(sizeof(SECItem));
+
+ char *trailer = NULL;
+ asc = body;
+ body = strchr(body, '\n');
+ if (!body)
+ body = strchr(asc, '\r'); /* maybe this is a MAC file */
+ if (body) {
+ trailer = strstr(++body, "-----END");
+ }
+ if (trailer != NULL) {
+ asc = trailer + 1;
+ *trailer = '\0';
+ } else {
+ goto loser;
+ }
+
+ /* Convert to binary */
+ rv = ATOB_ConvertAsciiToItem(der, body);
+ if (rv) {
+ goto loser;
+ }
+ if ((certsonly && !key) || (!certsonly && key))
+ PUT_Object(der, error);
+ } /* while */
+ } else { /* No headers and footers, translate the blob */
+ der = nss_ZNEW(NULL, SECItem);
+ rv = ATOB_ConvertAsciiToItem(der, asc);
+ if (rv) {
+ goto loser;
+ }
+ }
+
+ nss_ZFreeIf(filedata.data);
+ filedata.data = 0;
+ filedata.len = 0;
+ } else {
+ /* Read in binary der */
+ rv = FileToItem(der, inFile);
+ if (rv) {
+ PR_Close(inFile);
+ return -1;
+ }
+ }
+ PR_Close(inFile);
+ return count;
+
+ loser:
+ if (filedata.len > 0)
+ nss_ZFreeIf(filedata.data);
+ PR_Close(inFile);
+ return -1;
+}
+
+FILE *plogfile;
+
+void open_log()
+{
+#ifdef DEBUG
+ plogfile = fopen("/tmp/pkcs11.log", "a");
+#endif
+
+ return;
+}
+
+void close_log()
+{
+#ifdef DEBUG
+ fclose(plogfile);
+#endif
+ return;
+}
+
+void plog(const char *fmt, ...)
+{
+#ifdef DEBUG
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(plogfile, fmt, ap);
+ va_end(ap);
+
+ fflush(plogfile);
+#endif
+}