diff options
author | Andras Timar <andras.timar@collabora.com> | 2017-03-26 18:31:29 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2017-03-26 18:31:29 +0200 |
commit | d6877736acfbd44417d79e8587739dfc92bf8123 (patch) | |
tree | 235fbc6127472cc5b0e216ced71b093612a74b9e /external | |
parent | cf3b07e4c160c056683aaf528253a9bcad95005e (diff) |
Revert "nss: remove nss-pem.patch"
This reverts commit 2a9e6ecc61b232be08d8b1687874289ca0fe8d43.
Diffstat (limited to 'external')
-rw-r--r-- | external/nss/ExternalPackage_nss.mk | 18 | ||||
-rw-r--r-- | external/nss/ExternalProject_nss.mk | 1 | ||||
-rw-r--r-- | external/nss/UnpackedTarball_nss.mk | 7 | ||||
-rw-r--r-- | external/nss/nss-pem.patch | 6376 |
4 files changed, 6402 insertions, 0 deletions
diff --git a/external/nss/ExternalPackage_nss.mk b/external/nss/ExternalPackage_nss.mk index 6d568b7edfee..a7c1994e787a 100644 --- a/external/nss/ExternalPackage_nss.mk +++ b/external/nss/ExternalPackage_nss.mk @@ -64,4 +64,22 @@ $(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\ )) endif +ifeq ($(SYSTEM_CURL),) +ifeq ($(OS),IOS) +# nothing +else ifeq ($(OS),MACOSX) +$(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\ + dist/out/lib/libnsspem.dylib \ +)) +else ifeq ($(OS),WNT) +$(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\ + dist/out/lib/nsspem.dll \ +)) +else # OS!=WNT/MACOSX +$(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\ + dist/out/lib/libnsspem.so \ +)) +endif +endif + # vim: set noet sw=4 ts=4: diff --git a/external/nss/ExternalProject_nss.mk b/external/nss/ExternalProject_nss.mk index 07cc472b9fb2..03fd1f1ce135 100644 --- a/external/nss/ExternalProject_nss.mk +++ b/external/nss/ExternalProject_nss.mk @@ -89,6 +89,7 @@ $(call gb_ExternalProject_get_state_target,nss,build): $(call gb_ExternalProject $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libnss3.dylib \ $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libnssckbi.dylib \ $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libnssdbm3.dylib \ + $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libnsspem.dylib \ $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libnssutil3.dylib \ $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libplc4.dylib \ $(gb_Package_SOURCEDIR_nss)/dist/out/lib/libplds4.dylib \ diff --git a/external/nss/UnpackedTarball_nss.mk b/external/nss/UnpackedTarball_nss.mk index a0ac57173fd1..73a63da68416 100644 --- a/external/nss/UnpackedTarball_nss.mk +++ b/external/nss/UnpackedTarball_nss.mk @@ -40,6 +40,13 @@ $(eval $(call gb_UnpackedTarball_add_patches,nss,\ external/nss/nss.utf8bom.patch.1) \ )) +# nss-pem is only needed for internal curl to read the NSS CA database +ifeq ($(SYSTEM_CURL),) +$(eval $(call gb_UnpackedTarball_add_patches,nss,\ + external/nss/nss-pem.patch \ +)) +endif + ifeq ($(COM_IS_CLANG),TRUE) ifneq ($(filter -fsanitize=%,$(CC)),) $(eval $(call gb_UnpackedTarball_add_patches,nss,\ diff --git a/external/nss/nss-pem.patch b/external/nss/nss-pem.patch new file mode 100644 index 000000000000..d41809d3ecaf --- /dev/null +++ b/external/nss/nss-pem.patch @@ -0,0 +1,6376 @@ +diff --git a/a/nss/lib/ckfw/manifest.mn b/b/nss/lib/ckfw/manifest.mn +index 20bebeb..4f10563 100644 +--- a/a/nss/lib/ckfw/manifest.mn ++++ b/b/nss/lib/ckfw/manifest.mn +@@ -5,7 +5,7 @@ + + CORE_DEPTH = ../.. + +-DIRS = builtins ++DIRS = builtins pem + + PRIVATE_EXPORTS = \ + ck.h \ +diff --git a/a/nss/lib/ckfw/pem/Makefile b/b/nss/lib/ckfw/pem/Makefile +new file mode 100644 +index 0000000..aec3bbd +--- /dev/null ++++ b/b/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 ++ ++ +diff --git a/a/nss/lib/ckfw/pem/anchor.c b/b/nss/lib/ckfw/pem/anchor.c +new file mode 100644 +index 0000000..621f919 +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++/* ++ * anchor.c ++ * ++ * This file "anchors" the actual cryptoki entry points in this module's ++ * shared library, which is required for dynamic loading. See the ++ * comments in nssck.api for more information. ++ */ ++ ++#include "ckpem.h" ++ ++#define MODULE_NAME pem ++#define INSTANCE_NAME (NSSCKMDInstance *)&pem_mdInstance ++#include "nssck.api" +diff --git a/a/nss/lib/ckfw/pem/ckpem.h b/b/nss/lib/ckfw/pem/ckpem.h +new file mode 100644 +index 0000000..9712ccd +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/ckpem.h +@@ -0,0 +1,263 @@ ++#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; ++ SECItem *privateKeyOrig; /* deep copy of privateKey until decrypted */ ++ 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; ++ ++/* 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, PRBool *pAdded); ++ ++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 */ +diff --git a/a/nss/lib/ckfw/pem/ckpemver.c b/b/nss/lib/ckfw/pem/ckpemver.c +new file mode 100644 +index 0000000..76ab5df +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++/* Library identity and versioning */ ++ ++#include "nsspem.h" ++ ++#if defined(DEBUG) ++#define _DEBUG_STRING " (debug)" ++#else ++#define _DEBUG_STRING "" ++#endif ++ ++/* ++ * Version information for the 'ident' and 'what commands ++ * ++ * NOTE: the first component of the concatenated rcsid string ++ * must not end in a '$' to prevent rcs keyword substitution. ++ */ ++const char __nss_ckpem_rcsid[] = "$Header: NSS Access to Flat Files in PEM format" ++ NSS_CKPEM_LIBRARY_VERSION _DEBUG_STRING ++ " " __DATE__ " " __TIME__ " $"; ++const char __nss_ckcapi_sccsid[] = "@(#)NSS Access to Flag Files in PEM format " ++ NSS_CKPEM_LIBRARY_VERSION _DEBUG_STRING ++ " " __DATE__ " " __TIME__; +diff --git a/a/nss/lib/ckfw/pem/config.mk b/b/nss/lib/ckfw/pem/config.mk +new file mode 100644 +index 0000000..ff6cd9a +--- /dev/null ++++ b/b/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 specified 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 ++ +diff --git a/a/nss/lib/ckfw/pem/constants.c b/b/nss/lib/ckfw/pem/constants.c +new file mode 100644 +index 0000000..0ceb443 +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++/* ++ * constants.c ++ * ++ * Identification and other constants, all collected here in one place. ++ */ ++ ++#ifndef NSSBASET_H ++#include "nssbaset.h" ++#endif /* NSSBASET_H */ ++ ++#ifndef NSSCKT_H ++#include "nssckt.h" ++#endif /* NSSCKT_H */ ++ ++#ifndef NSSCKBI_H ++#include "../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"; +diff --git a/a/nss/lib/ckfw/pem/manifest.mn b/b/nss/lib/ckfw/pem/manifest.mn +new file mode 100644 +index 0000000..8de27d1 +--- /dev/null ++++ b/b/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 +diff --git a/a/nss/lib/ckfw/pem/nsspem.def b/b/nss/lib/ckfw/pem/nsspem.def +new file mode 100644 +index 0000000..4978252 +--- /dev/null ++++ b/b/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: ++;+*; ++;+}; +diff --git a/a/nss/lib/ckfw/pem/nsspem.h b/b/nss/lib/ckfw/pem/nsspem.h +new file mode 100644 +index 0000000..1547bf4 +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#ifndef NSSPEM_H ++#define NSSPEM_H ++ ++/* ++ * NSS CKPEM Version numbers. ++ * ++ * These are the version numbers for the capi module packaged with ++ * this release on NSS. To determine the version numbers of the builtin ++ * module you are using, use the appropriate PKCS #11 calls. ++ * ++ * These version numbers detail changes to the PKCS #11 interface. They map ++ * to the PKCS #11 spec versions. ++ */ ++#define NSS_CKPEM_CRYPTOKI_VERSION_MAJOR 2 ++#define NSS_CKPEM_CRYPTOKI_VERSION_MINOR 20 ++ ++/* These version numbers detail the changes ++ * to the list of trusted certificates. ++ * ++ * NSS_CKPEM_LIBRARY_VERSION_MINOR is a CK_BYTE. It's not clear ++ * whether we may use its full range (0-255) or only 0-99 because ++ * of the comment in the CK_VERSION type definition. ++ */ ++#define NSS_CKPEM_LIBRARY_VERSION_MAJOR 1 ++#define NSS_CKPEM_LIBRARY_VERSION_MINOR 1 ++#define NSS_CKPEM_LIBRARY_VERSION "1.1" ++ ++/* These version numbers detail the semantic changes to the ckfw engine. */ ++#define NSS_CKPEM_HARDWARE_VERSION_MAJOR 1 ++#define NSS_CKPEM_HARDWARE_VERSION_MINOR 0 ++ ++/* These version numbers detail the semantic changes to ckbi itself ++ * (new PKCS #11 objects), etc. */ ++#define NSS_CKPEM_FIRMWARE_VERSION_MAJOR 1 ++#define NSS_CKPEM_FIRMWARE_VERSION_MINOR 0 ++ ++#endif /* NSSCKBI_H */ +diff --git a/a/nss/lib/ckfw/pem/nsspem.rc b/b/nss/lib/ckfw/pem/nsspem.rc +new file mode 100644 +index 0000000..eb208d6 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/nsspem.rc +@@ -0,0 +1,64 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "nsspem.h" ++#include <winver.h> ++ ++#define MY_LIBNAME "nsspem" ++#define MY_FILEDESCRIPTION "NSS PEM support" ++ ++#ifdef _DEBUG ++#define MY_DEBUG_STR " (debug)" ++#define MY_FILEFLAGS_1 VS_FF_DEBUG ++#else ++#define MY_DEBUG_STR "" ++#define MY_FILEFLAGS_1 0x0L ++#endif ++#if NSS_BETA ++#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE ++#else ++#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 ++#endif ++ ++#ifdef WINNT ++#define MY_FILEOS VOS_NT_WINDOWS32 ++#else ++#define MY_FILEOS VOS__WINDOWS32 ++#endif ++ ++#define MY_INTERNAL_NAME MY_LIBNAME ++ ++///////////////////////////////////////////////////////////////////////////// ++// ++// Version-information resource ++// ++ ++VS_VERSION_INFO VERSIONINFO ++ FILEVERSION NSS_CKPEM_LIBRARY_VERSION_MAJOR,NSS_CKPEM_LIBRARY_VERSION_MINOR,0,0 ++ PRODUCTVERSION NSS_CKPEM_LIBRARY_VERSION_MAJOR,NSS_CKPEM_LIBRARY_VERSION_MINOR,0,0 ++ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK ++ FILEFLAGS MY_FILEFLAGS_2 ++ FILEOS MY_FILEOS ++ FILETYPE VFT_DLL ++ FILESUBTYPE 0x0L // not used ++ ++BEGIN ++ BLOCK "StringFileInfo" ++ BEGIN ++ BLOCK "040904B0" // Lang=US English, CharSet=Unicode ++ BEGIN ++ VALUE "CompanyName", "Mozilla Foundation\0" ++ VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" ++ VALUE "FileVersion", NSS_CKPEM_LIBRARY_VERSION "\0" ++ VALUE "InternalName", MY_INTERNAL_NAME "\0" ++ VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" ++ VALUE "ProductName", "Network Security Services\0" ++ VALUE "ProductVersion", NSS_CKPEM_LIBRARY_VERSION "\0" ++ END ++ END ++ BLOCK "VarFileInfo" ++ BEGIN ++ VALUE "Translation", 0x409, 1200 ++ END ++END +diff --git a/a/nss/lib/ckfw/pem/pargs.c b/b/nss/lib/ckfw/pem/pargs.c +new file mode 100644 +index 0000000..21291a8 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/pargs.c +@@ -0,0 +1,164 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include <string.h> ++#include <nspr.h> ++ ++void *pem_Malloc(const PRInt32 sz) ++{ ++ return PR_Malloc(sz); ++} ++ ++char *pem_StrNdup(const char *instr, PRInt32 inlen) ++{ ++ size_t len = inlen; ++ char *buffer; ++ if (!instr) { ++ return NULL; ++ } ++ ++ if (!len) { ++ return NULL; ++ } ++ 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) ++{ ++ size_t len; ++ if (!instr) { ++ return NULL; ++ } ++ ++ 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) ++{ ++ char nextchar; ++ char *instring = (char *) inputstring; ++ 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; ++ } ++ *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) ++{ ++ PRInt32 counter; ++ if (!numStrings || !instrings) { ++ return PR_FALSE; ++ } ++ for (counter = 0; counter < numStrings; counter++) { ++ char *astring = instrings[counter]; ++ if (astring) { ++ pem_Free(astring); ++ } ++ } ++ PR_Free((void *) instrings); ++ return PR_TRUE; ++} +diff --git a/a/nss/lib/ckfw/pem/pfind.c b/b/nss/lib/ckfw/pem/pfind.c +new file mode 100644 +index 0000000..30b1174 +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++ ++/* ++ * pfind.c ++ * ++ * This file implements the NSSCKMDFindObjects object for the ++ * "PEM objects" cryptoki module. ++ */ ++ ++NSS_EXTERN_DATA pemInternalObject **gobj; ++NSS_EXTERN_DATA int pem_nobjs; ++ ++struct pemFOStr { ++ NSSArena *arena; ++ CK_ULONG n; ++ CK_ULONG i; ++ pemInternalObject **objs; ++}; ++ ++#define PEM_ITEM_CHUNK 512 ++ ++#define PUT_Object(obj,err) \ ++ { \ ++ if (count >= size) { \ ++ *listp = *listp ? \ ++ nss_ZREALLOCARRAY(*listp, pemInternalObject *, \ ++ (size+PEM_ITEM_CHUNK) ) : \ ++ nss_ZNEWARRAY(NULL, pemInternalObject *, \ ++ (size+PEM_ITEM_CHUNK) ) ; \ ++ if ((pemInternalObject **)NULL == *listp) { \ ++ err = CKR_HOST_MEMORY; \ ++ goto loser; \ ++ } \ ++ size += PEM_ITEM_CHUNK; \ ++ } \ ++ (*listp)[ count ] = (obj); \ ++ count++; \ ++ } ++ ++static void ++pem_mdFindObjects_Final ++( ++ NSSCKMDFindObjects * mdFindObjects, ++ NSSCKFWFindObjects * fwFindObjects, ++ NSSCKMDSession * mdSession, ++ NSSCKFWSession * fwSession, ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ struct pemFOStr *fo = (struct pemFOStr *) mdFindObjects->etc; ++ NSSArena *arena = fo->arena; ++ ++ nss_ZFreeIf(fo->objs); ++ nss_ZFreeIf(fo); ++ nss_ZFreeIf(mdFindObjects); ++ if ((NSSArena *) NULL != arena) { ++ NSSArena_Destroy(arena); ++ } ++ ++ return; ++} ++ ++static NSSCKMDObject * ++pem_mdFindObjects_Next ++( ++ NSSCKMDFindObjects * mdFindObjects, ++ NSSCKFWFindObjects * fwFindObjects, ++ NSSCKMDSession * mdSession, ++ NSSCKFWSession * fwSession, ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ NSSArena * arena, ++ CK_RV * pError ++) ++{ ++ struct pemFOStr *fo = (struct pemFOStr *) mdFindObjects->etc; ++ pemInternalObject *io; ++ ++ plog("pem_FindObjects_Next: "); ++ ++ if (fo->i == fo->n) { ++ plog("Done creating objects\n"); ++ *pError = CKR_OK; ++ return (NSSCKMDObject *) NULL; ++ } ++ ++ io = fo->objs[fo->i]; ++ fo->i++; ++ ++ plog("Creating object for type %d\n", io->type); ++ ++ 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; ++} +diff --git a/a/nss/lib/ckfw/pem/pinst.c b/b/nss/lib/ckfw/pem/pinst.c +new file mode 100644 +index 0000000..9c98e89 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/pinst.c +@@ -0,0 +1,768 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++#include <stdlib.h> ++#include "ckpem.h" ++#include "blapi.h" ++#include "prprf.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; ++ } ++ ++ /* store deep copy of original key DER so we can compare it later on */ ++ o->u.key.key.privateKeyOrig = SECITEM_DupItem(keyDER); ++ if (o->u.key.key.privateKeyOrig == NULL) { ++ nss_ZFreeIf(o->u.key.key.privateKey->data); ++ 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.privateKeyOrig, 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; ++ 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, PRBool *pAdded) ++{ ++ int i; ++ pemInternalObject *io; ++ ++ /* FIXME: copy-pasted from CreateObject */ ++ const char *nickname = strrchr(filename, '/'); ++ if (nickname && CKO_PRIVATE_KEY != objClass) ++ nickname++; ++ else ++ nickname = filename; ++ ++ if (pAdded) ++ *pAdded = PR_FALSE; ++ ++ /* 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 */ ++ 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++; ++ ++ if (pAdded) ++ *pAdded = PR_TRUE; ++ ++ 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; ++ ++ PR_snprintf(nickname, 1024, "%s - %d", certfile, i); ++ ++ o = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, objs[i], NULL, ++ nickname, 0, slotID, NULL); ++ 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, NULL); ++ 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, NULL); ++ 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, NULL); ++ 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 */ ++}; +diff --git a/a/nss/lib/ckfw/pem/pobject.c b/b/nss/lib/ckfw/pem/pobject.c +new file mode 100644 +index 0000000..a13e531 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/pobject.c +@@ -0,0 +1,1240 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++#include "secasn1.h" ++#include "certt.h" ++#include "prprf.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: ++ SECITEM_FreeItem(io->u.key.key.privateKeyOrig, PR_TRUE); ++ 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; ++ ++ PR_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, NULL); ++ 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, NULL); ++ if (listItem->io == NULL) ++ goto loser; ++ } ++ } else { ++ listItem->io = AddObjectIfNeeded(CKO_CERTIFICATE, pemCert, ++ derlist[0], NULL, filename, objid, ++ slotID, NULL); ++ 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; ++ PRBool added; ++ ++ 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, ++ &added); ++ 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 && added) { ++ /* 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); ++} +diff --git a/a/nss/lib/ckfw/pem/prsa.c b/b/nss/lib/ckfw/pem/prsa.c +new file mode 100644 +index 0000000..d42e9f7 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/prsa.c +@@ -0,0 +1,702 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++#include "secdert.h" ++#include "secoid.h" ++#include "nssckmdt.h" ++ ++#define SSL3_SHAMD5_HASH_SIZE 36 /* LEN_MD5 (16) + LEN_SHA1 (20) */ ++ ++SEC_ASN1_MKSUB(SEC_AnyTemplate) ++SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) ++ ++/* ++ * 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 */ ++}; +diff --git a/a/nss/lib/ckfw/pem/psession.c b/b/nss/lib/ckfw/pem/psession.c +new file mode 100644 +index 0000000..70c5407 +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++#include "secmodt.h" ++#include "pk11pub.h" ++#include "base64.h" ++#include "blapi.h" ++ ++/* ++ * psession.c ++ * ++ * This file implements the NSSCKMDSession object for the ++ * "PEM objects" cryptoki module. ++ */ ++ ++NSS_EXTERN_DATA pemInternalObject **gobj; ++NSS_EXTERN_DATA int pem_nobjs; ++NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS]; ++NSS_EXTERN_DATA const SEC_ASN1Template pem_RSAPrivateKeyTemplate[]; ++ ++void prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey * key); ++void pem_DestroyPrivateKey(NSSLOWKEYPrivateKey * privk); ++ ++/* ++ * Convert a hex string into bytes. ++ */ ++static unsigned char *convert_iv(char *src, int num) ++{ ++ int i; ++ char conv[3]; ++ unsigned char *c; ++ ++ c = (unsigned char *) malloc((num) + 1); ++ if (c == NULL) ++ return NULL; ++ ++ conv[2] = '\0'; ++ memset(c, 0, num); ++ for (i = 0; i < num; i++) { ++ conv[0] = src[(i * 2)]; ++ conv[1] = src[(i * 2) + 1]; ++ c[i] = strtol(conv, NULL, 16); ++ } ++ return c; ++} ++ ++/* ++ * The key is a 24-bit hash. The first 16 bits are the MD5 hash of the ++ * password and the IV (salt). This has is then re-hashed with the ++ * password and IV again and the first 8 bytes of that are the remaining ++ * bytes of the 24-bit key. ++ */ ++static int ++make_key(const unsigned char *salt, const unsigned char *data, int len, ++ unsigned char *key) ++{ ++ int nkey = 0; ++ MD5Context *Md5Ctx = MD5_NewContext(); ++ unsigned int digestLen; ++ int count, i; ++ 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; ++} +diff --git a/a/nss/lib/ckfw/pem/pslot.c b/b/nss/lib/ckfw/pem/pslot.c +new file mode 100644 +index 0000000..2f9901b +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/pslot.c +@@ -0,0 +1,183 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++#include "prprf.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); ++ PR_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 */ ++}; +diff --git a/a/nss/lib/ckfw/pem/ptoken.c b/b/nss/lib/ckfw/pem/ptoken.c +new file mode 100644 +index 0000000..6c35b21 +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/ptoken.c +@@ -0,0 +1,334 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++#include "ckpem.h" ++#include "prprf.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); ++ PR_snprintf(tokenid, 256, "PEM Token #%ld", slotID); ++ ++ return (NSSUTF8 *) tokenid; ++} ++ ++static NSSUTF8 * ++pem_mdToken_GetManufacturerID ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ CK_RV * pError ++) ++{ ++ return (NSSUTF8 *) pem_ManufacturerID; ++} ++ ++static NSSUTF8 * ++pem_mdToken_GetModel ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ CK_RV * pError ++) ++{ ++ return (NSSUTF8 *) pem_TokenModel; ++} ++ ++static NSSUTF8 * ++pem_mdToken_GetSerialNumber ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ CK_RV * pError ++) ++{ ++ return (NSSUTF8 *) pem_TokenSerialNumber; ++} ++ ++static CK_BBOOL ++pem_mdToken_GetIsWriteProtected ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ return CK_TRUE; ++} ++ ++static CK_VERSION ++pem_mdToken_GetHardwareVersion ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ return pem_HardwareVersion; ++} ++ ++static CK_VERSION ++pem_mdToken_GetFirmwareVersion ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ return pem_FirmwareVersion; ++} ++ ++static NSSCKMDSession *pem_mdToken_OpenSession ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ NSSCKFWSession * fwSession, ++ CK_BBOOL rw, ++ CK_RV * pError ++) ++{ ++ plog("pem_mdToken_OpenSession\n"); ++ return pem_CreateSession(fwSession, pError); ++} ++ ++static CK_ULONG ++pem_mdToken_GetMechanismCount ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ return (CK_ULONG) 1; ++} ++ ++static CK_RV ++pem_mdToken_GetMechanismTypes ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ CK_MECHANISM_TYPE types[] ++) ++{ ++ types[0] = CKM_RSA_PKCS; ++ return CKR_OK; ++} ++ ++static NSSCKMDMechanism * ++pem_mdToken_GetMechanism ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance, ++ CK_MECHANISM_TYPE which, ++ CK_RV * pError ++) ++{ ++ if (which != CKM_RSA_PKCS) { ++ *pError = CKR_MECHANISM_INVALID; ++ return (NSSCKMDMechanism *) NULL; ++ } ++ return (NSSCKMDMechanism *) & pem_mdMechanismRSA; ++} ++ ++static CK_BBOOL ++pem_mdToken_GetUserPinInitialized ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ plog("pem_mdToken_GetUserPinInitialized: always TRUE\n"); ++ return CK_TRUE; ++} ++ ++static CK_BBOOL ++pem_mdToken_GetLoginRequired ++( ++ NSSCKMDToken * mdToken, ++ NSSCKFWToken * fwToken, ++ NSSCKMDInstance * mdInstance, ++ NSSCKFWInstance * fwInstance ++) ++{ ++ char *label; ++ CK_RV pError; ++ NSSCKFWSlot *fwSlot; ++ CK_SLOT_ID slotID; ++ ++ fwSlot = NSSCKFWToken_GetFWSlot(fwToken); ++ slotID = nssCKFWSlot_GetSlotID(fwSlot); ++ ++ label = pem_mdToken_GetLabel(mdToken, fwToken, mdInstance, fwInstance, ++ &pError); ++ ++ plog("pem_mdToken_GetLoginRequired %s: %d\n", label, ++ token_needsLogin[slotID - 1]); ++ ++ if (token_needsLogin[slotID - 1] == PR_TRUE) ++ return CK_TRUE; ++ else ++ return CK_FALSE; ++} ++ ++NSSCKMDToken * ++pem_NewToken ++( ++ NSSCKFWInstance * fwInstance, ++ CK_RV * pError ++) ++{ ++ NSSArena *arena; ++ NSSCKMDToken *mdToken; ++ pemToken *token; ++ ++ arena = NSSCKFWInstance_GetArena(fwInstance, pError); ++ if ((NSSArena *) NULL == arena) { ++ if (CKR_OK == *pError) { ++ *pError = CKR_GENERAL_ERROR; ++ } ++ } ++ ++ mdToken = nss_ZNEW(arena, NSSCKMDToken); ++ if ((NSSCKMDToken *) NULL == mdToken) { ++ *pError = CKR_HOST_MEMORY; ++ return (NSSCKMDToken *) NULL; ++ } ++ ++ token = nss_ZNEW(arena, struct pemTokenStr); ++ if ((struct pemTokenStr *) NULL == token) { ++ *pError = CKR_HOST_MEMORY; ++ return (NSSCKMDToken *) NULL; ++ } ++ ++ mdToken->etc = (void *) token; ++ mdToken->GetLabel = pem_mdToken_GetLabel; ++ mdToken->GetManufacturerID = pem_mdToken_GetManufacturerID; ++ mdToken->GetModel = pem_mdToken_GetModel; ++ mdToken->GetSerialNumber = pem_mdToken_GetSerialNumber; ++ mdToken->GetIsWriteProtected = pem_mdToken_GetIsWriteProtected; ++ mdToken->GetLoginRequired = pem_mdToken_GetLoginRequired; ++ mdToken->GetUserPinInitialized = pem_mdToken_GetUserPinInitialized; ++ mdToken->GetHardwareVersion = pem_mdToken_GetHardwareVersion; ++ mdToken->GetFirmwareVersion = pem_mdToken_GetFirmwareVersion; ++ mdToken->OpenSession = pem_mdToken_OpenSession; ++ mdToken->GetMechanismCount = pem_mdToken_GetMechanismCount; ++ mdToken->GetMechanismTypes = pem_mdToken_GetMechanismTypes; ++ mdToken->GetMechanism = pem_mdToken_GetMechanism; ++ ++ return mdToken; ++} ++ ++#if 0 ++NSS_IMPLEMENT_DATA const NSSCKMDToken pem_mdToken = { ++ (void *) NULL, /* etc */ ++ NULL, /* Setup */ ++ NULL, /* Invalidate */ ++ NULL, /* InitToken -- default errs */ ++ pem_mdToken_GetLabel, ++ pem_mdToken_GetManufacturerID, ++ pem_mdToken_GetModel, ++ pem_mdToken_GetSerialNumber, ++ NULL, /* GetHasRNG -- default is false */ ++ pem_mdToken_GetIsWriteProtected, ++ pem_mdToken_GetLoginRequired, ++ pem_mdToken_GetUserPinInitialized, ++ NULL, /* GetRestoreKeyNotNeeded -- irrelevant */ ++ NULL, /* GetHasClockOnToken -- default is false */ ++ NULL, /* GetHasProtectedAuthenticationPath -- default is false */ ++ NULL, /* GetSupportsDualCryptoOperations -- default is false */ ++ NULL, /* GetMaxSessionCount -- default is CK_UNAVAILABLE_INFORMATION */ ++ NULL, /* GetMaxRwSessionCount -- default is CK_UNAVAILABLE_INFORMATION */ ++ NULL, /* GetMaxPinLen -- irrelevant */ ++ NULL, /* GetMinPinLen -- irrelevant */ ++ NULL, /* GetTotalPublicMemory -- default is CK_UNAVAILABLE_INFORMATION */ ++ NULL, /* GetFreePublicMemory -- default is CK_UNAVAILABLE_INFORMATION */ ++ NULL, /* GetTotalPrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */ ++ NULL, /* GetFreePrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */ ++ pem_mdToken_GetHardwareVersion, ++ pem_mdToken_GetFirmwareVersion, ++ NULL, /* GetUTCTime -- no clock */ ++ pem_mdToken_OpenSession, ++ pem_mdToken_GetMechanismCount, ++ pem_mdToken_GetMechanismTypes, ++ pem_mdToken_GetMechanism, ++ (void *) NULL /* null terminator */ ++}; ++#endif +diff --git a/a/nss/lib/ckfw/pem/rsawrapr.c b/b/nss/lib/ckfw/pem/rsawrapr.c +new file mode 100644 +index 0000000..1179f2a +--- /dev/null ++++ b/b/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 (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++/* $Id: $ */ ++ ++#include "ckpem.h" ++#include "blapi.h" ++#include "softoken.h" ++#include "sechash.h" ++#include "base.h" ++ ++#include "secerr.h" ++ ++#define RSA_BLOCK_MIN_PAD_LEN 8 ++#define RSA_BLOCK_FIRST_OCTET 0x00 ++#define RSA_BLOCK_PRIVATE0_PAD_OCTET 0x00 ++#define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff ++#define RSA_BLOCK_AFTER_PAD_OCTET 0x00 ++ ++#define OAEP_SALT_LEN 8 ++#define OAEP_PAD_LEN 8 ++#define OAEP_PAD_OCTET 0x00 ++ ++#define FLAT_BUFSIZE 512 /* bytes to hold flattened SHA1Context. */ ++ ++unsigned ++pem_PublicModulusLen(NSSLOWKEYPublicKey *pubk) ++{ ++ unsigned char b0; ++ ++ /* interpret modulus length as key strength... in ++ * fortezza that's the public key length */ ++ ++ switch (pubk->keyType) { ++ case pemLOWKEYRSAKey: ++ b0 = pubk->u.rsa.modulus.data[0]; ++ return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static SHA1Context *SHA1_CloneContext(SHA1Context * original) ++{ ++ SHA1Context *clone = NULL; ++ unsigned char *pBuf; ++ int sha1ContextSize = SHA1_FlattenSize(original); ++ SECStatus frv; ++ unsigned char buf[FLAT_BUFSIZE]; ++ ++ PORT_Assert(sizeof buf >= sha1ContextSize); ++ if (sizeof buf >= sha1ContextSize) { ++ pBuf = buf; ++ } else { ++ pBuf = nss_ZAlloc(NULL, sha1ContextSize); ++ if (!pBuf) ++ goto done; ++ } ++ ++ frv = SHA1_Flatten(original, pBuf); ++ if (frv == SECSuccess) { ++ clone = SHA1_Resurrect(pBuf, NULL); ++ memset(pBuf, 0, sha1ContextSize); ++ } ++ done: ++ if (pBuf != buf) ++ nss_ZFreeIf(pBuf); ++ return clone; ++} ++ ++/* ++ * Modify data by XORing it with a special hash of salt. ++ */ ++static SECStatus ++oaep_xor_with_h1(unsigned char *data, unsigned int datalen, ++ unsigned char *salt, unsigned int saltlen) ++{ ++ SHA1Context *sha1cx; ++ unsigned char *dp, *dataend; ++ unsigned char end_octet; ++ ++ sha1cx = SHA1_NewContext(); ++ if (sha1cx == NULL) { ++ return SECFailure; ++ } ++ ++ /* ++ * Get a hash of salt started; we will use it several times, ++ * adding in a different end octet (x00, x01, x02, ...). ++ */ ++ SHA1_Begin(sha1cx); ++ SHA1_Update(sha1cx, salt, saltlen); ++ end_octet = 0; ++ ++ dp = data; ++ dataend = data + datalen; ++ ++ while (dp < dataend) { ++ SHA1Context *sha1cx_h1; ++ unsigned int sha1len, sha1off; ++ unsigned char sha1[SHA1_LENGTH]; ++ ++ /* ++ * Create hash of (salt || end_octet) ++ */ ++ sha1cx_h1 = SHA1_CloneContext(sha1cx); ++ SHA1_Update(sha1cx_h1, &end_octet, 1); ++ SHA1_End(sha1cx_h1, sha1, &sha1len, sizeof(sha1)); ++ SHA1_DestroyContext(sha1cx_h1, PR_TRUE); ++ PORT_Assert(sha1len == SHA1_LENGTH); ++ ++ /* ++ * XOR that hash with the data. ++ * When we have fewer than SHA1_LENGTH octets of data ++ * left to xor, use just the low-order ones of the hash. ++ */ ++ sha1off = 0; ++ if ((dataend - dp) < SHA1_LENGTH) ++ sha1off = SHA1_LENGTH - (dataend - dp); ++ while (sha1off < SHA1_LENGTH) ++ *dp++ ^= sha1[sha1off++]; ++ ++ /* ++ * Bump for next hash chunk. ++ */ ++ end_octet++; ++ } ++ ++ SHA1_DestroyContext(sha1cx, PR_TRUE); ++ return SECSuccess; ++} ++ ++/* ++ * Modify salt by XORing it with a special hash of data. ++ */ ++static SECStatus ++oaep_xor_with_h2(unsigned char *salt, unsigned int saltlen, ++ unsigned char *data, unsigned int datalen) ++{ ++ unsigned char sha1[SHA1_LENGTH]; ++ unsigned char *psalt, *psha1, *saltend; ++ SECStatus rv; ++ ++ /* ++ * Create a hash of data. ++ */ ++ rv = SHA1_HashBuf(sha1, data, datalen); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ ++ /* ++ * XOR the low-order octets of that hash with salt. ++ */ ++ PORT_Assert(saltlen <= SHA1_LENGTH); ++ saltend = salt + saltlen; ++ psalt = salt; ++ psha1 = sha1 + SHA1_LENGTH - saltlen; ++ while (psalt < saltend) { ++ *psalt++ ^= *psha1++; ++ } ++ ++ return SECSuccess; ++} ++ ++/* ++ * 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_BlockPrivate0 = 0, /* unused, really */ ++ 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; ++ ++/* ++ * 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 +diff --git a/a/nss/lib/ckfw/pem/util.c b/b/nss/lib/ckfw/pem/util.c +new file mode 100644 +index 0000000..e5fb4da +--- /dev/null ++++ b/b/nss/lib/ckfw/pem/util.c +@@ -0,0 +1,314 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * The contents of this file are subject to the Mozilla Public License Version ++ * 1.1 (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS IS" basis, ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License ++ * for the specific language governing rights and limitations under the ++ * License. ++ * ++ * The Original Code is the Netscape security libraries. ++ * ++ * The Initial Developer of the Original Code is ++ * Netscape Communications Corporation. ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Rob Crittenden (rcritten@redhat.com) ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++ ++/* cribbed from secutil.c */ ++ ++#include "prtypes.h" ++#include "prtime.h" ++#include "prlong.h" ++#include "prerror.h" ++#include "prlog.h" ++#include "prprf.h" ++#include "plgetopt.h" ++#include "plstr.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)) { ++ char *trailer; ++ 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 (!PL_strcasecmp(c, "DES-EDE3-CBC")) ++ *cipher = NSS_DES_EDE3_CBC; ++ else if (!PL_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; ++ ++ 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 ++} |