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