[Libreoffice-commits] core.git: external/nss ucb/source

Cédric Bosdonnat cedric.bosdonnat at free.fr
Tue Jul 15 02:22:13 PDT 2014


 external/nss/ExternalPackage_nss.mk       |    3 
 external/nss/UnpackedTarball_nss.mk       |    1 
 external/nss/nss-pem.patch                | 6281 ++++++++++++++++++++++++++++++
 ucb/source/ucp/cmis/cmis_content.cxx      |   14 
 ucb/source/ucp/cmis/cmis_repo_content.cxx |   14 
 5 files changed, 6313 insertions(+)

New commits:
commit 165075e0d705cbd146463c94b027e728db864ab2
Author: Cédric Bosdonnat <cedric.bosdonnat at free.fr>
Date:   Tue Jul 15 10:31:14 2014 +0200

    fdo#72277: Use NSS CACERT in cmis ucp with internal curl
    
    This fix contains two parts:
      * initialize NSS in the CMIS UCP right before sending an HTTP request
        in case internal curl is used. This makes internal curl find the NSS
        CACERT database from the user mozilla profile.
    
      * add nsspem to allow curl to use CACERTs from libnssckbi. Without
        libnsspem curl is unable to read the certificates from the NSS
        database. The nss-pem code has been extracted from the fedora-hosted
        repository: https://git.fedorahosted.org/cgit/nss-pem.git
    
    Change-Id: Ie8dedf020480cca01bf9761382886566a1150778

diff --git a/external/nss/ExternalPackage_nss.mk b/external/nss/ExternalPackage_nss.mk
index e7e9e8a..fcbca81 100644
--- a/external/nss/ExternalPackage_nss.mk
+++ b/external/nss/ExternalPackage_nss.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\
 		dist/out/lib/libnss3.dylib \
 		dist/out/lib/libnssckbi.dylib \
 		dist/out/lib/libnssdbm3.dylib \
+		dist/out/lib/libnsspem.dylib \
 		dist/out/lib/libnssutil3.dylib \
 		dist/out/lib/libplc4.dylib \
 		dist/out/lib/libplds4.dylib \
