Created
August 18, 2022 17:22
-
-
Save rb2k/5cd5216b07f00816028dcf1a5f6bc688 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sources taken from https://git.fedorahosted.org/git/nss-pem.git | |
Patches taken from http://pkgs.fedoraproject.org/cgit/nss.git/ | |
Following patches were applied in that order: | |
nss-enable-pem.patch | |
0039-Sync-up-with-nss-3.15.4-changes-in-freebl-and-softok.patch | |
Signed-off-by: Lars Wendler <[email protected]> | |
--- nss-3.15.4/nss/lib/ckfw/manifest.mn | |
+++ nss-3.15.4/nss/lib/ckfw/manifest.mn | |
@@ -5,7 +5,7 @@ | |
CORE_DEPTH = ../.. | |
-DIRS = builtins | |
+DIRS = builtins pem | |
PRIVATE_EXPORTS = \ | |
ck.h \ | |
--- nss-3.15.4/nss/lib/ckfw/pem/anchor.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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" | |
--- nss-3.15.4/nss/lib/ckfw/pem/ckpem.h | |
+++ nss-3.15.4/nss/lib/ckfw/pem/ckpem.h | |
@@ -0,0 +1,264 @@ | |
+#ifndef CKPEM_H | |
+#define CKPEM_H | |
+ | |
+#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 { | |
+ pemAll = -1, /* matches all types */ | |
+ pemRaw, | |
+ pemCert, | |
+ pemBareKey, | |
+ pemTrust | |
+} pemObjectType; | |
+ | |
+typedef struct pemInternalObjectStr pemInternalObject; | |
+typedef struct pemObjectListItemStr pemObjectListItem; | |
+ | |
+/* | |
+ * singly-linked list of internal objects | |
+ */ | |
+struct pemObjectListItemStr { | |
+ pemInternalObject *io; | |
+ pemObjectListItem *next; | |
+}; | |
+ | |
+/* | |
+ * 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; | |
+ unsigned char hashKeyData[128]; | |
+ SECItem *derCert; | |
+ char *nickname; | |
+ NSSCKMDObject mdObject; | |
+ CK_SLOT_ID slotID; | |
+ CK_ULONG gobjIndex; | |
+ int refCount; | |
+ | |
+ /* used by pem_mdFindObjects_Next */ | |
+ CK_BBOOL extRef; | |
+ | |
+ /* If list != NULL, the object contains no useful data except of the list | |
+ * of slave objects */ | |
+ pemObjectListItem *list; | |
+}; | |
+ | |
+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 * | |
+AddObjectIfNeeded(CK_OBJECT_CLASS objClass, pemObjectType type, | |
+ SECItem *certDER, SECItem *keyDER, char *filename, int objid, | |
+ CK_SLOT_ID slotID); | |
+ | |
+void pem_DestroyInternalObject (pemInternalObject *io); | |
+ | |
+ | |
+/* prsa.c */ | |
+unsigned int pem_PrivateModulusLen(pemLOWKEYPrivateKey *privk); | |
+ | |
+/* ptoken.c */ | |
+NSSCKMDToken * pem_NewToken(NSSCKFWInstance *fwInstance, CK_RV *pError); | |
+ | |
+/* util.c */ | |
+void open_log(); | |
+void plog(const char *fmt, ...); | |
+ | |
+#endif /* CKPEM_H */ | |
--- nss-3.15.4/nss/lib/ckfw/pem/ckpemver.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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__; | |
--- nss-3.15.4/nss/lib/ckfw/pem/config.mk | |
+++ nss-3.15.4/nss/lib/ckfw/pem/config.mk | |
@@ -0,0 +1,71 @@ | |
+# | |
+# ***** 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 ***** | |
+CONFIG_CVS_ID = "@(#) $RCSfile: config.mk,v $ $Revision: 1.11 $ $Date: 2005/01/20 02:25:46 $" | |
+ | |
+# | |
+# Override TARGETS variable so that only shared libraries | |
+# are specifed as dependencies within rules.mk. | |
+# | |
+ | |
+TARGETS = $(SHARED_LIBRARY) | |
+LIBRARY = | |
+IMPORT_LIBRARY = | |
+PROGRAM = | |
+ | |
+ifeq (,$(filter-out WIN%,$(OS_TARGET))) | |
+ SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) | |
+ RES = $(OBJDIR)/$(LIBRARY_NAME).res | |
+ RESNAME = $(LIBRARY_NAME).rc | |
+endif | |
+ | |
+ifdef BUILD_IDG | |
+ DEFINES += -DNSSDEBUG | |
+endif | |
+ | |
+# | |
+# To create a loadable module on Darwin, we must use -bundle. | |
+# | |
+ifeq ($(OS_TARGET),Darwin) | |
+DSO_LDOPTS = -bundle | |
+endif | |
+ | |
+ifeq ($(OS_TARGET),SunOS) | |
+# The -R '$ORIGIN' linker option instructs this library to search for its | |
+# dependencies in the same directory where it resides. | |
+MKSHLIB += -R '$$ORIGIN' | |
+endif | |
+ | |
--- nss-3.15.4/nss/lib/ckfw/pem/constants.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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 "../builtins/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"; | |
--- nss-3.15.4/nss/lib/ckfw/pem/Makefile | |
+++ nss-3.15.4/nss/lib/ckfw/pem/Makefile | |
@@ -0,0 +1,107 @@ | |
+# | |
+# ***** 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 ***** | |
+MAKEFILE_CVS_ID = "@(#) $RCSfile: Makefile,v $ $Revision: 1.5 $ $Date: 2007/05/09 00:09:37 $" | |
+ | |
+include manifest.mn | |
+include $(CORE_DEPTH)/coreconf/config.mk | |
+include config.mk | |
+ | |
+EXTRA_LIBS = \ | |
+ $(DIST)/lib/$(LIB_PREFIX)nssckfw.$(LIB_SUFFIX) \ | |
+ $(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \ | |
+ $(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) \ | |
+ $(DIST)/lib/$(LIB_PREFIX)nssutil.$(LIB_SUFFIX) \ | |
+ $(NULL) | |
+ | |
+# can't do this in manifest.mn because OS_TARGET isn't defined there. | |
+ifeq (,$(filter-out WIN%,$(OS_TARGET))) | |
+ | |
+ifdef NS_USE_GCC | |
+EXTRA_LIBS += \ | |
+ -L$(NSPR_LIB_DIR) \ | |
+ -lplc4 \ | |
+ -lplds4 \ | |
+ -lnspr4 \ | |
+ $(NULL) | |
+else | |
+EXTRA_SHARED_LIBS += \ | |
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \ | |
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \ | |
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \ | |
+ crypt32.lib \ | |
+ advapi32.lib \ | |
+ rpcrt4.lib \ | |
+ $(NULL) | |
+endif # NS_USE_GCC | |
+else | |
+ | |
+EXTRA_LIBS += \ | |
+ -L$(NSPR_LIB_DIR) \ | |
+ -lplc4 \ | |
+ -lplds4 \ | |
+ -lnspr4 \ | |
+ $(NULL) | |
+endif | |
+ | |
+ | |
+include $(CORE_DEPTH)/coreconf/rules.mk | |
+ | |
+# Generate certdata.c. | |
+generate: | |
+ $(PERL) certdata.perl < certdata.txt | |
+ | |
+# This'll need some help from a build person. | |
+ | |
+ | |
+ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.1) | |
+DSO_LDOPTS = -bM:SRE -bh:4 -bnoentry | |
+EXTRA_DSO_LDOPTS = -lc | |
+MKSHLIB = xlC $(DSO_LDOPTS) | |
+ | |
+$(SHARED_LIBRARY): $(OBJS) | |
+ @$(MAKE_OBJDIR) | |
+ rm -f $@ | |
+ $(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(EXTRA_DSO_LDOPTS) | |
+ chmod +x $@ | |
+ | |
+endif | |
+ | |
+ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2) | |
+LD += -G | |
+endif | |
+ | |
+ | |
--- nss-3.15.4/nss/lib/ckfw/pem/manifest.mn | |
+++ nss-3.15.4/nss/lib/ckfw/pem/manifest.mn | |
@@ -0,0 +1,68 @@ | |
+# | |
+# ***** 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 ***** | |
+MANIFEST_CVS_ID = "@(#) $RCSfile: manifest.mn,v $ $Revision: 1.1 $ $Date: 2005/11/04 02:05:04 $" | |
+ | |
+CORE_DEPTH = ../../.. | |
+ | |
+MODULE = nss | |
+MAPFILE = $(OBJDIR)/nsspem.def | |
+ | |
+EXPORTS = \ | |
+ nsspem.h \ | |
+ $(NULL) | |
+ | |
+CSRCS = \ | |
+ anchor.c \ | |
+ constants.c \ | |
+ pargs.c \ | |
+ pfind.c \ | |
+ pinst.c \ | |
+ pobject.c \ | |
+ prsa.c \ | |
+ psession.c \ | |
+ pslot.c \ | |
+ ptoken.c \ | |
+ ckpemver.c \ | |
+ rsawrapr.c \ | |
+ util.c \ | |
+ $(NULL) | |
+ | |
+REQUIRES = nspr | |
+ | |
+LIBRARY_NAME = nsspem | |
+ | |
+#EXTRA_SHARED_LIBS = -L$(DIST)/lib -lnssckfw -lnssb -lplc4 -lplds4 | |
--- nss-3.15.4/nss/lib/ckfw/pem/nsspem.def | |
+++ nss-3.15.4/nss/lib/ckfw/pem/nsspem.def | |
@@ -0,0 +1,58 @@ | |
+;+# | |
+;+# ***** 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) 2003 | |
+;+# 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 ***** | |
+;+# | |
+;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS | |
+;+# 1. For all unix platforms, the string ";-" means "remove this line" | |
+;+# 2. For all unix platforms, the string " DATA " will be removed from any | |
+;+# line on which it occurs. | |
+;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. | |
+;+# On AIX, lines containing ";+" will be removed. | |
+;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. | |
+;+# 5. For all unix platforms, after the above processing has taken place, | |
+;+# all characters after the first ";" on the line will be removed. | |
+;+# And for AIX, the first ";" will also be removed. | |
+;+# This file is passed directly to windows. Since ';' is a comment, all UNIX | |
+;+# directives are hidden behind ";", ";+", and ";-" | |
+;+ | |
+;+NSS_3.1 { # NSS 3.1 release | |
+;+ global: | |
+LIBRARY nsspem ;- | |
+EXPORTS ;- | |
+C_GetFunctionList; | |
+;+ local: | |
+;+*; | |
+;+}; | |
--- nss-3.15.4/nss/lib/ckfw/pem/nsspem.h | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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 */ | |
--- nss-3.15.4/nss/lib/ckfw/pem/pargs.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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; | |
+} | |
--- nss-3.15.4/nss/lib/ckfw/pem/pfind.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/pfind.c | |
@@ -0,0 +1,435 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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); | |
+ | |
+ if (!io->extRef) { | |
+ /* increase reference count only once as ckfw will free the found | |
+ * object only once */ | |
+ io->extRef = CK_TRUE; | |
+ io->refCount ++; | |
+ } | |
+ | |
+ 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; | |
+ pemObjectType type = pemRaw; | |
+ CK_OBJECT_CLASS objClass = pem_GetObjectClass(pTemplate, ulAttributeCount); | |
+ | |
+ *pError = CKR_OK; | |
+ | |
+ plog("collect_objects slot #%ld, ", slotID); | |
+ plog("%d attributes, ", ulAttributeCount); | |
+ plog("%d objects to look through.\n", pem_nobjs); | |
+ plog("Looking for: "); | |
+ /* | |
+ * now determine type of the object | |
+ */ | |
+ switch (objClass) { | |
+ case CKO_CERTIFICATE: | |
+ plog("CKO_CERTIFICATE\n"); | |
+ type = pemCert; | |
+ break; | |
+ case CKO_PUBLIC_KEY: | |
+ plog("CKO_PUBLIC_KEY\n"); | |
+ type = pemBareKey; | |
+ break; | |
+ case CKO_PRIVATE_KEY: | |
+ type = pemBareKey; | |
+ plog("CKO_PRIVATE_KEY\n"); | |
+ break; | |
+ case CKO_NETSCAPE_TRUST: | |
+ type = pemTrust; | |
+ plog("CKO_NETSCAPE_TRUST\n"); | |
+ break; | |
+ case CKO_NETSCAPE_CRL: | |
+ plog("CKO_NETSCAPE_CRL\n"); | |
+ goto done; | |
+ case CKO_NETSCAPE_SMIME: | |
+ plog("CKO_NETSCAPE_SMIME\n"); | |
+ goto done; | |
+ case CKO_NETSCAPE_BUILTIN_ROOT_LIST: | |
+ plog("CKO_NETSCAPE_BUILTIN_ROOT_LIST\n"); | |
+ goto done; | |
+ case CK_INVALID_HANDLE: | |
+ type = pemAll; /* look through all objectclasses - ignore the type field */ | |
+ 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 */ | |
+ } | |
+ | |
+ /* find objects */ | |
+ for (i = 0; i < pem_nobjs; i++) { | |
+ int match = 1; /* matches type if type not specified */ | |
+ if (NULL == gobj[i]) | |
+ continue; | |
+ | |
+ plog(" %d type = %d\n", i, gobj[i]->type); | |
+ if (type != pemAll) { | |
+ /* type specified - must match given type */ | |
+ match = (type == gobj[i]->type); | |
+ } | |
+ if (match) { | |
+ match = (slotID == gobj[i]->slotID) && | |
+ (CK_TRUE == pem_match(pTemplate, ulAttributeCount, gobj[i])); | |
+ } | |
+ if (match) { | |
+ pemInternalObject *o = gobj[i]; | |
+ PUT_Object(o, *pError); | |
+ } | |
+ } | |
+ | |
+ 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 = NULL; | |
+ 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; | |
+} | |
--- nss-3.15.4/nss/lib/ckfw/pem/pinst.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/pinst.c | |
@@ -0,0 +1,751 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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 | |
+ | |
+/* | |
+ * 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; | |
+ if (!length) | |
+ return NULL; | |
+ | |
+ tag = buf[used_length++]; | |
+ | |
+ if (rettag) { | |
+ *rettag = tag; | |
+ } | |
+ | |
+ /* blow out when we come to the end */ | |
+ if (tag == 0 || length <= used_length) { | |
+ return NULL; | |
+ } | |
+ | |
+ *data_length = buf[used_length++]; | |
+ | |
+ if (*data_length & 0x80) { | |
+ int len_count = *data_length & 0x7f; | |
+ | |
+ *data_length = 0; | |
+ | |
+ while (len_count-- > 0) { | |
+ if (length <= used_length) | |
+ return NULL; | |
+ | |
+ *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 (subject == NULL || valid == NULL || subjkey == 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; | |
+} | |
+ | |
+static CK_RV | |
+assignObjectID(pemInternalObject *o, int objid) | |
+{ | |
+ char id[16]; | |
+ int len; | |
+ | |
+ sprintf(id, "%d", objid); | |
+ len = strlen(id) + 1; /* zero terminate */ | |
+ o->id.size = len; | |
+ o->id.data = nss_ZAlloc(NULL, len); | |
+ if (o->id.data == NULL) | |
+ return CKR_HOST_MEMORY; | |
+ | |
+ nsslibc_memcpy(o->id.data, id, len); | |
+ return CKR_OK; | |
+} | |
+ | |
+static 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 *nickname; | |
+ | |
+ 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)); | |
+ nickname = filename; | |
+ 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->nickname = (char *) nss_ZAlloc(NULL, strlen(nickname) + 1); | |
+ if (o->nickname == NULL) | |
+ goto fail; | |
+ strcpy(o->nickname, nickname); | |
+ | |
+ if (CKR_OK != assignObjectID(o, objid)) | |
+ goto fail; | |
+ | |
+ o->objClass = objClass; | |
+ o->type = type; | |
+ o->slotID = slotID; | |
+ | |
+ o->derCert = nss_ZNEW(NULL, SECItem); | |
+ if (o->derCert == NULL) | |
+ goto fail; | |
+ o->derCert->data = (void *) nss_ZAlloc(NULL, certDER->len); | |
+ if (o->derCert->data == NULL) | |
+ goto fail; | |
+ o->derCert->len = certDER->len; | |
+ nsslibc_memcpy(o->derCert->data, certDER->data, certDER->len); | |
+ | |
+ switch (objClass) { | |
+ case CKO_CERTIFICATE: | |
+ case CKO_NETSCAPE_TRUST: | |
+ if (SECSuccess != GetCertFields(o->derCert->data, o->derCert->len, | |
+ &issuer, &serial, &derSN, &subject, | |
+ &valid, &subjkey)) | |
+ goto fail; | |
+ | |
+ o->u.cert.subject.data = (void *) nss_ZAlloc(NULL, subject.len); | |
+ if (o->u.cert.subject.data == NULL) | |
+ goto fail; | |
+ 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); | |
+ if (o->u.cert.issuer.data == NULL) { | |
+ nss_ZFreeIf(o->u.cert.subject.data); | |
+ goto fail; | |
+ } | |
+ 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); | |
+ if (o->u.cert.serial.data == NULL) { | |
+ nss_ZFreeIf(o->u.cert.issuer.data); | |
+ nss_ZFreeIf(o->u.cert.subject.data); | |
+ goto fail; | |
+ } | |
+ 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); | |
+ if (o->u.key.key.privateKey == NULL) | |
+ goto fail; | |
+ o->u.key.key.privateKey->data = | |
+ (void *) nss_ZAlloc(NULL, keyDER->len); | |
+ if (o->u.key.key.privateKey->data == NULL) { | |
+ nss_ZFreeIf(o->u.key.key.privateKey); | |
+ goto fail; | |
+ } | |
+ o->u.key.key.privateKey->len = keyDER->len; | |
+ nsslibc_memcpy(o->u.key.key.privateKey->data, keyDER->data, | |
+ keyDER->len); | |
+ } | |
+ | |
+ | |
+ return o; | |
+ | |
+fail: | |
+ if (o) { | |
+ if (o->derCert) { | |
+ nss_ZFreeIf(o->derCert->data); | |
+ nss_ZFreeIf(o->derCert); | |
+ } | |
+ nss_ZFreeIf(o->id.data); | |
+ nss_ZFreeIf(o->nickname); | |
+ nss_ZFreeIf(o); | |
+ } | |
+ return NULL; | |
+} | |
+ | |
+/* Compare the DER encoding of the internal object against those | |
+ * of the provided certDER or keyDER according to its objClass. | |
+ */ | |
+static PRBool | |
+derEncodingsMatch(CK_OBJECT_CLASS objClass, pemInternalObject * obj, | |
+ SECItem * certDER, SECItem * keyDER) | |
+{ | |
+ SECComparison result; | |
+ | |
+ switch (objClass) { | |
+ case CKO_CERTIFICATE: | |
+ case CKO_NETSCAPE_TRUST: | |
+ result = SECITEM_CompareItem(obj->derCert, certDER); | |
+ break; | |
+ | |
+ case CKO_PRIVATE_KEY: | |
+ result = SECITEM_CompareItem(obj->u.key.key.privateKey, keyDER); | |
+ break; | |
+ | |
+ default: | |
+ /* unhandled object class */ | |
+ return PR_FALSE; | |
+ } | |
+ | |
+ return SECEqual == result; | |
+} | |
+ | |
+static CK_RV | |
+LinkSharedKeyObject(int oldKeyIdx, int newKeyIdx) | |
+{ | |
+ int i; | |
+ for (i = 0; i < pem_nobjs; i++) { | |
+ CK_RV rv; | |
+ const pemInternalObject *obj = gobj[i]; | |
+ if (NULL == obj) | |
+ continue; | |
+ | |
+ if (atoi(obj->id.data) != oldKeyIdx) | |
+ continue; | |
+ | |
+ nss_ZFreeIf(obj->id.data); | |
+ rv = assignObjectID(obj, newKeyIdx); | |
+ if (CKR_OK != rv) | |
+ return rv; | |
+ } | |
+ | |
+ return CKR_OK; | |
+} | |
+ | |
+pemInternalObject * | |
+AddObjectIfNeeded(CK_OBJECT_CLASS objClass, | |
+ pemObjectType type, SECItem * certDER, | |
+ SECItem * keyDER, char *filename, | |
+ int objid, CK_SLOT_ID slotID) | |
+{ | |
+ int i; | |
+ | |
+ /* FIXME: copy-pasted from CreateObject */ | |
+ const char *nickname = strrchr(filename, '/'); | |
+ if (nickname && CKO_PRIVATE_KEY != objClass) | |
+ nickname++; | |
+ else | |
+ nickname = filename; | |
+ | |
+ /* first look for the object in gobj, it might be already there */ | |
+ for (i = 0; i < pem_nobjs; i++) { | |
+ if (NULL == gobj[i]) | |
+ continue; | |
+ | |
+ /* Comparing DER encodings is dependable and frees the PEM module | |
+ * from having to require clients to provide unique nicknames. | |
+ */ | |
+ if ((gobj[i]->objClass == objClass) | |
+ && (gobj[i]->type == type) | |
+ && (gobj[i]->slotID == slotID) | |
+ && derEncodingsMatch(objClass, gobj[i], certDER, keyDER)) { | |
+ | |
+ /* While adding a client certificate we (wrongly?) assumed that the | |
+ * key object will follow right after the cert object. However, if | |
+ * the key object is shared by multiple client certificates, such | |
+ * an assumption does not hold. We have to update the references. | |
+ */ | |
+ LinkSharedKeyObject(pem_nobjs, i); | |
+ | |
+ plog("AddObjectIfNeeded: re-using internal object #%i\n", i); | |
+ gobj[i]->refCount ++; | |
+ return gobj[i]; | |
+ } | |
+ } | |
+ | |
+ /* object not found, we need to create it */ | |
+ pemInternalObject *io = CreateObject(objClass, type, certDER, keyDER, | |
+ filename, objid, slotID); | |
+ if (io == NULL) | |
+ return NULL; | |
+ | |
+ /* initialize pointers to functions */ | |
+ pem_CreateMDObject(NULL, io, NULL); | |
+ | |
+ io->gobjIndex = count; | |
+ | |
+ /* add object to global array */ | |
+ 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) | |
+ return NULL; | |
+ size += PEM_ITEM_CHUNK; | |
+ } | |
+ gobj[count] = io; | |
+ count++; | |
+ pem_nobjs++; | |
+ | |
+ io->refCount ++; | |
+ return io; | |
+} | |
+ | |
+CK_RV | |
+AddCertificate(char *certfile, char *keyfile, PRBool cacert, | |
+ CK_SLOT_ID slotID) | |
+{ | |
+ pemInternalObject *o; | |
+ CK_RV error = 0; | |
+ int objid, i; | |
+ int nobjs = 0; | |
+ SECItem **objs = NULL; | |
+ char *ivstring = NULL; | |
+ int cipher; | |
+ | |
+ 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 = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, objs[i], NULL, | |
+ nickname, 0, slotID); | |
+ if (o == NULL) { | |
+ error = CKR_GENERAL_ERROR; | |
+ goto loser; | |
+ } | |
+ | |
+ /* Add the CA trust object */ | |
+ o = AddObjectIfNeeded(CKO_NETSCAPE_TRUST, pemTrust, objs[i], NULL, | |
+ nickname, 0, slotID); | |
+ if (o == NULL) { | |
+ error = CKR_GENERAL_ERROR; | |
+ goto loser; | |
+ } | |
+ } /* for */ | |
+ } else { | |
+ objid = pem_nobjs + 1; | |
+ o = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, objs[0], NULL, certfile, | |
+ objid, slotID); | |
+ if (o == NULL) { | |
+ error = CKR_GENERAL_ERROR; | |
+ goto loser; | |
+ } | |
+ | |
+ o = NULL; | |
+ | |
+ 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 = AddObjectIfNeeded(CKO_PRIVATE_KEY, pemBareKey, objs[0], | |
+ keyobjs[0], certfile, objid, slotID); | |
+ if (o == NULL) { | |
+ error = CKR_GENERAL_ERROR; | |
+ goto loser; | |
+ } | |
+ } | |
+ } | |
+ | |
+ 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 */ | |
+ char **certstrings = NULL; | |
+ char *modparms = NULL; | |
+ PRInt32 numcerts = 0; | |
+ PRBool status, error = PR_FALSE; | |
+ int i; | |
+ CK_C_INITIALIZE_ARGS_PTR modArgs = NULL; | |
+ | |
+ if (!fwInstance) return CKR_ARGUMENTS_BAD; | |
+ | |
+ modArgs = NSSCKFWInstance_GetInitArgs(fwInstance); | |
+ if (modArgs && | |
+ ((modArgs->flags & CKF_OS_LOCKING_OK) || (modArgs->CreateMutex != 0))) { | |
+ return CKR_CANT_LOCK; | |
+ } | |
+ | |
+ if (pemInitialized) { | |
+ return CKR_OK; | |
+ } | |
+ | |
+ RNG_RNGInit(); | |
+ | |
+ open_log(); | |
+ | |
+ plog("pem_Initialize\n"); | |
+ | |
+ if (!modArgs || !modArgs->LibraryParameters) { | |
+ goto done; | |
+ } | |
+ modparms = (char *) modArgs->LibraryParameters; | |
+ 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(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; | |
+ | |
+ nss_ZFreeIf(gobj); | |
+ gobj = NULL; | |
+ | |
+ pem_nobjs = 0; | |
+ size = 0; | |
+ count = 0; | |
+ | |
+ 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 */ | |
+}; | |
--- nss-3.15.4/nss/lib/ckfw/pem/pobject.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/pobject.c | |
@@ -0,0 +1,1236 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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 APPEND_LIST_ITEM(item) do { \ | |
+ item->next = nss_ZNEW(NULL, pemObjectListItem); \ | |
+ if (NULL == item->next) \ | |
+ goto loser; \ | |
+ item = item->next; \ | |
+} while (0) | |
+ | |
+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(CK_ULONG) | |
+}; | |
+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) | |
+}; | |
+ | |
+/* SEC_SkipTemplate is already defined and exported by libnssutil */ | |
+#ifdef SEC_SKIP_TEMPLATE | |
+/* | |
+ * 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} | |
+}; | |
+#endif | |
+ | |
+/* | |
+ * 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; | |
+} | |
+ | |
+/* | |
+ * Destroy internal object or list object if refCount becomes zero (after | |
+ * decrement). Safe to call with NULL argument. | |
+ */ | |
+void | |
+pem_DestroyInternalObject | |
+( | |
+ pemInternalObject * io | |
+) | |
+{ | |
+ if (NULL == io) | |
+ /* nothing to destroy */ | |
+ return; | |
+ | |
+ if (NULL != io->list) { | |
+ /* destroy list object */ | |
+ pemObjectListItem *item = io->list; | |
+ while (item) { | |
+ pemObjectListItem *next = item->next; | |
+ | |
+ /* recursion of maximal depth 1 */ | |
+ pem_DestroyInternalObject(item->io); | |
+ | |
+ nss_ZFreeIf(item); | |
+ item = next; | |
+ } | |
+ nss_ZFreeIf(io); | |
+ return; | |
+ } | |
+ | |
+ io->refCount --; | |
+ if (0 < io->refCount) | |
+ return; | |
+ | |
+ /* destroy internal object */ | |
+ 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); | |
+ /* go through */ | |
+ case pemTrust: | |
+ nss_ZFreeIf(io->id.data); | |
+ nss_ZFreeIf(io->nickname); | |
+ nss_ZFreeIf(io->derCert->data); | |
+ nss_ZFreeIf(io->derCert); | |
+ if (io->u.cert.subject.size > 0) { | |
+ nss_ZFreeIf(io->u.cert.subject.data); | |
+ } | |
+ if (io->u.cert.issuer.size > 0) { | |
+ nss_ZFreeIf(io->u.cert.issuer.data); | |
+ } | |
+ if (io->u.cert.serial.size > 0) { | |
+ nss_ZFreeIf(io->u.cert.serial.data); | |
+ } | |
+ break; | |
+ case pemBareKey: | |
+ nss_ZFreeIf(io->u.key.key.coefficient.data); | |
+ nss_ZFreeIf(io->u.key.key.exponent2.data); | |
+ nss_ZFreeIf(io->u.key.key.exponent1.data); | |
+ nss_ZFreeIf(io->u.key.key.prime2.data); | |
+ nss_ZFreeIf(io->u.key.key.prime1.data); | |
+ nss_ZFreeIf(io->u.key.key.privateExponent.data); | |
+ nss_ZFreeIf(io->u.key.key.exponent.data); | |
+ nss_ZFreeIf(io->u.key.key.modulus.data); | |
+ nss_ZFreeIf(io->u.key.key.privateKey->data); | |
+ nss_ZFreeIf(io->u.key.key.privateKey); | |
+ nss_ZFreeIf(io->u.key.key.pubKey); | |
+ nss_ZFreeIf(io->id.data); | |
+ nss_ZFreeIf(io->nickname); | |
+ nss_ZFreeIf(io->derCert->data); | |
+ nss_ZFreeIf(io->derCert); | |
+ | |
+ /* strdup'd in ReadDERFromFile */ | |
+ if (io->u.key.ivstring) | |
+ free(io->u.key.ivstring); | |
+ break; | |
+ } | |
+ | |
+ if (NULL != gobj) | |
+ /* remove reference to self from the global array */ | |
+ gobj[io->gobjIndex] = NULL; | |
+ | |
+ nss_ZFreeIf(io); | |
+ return; | |
+} | |
+ | |
+/* | |
+ * Finalize - needed | |
+ * Destroy - CKR_SESSION_READ_ONLY | |
+ * IsTokenObject - CK_TRUE | |
+ * GetAttributeCount | |
+ * GetAttributeTypes | |
+ * GetAttributeSize | |
+ * GetAttribute | |
+ * SetAttribute - unneeded | |
+ * GetObjectSize - unneeded | |
+ */ | |
+ | |
+static void | |
+pem_mdObject_Finalize | |
+( | |
+ NSSCKMDObject * mdObject, | |
+ NSSCKFWObject * fwObject, | |
+ NSSCKMDSession * mdSession, | |
+ NSSCKFWSession * fwSession, | |
+ NSSCKMDToken * mdToken, | |
+ NSSCKFWToken * fwToken, | |
+ NSSCKMDInstance * mdInstance, | |
+ NSSCKFWInstance * fwInstance | |
+) | |
+{ | |
+ pem_DestroyInternalObject((pemInternalObject *) mdObject->etc); | |
+} | |
+ | |
+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 (NULL != io->list) { | |
+ /* list object --> use the first item in the list */ | |
+ NSSCKMDObject *md = &(io->list->io->mdObject); | |
+ return md->GetAttributeCount(md, fwObject, mdSession, fwSession, | |
+ mdToken, fwToken, mdInstance, fwInstance, | |
+ pError); | |
+ } | |
+ | |
+ 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; | |
+ | |
+ if (NULL != io->list) { | |
+ /* list object --> use the first item in the list */ | |
+ NSSCKMDObject *md = &(io->list->io->mdObject); | |
+ return md->GetAttributeTypes(md, fwObject, mdSession, fwSession, | |
+ mdToken, fwToken, mdInstance, fwInstance, | |
+ typeArray, ulCount); | |
+ } | |
+ | |
+ 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; | |
+ | |
+ if (NULL != io->list) { | |
+ /* list object --> use the first item in the list */ | |
+ NSSCKMDObject *md = &(io->list->io->mdObject); | |
+ return md->GetAttributeSize(md, fwObject, mdSession, fwSession, | |
+ mdToken, fwToken, mdInstance, fwInstance, | |
+ attribute, pError); | |
+ } | |
+ | |
+ 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; | |
+ | |
+ if (NULL != io->list) { | |
+ /* list object --> use the first item in the list */ | |
+ NSSCKMDObject *md = &(io->list->io->mdObject); | |
+ return md->GetAttribute(md, fwObject, mdSession, fwSession, | |
+ mdToken, fwToken, mdInstance, fwInstance, | |
+ attribute, pError); | |
+ } | |
+ | |
+ 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 const NSSCKMDObject | |
+pem_prototype_mdObject = { | |
+ (void *) NULL, /* etc */ | |
+ pem_mdObject_Finalize, | |
+ pem_mdObject_Destroy, | |
+ pem_mdObject_IsTokenObject, | |
+ pem_mdObject_GetAttributeCount, | |
+ pem_mdObject_GetAttributeTypes, | |
+ pem_mdObject_GetAttributeSize, | |
+ pem_mdObject_GetAttribute, | |
+ NULL, /* FreeAttribute */ | |
+ NULL, /* SetAttribute */ | |
+ NULL, /* 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; | |
+ CK_BBOOL isToken; | |
+ NSSCKFWSlot *fwSlot; | |
+ CK_SLOT_ID slotID; | |
+ CK_BBOOL cacert; | |
+ char *filename; | |
+ SECItem **derlist = NULL; | |
+ int nobjs = 0; | |
+ int i; | |
+ int objid; | |
+ pemToken *token; | |
+ int cipher; | |
+ char *ivstring = NULL; | |
+ pemInternalObject *listObj = NULL; | |
+ pemObjectListItem *listItem = NULL; | |
+ | |
+ /* | |
+ * 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 | |
+ | |
+ listObj = nss_ZNEW(NULL, pemInternalObject); | |
+ if (NULL == listObj) { | |
+ nss_ZFreeIf(filename); | |
+ return NULL; | |
+ } | |
+ | |
+ listItem = listObj->list = nss_ZNEW(NULL, pemObjectListItem); | |
+ if (NULL == listItem) { | |
+ nss_ZFreeIf(listObj); | |
+ nss_ZFreeIf(filename); | |
+ return NULL; | |
+ } | |
+ | |
+ if (objClass == CKO_CERTIFICATE) { | |
+ nobjs = ReadDERFromFile(&derlist, filename, PR_TRUE, &cipher, &ivstring, PR_TRUE /* certs only */); | |
+ if (nobjs < 1) | |
+ goto loser; | |
+ | |
+ /* 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); | |
+ | |
+ if (c) | |
+ APPEND_LIST_ITEM(listItem); | |
+ listItem->io = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, | |
+ derlist[c], NULL, nickname, 0, | |
+ slotID); | |
+ if (listItem->io == NULL) | |
+ goto loser; | |
+ | |
+ /* Add the trust object */ | |
+ APPEND_LIST_ITEM(listItem); | |
+ listItem->io = AddObjectIfNeeded(CKO_NETSCAPE_TRUST, pemTrust, | |
+ derlist[c], NULL, nickname, 0, | |
+ slotID); | |
+ if (listItem->io == NULL) | |
+ goto loser; | |
+ } | |
+ } else { | |
+ listItem->io = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, | |
+ derlist[0], NULL, filename, objid, | |
+ slotID); | |
+ if (listItem->io == NULL) | |
+ goto loser; | |
+ } | |
+ } 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) | |
+ goto loser; | |
+ | |
+ certDER.len = 0; /* in case there is no equivalent cert */ | |
+ certDER.data = NULL; | |
+ | |
+ objid = -1; | |
+ for (i = 0; i < pem_nobjs; i++) { | |
+ if (NULL == gobj[i]) | |
+ continue; | |
+ | |
+ 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); | |
+ | |
+ if (certDER.data == NULL) | |
+ goto loser; | |
+ | |
+ 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; | |
+ | |
+ listItem->io = AddObjectIfNeeded(CKO_PRIVATE_KEY, pemBareKey, &certDER, | |
+ derlist[0], filename, objid, slotID); | |
+ if (listItem->io == NULL) | |
+ goto loser; | |
+ | |
+ listItem->io->u.key.ivstring = ivstring; | |
+ listItem->io->u.key.cipher = cipher; | |
+ 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) { | |
+ /* FIXME: Why 1.0s? Is it enough? Isn't it too much? | |
+ * What about e.g. 3.14s? */ | |
+ 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 == listItem->io) { | |
+ pem_DestroyInternalObject(listObj); | |
+ return (NSSCKMDObject *) NULL; | |
+ } | |
+ return pem_CreateMDObject(NULL, listObj, pError); | |
+} | |
--- nss-3.15.4/nss/lib/ckfw/pem/prsa.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/prsa.c | |
@@ -0,0 +1,699 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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} | |
+}; | |
+ | |
+static const SEC_ASN1Template pem_AttributeTemplate[] = { | |
+ { SEC_ASN1_SEQUENCE, | |
+ 0, NULL, sizeof(NSSLOWKEYAttribute) }, | |
+ { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, | |
+ { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(NSSLOWKEYAttribute, attrValue), | |
+ SEC_ASN1_SUB(SEC_AnyTemplate) }, | |
+ { 0 } | |
+}; | |
+ | |
+static const SEC_ASN1Template pem_SetOfAttributeTemplate[] = { | |
+ { SEC_ASN1_SET_OF, 0, pem_AttributeTemplate }, | |
+}; | |
+ | |
+const SEC_ASN1Template pem_PrivateKeyInfoTemplate[] = { | |
+ { SEC_ASN1_SEQUENCE, | |
+ 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, | |
+ { SEC_ASN1_INTEGER, | |
+ offsetof(NSSLOWKEYPrivateKeyInfo,version) }, | |
+ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
+ offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), | |
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
+ { SEC_ASN1_OCTET_STRING, | |
+ offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, | |
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, | |
+ offsetof(NSSLOWKEYPrivateKeyInfo, attributes), | |
+ pem_SetOfAttributeTemplate }, | |
+ { 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); | |
+ } | |
+ nss_ZFreeIf(privk); | |
+} | |
+ | |
+/* decode and parse the rawkey into the lpk structure */ | |
+static pemLOWKEYPrivateKey * | |
+pem_getPrivateKey(PLArenaPool *arena, SECItem *rawkey, CK_RV * pError, NSSItem *modulus) | |
+{ | |
+ pemLOWKEYPrivateKey *lpk = NULL; | |
+ SECStatus rv = SECFailure; | |
+ NSSLOWKEYPrivateKeyInfo *pki = NULL; | |
+ SECItem *keysrc = NULL; | |
+ | |
+ /* make sure SECOID is initialized - not sure why we have to do this outside of nss_Init */ | |
+ if (SECSuccess != (rv = SECOID_Init())) { | |
+ *pError = CKR_GENERAL_ERROR; | |
+ return NULL; /* wha???? */ | |
+ } | |
+ | |
+ pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, | |
+ sizeof(NSSLOWKEYPrivateKeyInfo)); | |
+ if(!pki) { | |
+ *pError = CKR_HOST_MEMORY; | |
+ goto done; | |
+ } | |
+ | |
+ /* let's first see if this is a "raw" RSA private key or an RSA private key in PKCS#8 format */ | |
+ rv = SEC_ASN1DecodeItem(arena, pki, pem_PrivateKeyInfoTemplate, rawkey); | |
+ if (rv != SECSuccess) { | |
+ /* not PKCS#8 - assume it's a "raw" RSA private key */ | |
+ keysrc = rawkey; | |
+ } else if (SECOID_GetAlgorithmTag(&pki->algorithm) == SEC_OID_PKCS1_RSA_ENCRYPTION) { | |
+ keysrc = &pki->privateKey; | |
+ } else { /* unsupported */ | |
+ *pError = CKR_FUNCTION_NOT_SUPPORTED; | |
+ goto done; | |
+ } | |
+ | |
+ lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, | |
+ sizeof(pemLOWKEYPrivateKey)); | |
+ if (lpk == NULL) { | |
+ *pError = CKR_HOST_MEMORY; | |
+ goto done; | |
+ } | |
+ | |
+ lpk->arena = arena; | |
+ lpk->keyType = pemLOWKEYRSAKey; | |
+ prepare_low_rsa_priv_key_for_asn1(lpk); | |
+ | |
+ /* I don't know what this is supposed to accomplish. We free the old | |
+ modulus data and set it again, making a copy of the new data. | |
+ But we just allocated a new empty key structure above with | |
+ nss_ZAlloc. So lpk->u.rsa.modulus.data is NULL and | |
+ lpk->u.rsa.modulus.len. If the intention is to free the old | |
+ modulus data, why not just set it to NULL after freeing? Why | |
+ go through this unnecessary and confusing copying code? | |
+ */ | |
+ if (modulus) { | |
+ nss_ZFreeIf(modulus->data); | |
+ modulus->data = (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); | |
+ modulus->size = lpk->u.rsa.modulus.len; | |
+ nsslibc_memcpy(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, | |
+ keysrc); | |
+ | |
+ if (rv != SECSuccess) { | |
+ goto done; | |
+ } | |
+ | |
+done: | |
+ return lpk; | |
+} | |
+ | |
+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; | |
+ CK_RV pError = 0; | |
+ | |
+ /* 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; | |
+ } | |
+ | |
+ arena = PORT_NewArena(2048); | |
+ if (!arena) { | |
+ return; | |
+ } | |
+ | |
+ lpk = pem_getPrivateKey(arena, io->u.key.key.privateKey, &pError, NULL); | |
+ if (lpk == NULL) { | |
+ PORT_FreeArena(arena, PR_FALSE); | |
+ return; | |
+ } | |
+ | |
+ nss_ZFreeIf(io->u.key.key.modulus.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.exponent.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.privateExponent.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.prime1.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.prime2.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.exponent1.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.exponent2.data); | |
+ 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); | |
+ | |
+ nss_ZFreeIf(io->u.key.key.coefficient.data); | |
+ 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; | |
+ | |
+ /* 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; | |
+ } | |
+ | |
+ arena = PORT_NewArena(2048); | |
+ if (!arena) { | |
+ *pError = CKR_HOST_MEMORY; | |
+ return (NSSCKMDCryptoOperation *) NULL; | |
+ } | |
+ | |
+ lpk = pem_getPrivateKey(arena, iKey->u.key.key.privateKey, pError, &iKey->u.key.key.modulus); | |
+ if (lpk == NULL) { | |
+ PORT_FreeArena(arena, PR_FALSE); | |
+ 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 void | |
+pem_mdCryptoOperationRSAPriv_Destroy | |
+( | |
+ NSSCKMDCryptoOperation * mdOperation, | |
+ NSSCKFWCryptoOperation * fwOperation, | |
+ NSSCKMDInstance * mdInstance, | |
+ NSSCKFWInstance * fwInstance | |
+) | |
+{ | |
+ pemInternalCryptoOperationRSAPriv *iOperation = | |
+ (pemInternalCryptoOperationRSAPriv *) mdOperation->etc; | |
+ | |
+ if (iOperation->buffer) { | |
+ nssItem_Destroy(iOperation->buffer); | |
+ iOperation->buffer = NULL; | |
+ } | |
+ pem_DestroyPrivateKey(iOperation->lpk); | |
+ iOperation->lpk = NULL; | |
+ nss_ZFreeIf(iOperation); | |
+} | |
+ | |
+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); | |
+ | |
+ if (NULL == modulus) { | |
+ *pError = CKR_FUNCTION_FAILED; | |
+ return 0; | |
+ } | |
+ | |
+ 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 */ | |
+}; | |
--- nss-3.15.4/nss/lib/ckfw/pem/psession.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/psession.c | |
@@ -0,0 +1,388 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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; | |
+ unsigned 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++; | |
+ } | |
+ MD5_DestroyContext(Md5Ctx, PR_TRUE); | |
+ | |
+ 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); | |
+} | |
+ | |
+/* | |
+ * increase refCount of internal object(s) | |
+ */ | |
+NSSCKMDObject * | |
+pem_mdSession_CopyObject | |
+( | |
+ NSSCKMDSession * mdSession, | |
+ NSSCKFWSession * fwSession, | |
+ NSSCKMDToken * mdToken, | |
+ NSSCKFWToken * fwToken, | |
+ NSSCKMDInstance * mdInstance, | |
+ NSSCKFWInstance * fwInstance, | |
+ NSSCKMDObject * mdOldObject, | |
+ NSSCKFWObject * fwOldObject, | |
+ NSSArena * arena, | |
+ CK_ATTRIBUTE_PTR pTemplate, | |
+ CK_ULONG ulAttributeCount, | |
+ CK_RV * pError | |
+) | |
+{ | |
+ NSSCKMDObject *rvmdObject = NULL; | |
+ pemInternalObject *io = (pemInternalObject *) mdOldObject->etc; | |
+ | |
+ /* make a new mdObject */ | |
+ rvmdObject = nss_ZNEW(arena, NSSCKMDObject); | |
+ if ((NSSCKMDObject *) NULL == rvmdObject) { | |
+ *pError = CKR_HOST_MEMORY; | |
+ return (NSSCKMDObject *) NULL; | |
+ } | |
+ | |
+ if (NULL == io->list) { | |
+ io->refCount ++; | |
+ } else { | |
+ /* go through list of objects */ | |
+ pemObjectListItem *item = io->list; | |
+ while (item) { | |
+ item->io->refCount ++; | |
+ item = item->next; | |
+ } | |
+ } | |
+ /* struct (shallow) copy the old one */ | |
+ *rvmdObject = *mdOldObject; | |
+ | |
+ return rvmdObject; | |
+} | |
+ | |
+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 = NULL; | |
+ unsigned char *iv = 0; | |
+ unsigned char mykey[32]; | |
+ unsigned char *output = NULL; | |
+ DESContext *cx = NULL; | |
+ SECStatus rv; | |
+ unsigned int len = 0; | |
+ NSSLOWKEYPrivateKey *lpk = NULL; | |
+ PLArenaPool *arena; | |
+ SECItem plain; | |
+ int i; | |
+ | |
+ fwSlot = NSSCKFWToken_GetFWSlot(fwToken); | |
+ slotID = nssCKFWSlot_GetSlotID(fwSlot); | |
+ | |
+ arena = PORT_NewArena(2048); | |
+ if (!arena) { | |
+ return CKR_HOST_MEMORY; | |
+ } | |
+ | |
+ 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 (NULL == gobj[i]) | |
+ continue; | |
+ | |
+ if ((slotID == gobj[i]->slotID) && (gobj[i]->type == pemBareKey)) { | |
+ io = gobj[i]; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (NULL == io) { | |
+ rv = CKR_SLOT_ID_INVALID; | |
+ goto loser; | |
+ } | |
+ | |
+ /* 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, pin->size, mykey); | |
+ | |
+ output = | |
+ (unsigned char *) nss_ZAlloc(NULL, | |
+ (io->u.key.key.privateKey->len + 1)); | |
+ if (!output) { | |
+ rv = CKR_HOST_MEMORY; | |
+ goto loser; | |
+ } | |
+ | |
+ cx = DES_CreateContext((const unsigned char *) mykey, iv, | |
+ io->u.key.cipher, PR_FALSE); | |
+ if (!cx) { | |
+ rv = CKR_HOST_MEMORY; | |
+ goto loser; | |
+ } | |
+ | |
+ 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) { | |
+ rv = CKR_PIN_INCORRECT; | |
+ goto loser; | |
+ } | |
+ | |
+ lpk = (NSSLOWKEYPrivateKey *) nss_ZAlloc(NULL, | |
+ sizeof (NSSLOWKEYPrivateKey)); | |
+ if (lpk == NULL) { | |
+ rv = CKR_HOST_MEMORY; | |
+ goto loser; | |
+ } | |
+ | |
+ lpk->arena = arena; | |
+ lpk->keyType = NSSLOWKEYRSAKey; | |
+ prepare_low_rsa_priv_key_for_asn1(lpk); | |
+ | |
+ | |
+ /* 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. | |
+ */ | |
+ memset(&plain, 0, sizeof(plain)); | |
+ plain.data = output; | |
+ plain.len = len - output[len - 1]; | |
+ rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, | |
+ &plain); | |
+ pem_DestroyPrivateKey(lpk); | |
+ arena = NULL; | |
+ if (rv != SECSuccess) | |
+ goto loser; | |
+ | |
+ 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]); | |
+ | |
+ rv = CKR_OK; | |
+ | |
+ loser: | |
+ if (arena) | |
+ PORT_FreeArena(arena, PR_FALSE); | |
+ if (iv) | |
+ free(iv); | |
+ nss_ZFreeIf(output); | |
+ | |
+ return rv; | |
+} | |
+ | |
+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; | |
+} | |
--- nss-3.15.4/nss/lib/ckfw/pem/pslot.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/pslot.c | |
@@ -0,0 +1,182 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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; | |
+ | |
+ 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; | |
+ } | |
+ | |
+ mdSlot->etc = pem_NewToken(fwInstance, pError); | |
+ | |
+ 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 */ | |
+}; | |
--- nss-3.15.4/nss/lib/ckfw/pem/ptoken.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/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 ([email protected]) | |
+ * | |
+ * 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 | |
--- nss-3.15.4/nss/lib/ckfw/pem/rsawrapr.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/rsawrapr.c | |
@@ -0,0 +1,823 @@ | |
+/* | |
+ * 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 ([email protected]) | |
+ * | |
+ * 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. */ | |
+ | |
+/* | |
+ * RSA block types | |
+ * | |
+ * The actual values are important -- they are fixed, *not* arbitrary. | |
+ * The explicit value assignments are not needed (because C would give | |
+ * us those same values anyway) but are included as a reminder... | |
+ */ | |
+typedef enum { | |
+ RSA_BlockUnused = 0, /* unused */ | |
+ RSA_BlockPrivate = 1, /* pad for a private-key operation */ | |
+ RSA_BlockPublic = 2, /* pad for a public-key operation */ | |
+ RSA_BlockRaw = 4, /* simply justify the block appropriately */ | |
+ RSA_BlockTotal | |
+} RSA_BlockType; | |
+ | |
+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_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, 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; | |
+ | |
+ 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_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_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 | |
--- nss-3.15.4/nss/lib/ckfw/pem/util.c | |
+++ nss-3.15.4/nss/lib/ckfw/pem/util.c | |
@@ -0,0 +1,312 @@ | |
+/* ***** 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 ([email protected]) | |
+ * | |
+ * 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 "prlog.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 "ckpem.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: | |
+ return (NULL); | |
+} | |
+ | |
+static SECStatus FileToItem(SECItem * dst, PRFileDesc * src) | |
+{ | |
+ PRFileInfo info; | |
+ PRInt32 numBytes; | |
+ PRStatus prStatus; | |
+ | |
+ prStatus = PR_GetOpenFileInfo(src, &info); | |
+ | |
+ if (prStatus != PR_SUCCESS || info.type == PR_FILE_DIRECTORY) { | |
+ 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: | |
+ nss_ZFreeIf(dst->data); | |
+ 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 = NULL; | |
+ 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); | |
+ if (rv != SECSuccess) { | |
+ PR_Close(inFile); | |
+ return -1; | |
+ } | |
+ asc = (char *) filedata.data; | |
+ if (!asc) { | |
+ PR_Close(inFile); | |
+ return -1; | |
+ } | |
+ | |
+ /* check for headers and trailers and remove them */ | |
+ if (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) || | |
+ (strncmp(body, "-----BEGIN PRIVATE KEY", 21) == 0)) { | |
+ key = 1; | |
+ c = body; | |
+ body = strchr(body, '\n'); | |
+ if (NULL == body) | |
+ goto loser; | |
+ body++; | |
+ if (strncmp(body, "Proc-Type: 4,ENCRYPTED", 22) == 0) { | |
+ body = strchr(body, '\n'); | |
+ if (NULL == body) | |
+ goto loser; | |
+ 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)); | |
+ if (der == NULL) | |
+ goto loser; | |
+ | |
+ 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 { | |
+ free(der); | |
+ goto loser; | |
+ } | |
+ | |
+ /* Convert to binary */ | |
+ rv = ATOB_ConvertAsciiToItem(der, body); | |
+ if (rv) { | |
+ free(der); | |
+ goto loser; | |
+ } | |
+ if ((certsonly && !key) || (!certsonly && key)) { | |
+ PUT_Object(der, error); | |
+ } else { | |
+ free(der->data); | |
+ free(der); | |
+ } | |
+ } /* while */ | |
+ } else { /* No headers and footers, translate the blob */ | |
+ der = (SECItem *) malloc(sizeof(SECItem)); | |
+ if (der == NULL) | |
+ goto loser; | |
+ | |
+ rv = ATOB_ConvertAsciiToItem(der, asc); | |
+ if (rv) { | |
+ free(der); | |
+ goto loser; | |
+ } | |
+ | |
+ /* NOTE: This code path has never been tested. */ | |
+ PUT_Object(der, error); | |
+ } | |
+ | |
+ nss_ZFreeIf(filedata.data); | |
+ filedata.data = 0; | |
+ filedata.len = 0; | |
+ } else { | |
+ /* Read in binary der */ | |
+ rv = FileToItem(der, inFile); | |
+ if (rv != SECSuccess) { | |
+ PR_Close(inFile); | |
+ return -1; | |
+ } | |
+ } | |
+ PR_Close(inFile); | |
+ return count; | |
+ | |
+ loser: | |
+ if (filedata.len > 0) | |
+ nss_ZFreeIf(filedata.data); | |
+ PR_Close(inFile); | |
+ return -1; | |
+} | |
+ | |
+#ifdef DEBUG | |
+#define LOGGING_BUFFER_SIZE 400 | |
+#define PEM_DEFAULT_LOG_FILE "/tmp/pkcs11.log" | |
+static const char *pemLogModuleName = "PEM"; | |
+static PRLogModuleInfo* pemLogModule; | |
+#endif | |
+ | |
+void open_log() | |
+{ | |
+#ifdef DEBUG | |
+ const char *nsprLogFile = PR_GetEnv("NSPR_LOG_FILE"); | |
+ | |
+ pemLogModule = PR_NewLogModule(pemLogModuleName); | |
+ | |
+ (void) PR_SetLogFile(nsprLogFile ? nsprLogFile : PEM_DEFAULT_LOG_FILE); | |
+ /* If false, the log file will remain what it was before */ | |
+#endif | |
+} | |
+ | |
+void plog(const char *fmt, ...) | |
+{ | |
+#ifdef DEBUG | |
+ char buf[LOGGING_BUFFER_SIZE]; | |
+ va_list ap; | |
+ | |
+ va_start(ap, fmt); | |
+ PR_vsnprintf(buf, sizeof(buf), fmt, ap); | |
+ va_end(ap); | |
+ PR_LOG(pemLogModule, PR_LOG_DEBUG, ("%s", buf)); | |
+#endif | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment