summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndras Timar <andras.timar@collabora.com>2017-03-26 18:31:29 +0200
committerAndras Timar <andras.timar@collabora.com>2017-03-26 18:31:29 +0200
commitd6877736acfbd44417d79e8587739dfc92bf8123 (patch)
tree235fbc6127472cc5b0e216ced71b093612a74b9e
parentcf3b07e4c160c056683aaf528253a9bcad95005e (diff)
Revert "nss: remove nss-pem.patch"
-rw-r--r--external/nss/ExternalPackage_nss.mk18
-rw-r--r--external/nss/ExternalProject_nss.mk1
-rw-r--r--external/nss/UnpackedTarball_nss.mk7
-rw-r--r--external/nss/nss-pem.patch6376
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
++}