@@ -33,6 +34,7 @@ $(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\
 		dist/out/lib/nss3.dll \
 		dist/out/lib/nssckbi.dll \
 		dist/out/lib/nssdbm3.dll \
+		dist/out/lib/nsspem.dll \
 		dist/out/lib/nssutil3.dll \
 		dist/out/lib/plc4.dll \
 		dist/out/lib/plds4.dll \
@@ -48,6 +50,7 @@ $(eval $(call gb_ExternalPackage_add_files,nss,$(LIBO_LIB_FOLDER),\
 		dist/out/lib/libnss3.so \
 		dist/out/lib/libnssckbi.so \
 		dist/out/lib/libnssdbm3.so \
+		dist/out/lib/libnsspem.so \
 		dist/out/lib/libnssutil3.so \
 		dist/out/lib/libplc4.so \
 		dist/out/lib/libplds4.so \
diff --git a/external/nss/UnpackedTarball_nss.mk b/external/nss/UnpackedTarball_nss.mk
index be801d7..bafe3b5 100644
--- a/external/nss/UnpackedTarball_nss.mk
+++ b/external/nss/UnpackedTarball_nss.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,nss,\
 	external/nss/nss_macosx.patch \
 	external/nss/nss-linux-x86.patch.0 \
 	external/nss/nss-win32-make.patch.1 \
+	external/nss/nss-pem.patch \
 	$(if $(filter WNTMSC,$(OS)$(COM)),external/nss/nss.windows.patch) \
 	$(if $(filter WNTGCC,$(OS)$(COM)),external/nss/nspr-4.9-build.patch.3 \
 		external/nss/nss-3.13.3-build.patch.3 \
diff --git a/external/nss/nss-pem.patch b/external/nss/nss-pem.patch
new file mode 100644
index 0000000..b65a04f
--- /dev/null
+++ b/external/nss/nss-pem.patch
@@ -0,0 +1,6281 @@
+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 at 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..2a47c75
+--- /dev/null
++++ b/b/nss/lib/ckfw/pem/ckpem.h
+@@ -0,0 +1,265 @@
++#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;
++
++  PRBool          logged_in;
++
++/* our raw object data array */
++NSS_EXTERN_DATA pemInternalObject nss_pem_data[];
++NSS_EXTERN_DATA const PRUint32               nss_pem_nObjects;
++
++NSS_EXTERN_DATA pemInternalObject pem_data[];
++NSS_EXTERN_DATA const PRUint32               pem_nObjects;
++
++NSS_EXTERN_DATA const CK_VERSION   pem_CryptokiVersion;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_ManufacturerID;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_LibraryDescription;
++NSS_EXTERN_DATA const CK_VERSION   pem_LibraryVersion;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_SlotDescription;
++NSS_EXTERN_DATA const CK_VERSION   pem_HardwareVersion;
++NSS_EXTERN_DATA const CK_VERSION   pem_FirmwareVersion;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_TokenLabel;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_TokenModel;
++NSS_EXTERN_DATA const NSSUTF8 *    pem_TokenSerialNumber;
++
++NSS_EXTERN_DATA const NSSCKMDInstance pem_mdInstance;
++NSS_EXTERN_DATA const NSSCKMDSlot     pem_mdSlot;
++NSS_EXTERN_DATA const NSSCKMDToken    pem_mdToken;
++NSS_EXTERN_DATA const NSSCKMDMechanism pem_mdMechanismRSA;
++
++NSS_EXTERN NSSCKMDSession *
++pem_CreateSession
++(
++  NSSCKFWSession *fwSession,
++  CK_RV *pError
++);
++
++NSS_EXTERN NSSCKMDFindObjects *
++pem_FindObjectsInit
++(
++  NSSCKFWSession *fwSession,
++  CK_ATTRIBUTE_PTR pTemplate,
++  CK_ULONG ulAttributeCount,
++  CK_RV *pError
++);
++
++NSS_EXTERN NSSCKMDObject *
++pem_CreateMDObject
++(
++  NSSArena *arena,
++  pemInternalObject *io,
++  CK_RV *pError
++);
++
++#define NSS_PEM_ARRAY_SIZE(x) ((sizeof (x))/(sizeof ((x)[0])))
++
++typedef enum {
++    pemLOWKEYNullKey = 0,
++    pemLOWKEYRSAKey = 1,
++    pemLOWKEYDSAKey = 2,
++    pemLOWKEYDHKey = 4,
++    pemLOWKEYECKey = 5
++} pemLOWKEYType;
++
++/*
++** Low Level private key object
++** This is only used by the raw Crypto engines (crypto), keydb (keydb),
++** and PKCS #11. Everyone else uses the high level key structure.
++*/
++struct pemLOWKEYPrivateKeyStr {
++    PLArenaPool *arena;
++    pemLOWKEYType keyType;
++    union {
++        RSAPrivateKey rsa;
++        DSAPrivateKey dsa;
++        DHPrivateKey  dh;
++        ECPrivateKey  ec;
++    } u;
++};
++typedef struct pemLOWKEYPrivateKeyStr pemLOWKEYPrivateKey;
++
++SECStatus ReadDERFromFile(SECItem ***derlist, char *filename, PRBool ascii, int *cipher, char **ivstring, PRBool certsonly);
++const NSSItem * pem_FetchAttribute ( pemInternalObject *io, CK_ATTRIBUTE_TYPE type);
++void pem_PopulateModulusExponent(pemInternalObject *io);
++NSSCKMDObject * pem_CreateObject(NSSCKFWInstance *fwInstance, NSSCKFWSession *fwSession, NSSCKMDToken *mdToken, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_RV *pError);
++NSSCKMDSlot *pem_NewSlot( NSSCKFWInstance *fwInstance, CK_RV *pError);
++
++
++PRBool pem_ParseString(const char* inputstring, const char delimiter,
++                       PRInt32* numStrings, char*** returnedstrings);
++PRBool pem_FreeParsedStrings(PRInt32 numStrings, char** instrings);
++
++pemInternalObject *
++AddObjectIfNeeded(CK_OBJECT_CLASS objClass, pemObjectType type,
++                  SECItem *certDER, SECItem *keyDER, char *filename, int objid,
++                  CK_SLOT_ID slotID, 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 at 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 specifed as dependencies within rules.mk.
++#
++
++TARGETS        = $(SHARED_LIBRARY)
++LIBRARY        =
++IMPORT_LIBRARY =
++PROGRAM        =
++
++ifeq (,$(filter-out WIN%,$(OS_TARGET)))
++    SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
++    RES = $(OBJDIR)/$(LIBRARY_NAME).res
++    RESNAME = $(LIBRARY_NAME).rc
++endif
++
++ifdef BUILD_IDG
++    DEFINES += -DNSSDEBUG
++endif
++
++#
++# To create a loadable module on Darwin, we must use -bundle.
++#
++ifeq ($(OS_TARGET),Darwin)
++DSO_LDOPTS = -bundle
++endif
++
++ifeq ($(OS_TARGET),SunOS)
++# The -R '$ORIGIN' linker option instructs this library to search for its
++# dependencies in the same directory where it resides.
++MKSHLIB += -R '$$ORIGIN'
++endif
++
+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 at 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 at 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/pargs.c b/b/nss/lib/ckfw/pem/pargs.c
+new file mode 100644
+index 0000000..f292a8b
+--- /dev/null
++++ b/b/nss/lib/ckfw/pem/pargs.c
+@@ -0,0 +1,162 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is the Netscape security libraries.
++ *
++ * The Initial Developer of the Original Code is
++ * Netscape Communications Corporation.
++ * Portions created by the Initial Developer are Copyright (C) 1994-2000
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *   Rob Crittenden (rcritten at redhat.com)
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include <string.h>
++#include <nspr.h>
++
++void *pem_Malloc(const PRInt32 sz)
++{
++    return PR_Malloc(sz);
++}
++
++char *pem_StrNdup(const char *instr, PRInt32 inlen)
++{
++    if (!instr) {
++        return NULL;
++    }
++
++    size_t len = inlen;
++    if (!len) {
++        return NULL;
++    }
++    char *buffer = (char *) pem_Malloc(len + 1);
++    if (!buffer) {
++        return NULL;
++    }
++    memcpy(buffer, instr, len);
++    buffer[len] = 0; /* NULL termination */
++    return buffer;
++}
++
++char *pem_Strdup(const char *instr)
++{
++    if (!instr) {
++        return NULL;
++    }
++
++    size_t len = strlen(instr);
++    return pem_StrNdup(instr, len);
++}
++
++void pem_Free(char *instr)
++{
++    if (!instr) {
++        PR_ASSERT(0);
++    }
++    PR_Free(instr);
++}
++
++void
++addString(char ***returnedstrings, char *newstring, PRInt32 stringcount)
++{
++    char **stringarray = NULL;
++    if (!returnedstrings || !newstring) {
++        return;
++    }
++    if (!stringcount) {
++        /* first string to be added, allocate buffer */
++        *returnedstrings =
++            (char **) PR_Malloc(sizeof(char *) * (stringcount + 1));
++        stringarray = *returnedstrings;
++    } else {
++        stringarray = (char **) PR_Realloc(*returnedstrings,
++                                           sizeof(char *) * (stringcount + 1));
++        if (stringarray) {
++            *returnedstrings = stringarray;
++        }
++    }
++    if (stringarray) {
++        stringarray[stringcount] = newstring;
++    }
++}
++
++PRBool
++pem_ParseString(const char *inputstring, const char delimiter,
++                PRInt32 * numStrings, char ***returnedstrings)
++{
++    if (!inputstring || !delimiter || !numStrings || !returnedstrings) {
++        /* we need a string and a non-zero delimiter, as well as
++         * a valid place to return the strings and count
++         */
++        return PR_FALSE;
++    }
++    char nextchar;
++    char *instring = (char *) inputstring;
++    *numStrings = 0;
++    *returnedstrings = NULL;
++
++    while ((nextchar = *instring)) {
++        unsigned long len = 0;
++        char *next = (char *) strchr(instring, delimiter);
++        if (next) {
++            /* current string string */
++            len = next - instring;
++        } else {
++            /* last string length */
++            len = strlen(instring);
++        }
++
++        if (len > 0) {
++            char *newstring = pem_StrNdup(instring, len);
++
++            addString(returnedstrings, newstring, (*numStrings)++);
++
++            instring += len;
++        }
++
++        if (delimiter == *instring) {
++            instring++; /* skip past next delimiter */
++        }
++    }
++    return PR_TRUE;
++}
++
++PRBool pem_FreeParsedStrings(PRInt32 numStrings, char **instrings)
++{
++    if (!numStrings || !instrings) {
++        return PR_FALSE;
++    }
++    PRInt32 counter;
++    for (counter = 0; counter < numStrings; counter++) {
++        char *astring = instrings[counter];
++        if (astring) {
++            pem_Free(astring);
++        }
++    }
++    PR_Free((void *) instrings);
++    return PR_TRUE;
++}
+diff --git a/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 at 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..813810c
+--- /dev/null
++++ b/b/nss/lib/ckfw/pem/pinst.c
+@@ -0,0 +1,766 @@
++/* ***** 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 at redhat.com)
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++#include <stdlib.h>
++#include "ckpem.h"
++#include "blapi.h"
++
++/*
++ * pinstance.c
++ *
++ * This file implements the NSSCKMDInstance object for the 
++ * "PEM objects" cryptoki module.
++ */
++
++static PRBool pemInitialized = PR_FALSE;
++
++pemInternalObject **gobj;
++int pem_nobjs = 0;
++int token_needsLogin[NUM_SLOTS];
++
++PRInt32 size = 0;
++PRInt32 count = 0;
++
++#define PEM_ITEM_CHUNK  512
++
++/*
++ * 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;
++
++    /* 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 */
++    pemInternalObject *io = CreateObject(objClass, type, certDER, keyDER,
++                                         filename, objid, slotID);
++    if (io == NULL)
++        return NULL;
++
++    /* initialize pointers to functions */
++    pem_CreateMDObject(NULL, io, NULL);
++
++    io->gobjIndex = count;
++
++    /* add object to global array */
++    if (count >= size) {
++        gobj = gobj ?
++            nss_ZREALLOCARRAY(gobj, pemInternalObject *,
++                    (size+PEM_ITEM_CHUNK) ) :
++            nss_ZNEWARRAY(NULL, pemInternalObject *,
++                    (size+PEM_ITEM_CHUNK) ) ;
++
++        if ((pemInternalObject **)NULL == gobj)
++            return NULL;
++        size += PEM_ITEM_CHUNK;
++    }
++    gobj[count] = io;
++    count++;
++    pem_nobjs++;
++
++    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;
++
++            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..48f72d0
+--- /dev/null
++++ b/b/nss/lib/ckfw/pem/pobject.c
+@@ -0,0 +1,1239 @@
++/* ***** 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 at redhat.com)
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "ckpem.h"
++#include "secasn1.h"
++#include "certt.h"
++#include "pk11pub.h"
++
++/*
++ * pobject.c
++ *
++ * This file implements the NSSCKMDObject object for the
++ * "PEM objects" cryptoki module.
++ */
++
++NSS_EXTERN_DATA pemInternalObject **gobj;
++NSS_EXTERN_DATA int pem_nobjs;
++NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS];
++
++#define 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,

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list