summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2023-01-05 17:49:02 +0000
committerRobert Relyea <rrelyea@redhat.com>2023-01-05 17:49:02 +0000
commit1ff7c5ae46033f821c9a980dca0bac343e0a4887 (patch)
tree8aa2af48b2817e4cefd4792b62ba762ebdba4aa9
parentd0576db1c914ce8498b9ed4f78e026119a5a405c (diff)
downloadnss-hg-1ff7c5ae46033f821c9a980dca0bac343e0a4887.tar.gz
WIP: Bug 1804091 NSS needs to move off of DSA for integrity checks. r=nss-reviewers,jschanck
When we first added integrity checks to NSS for FIPS compliance, the only signature method allowed was DSA. NIST will be sunsetting DSA in 2023, so we need to update our integrity checks again. Since the time we added these checks, NIST has started accepting HMAC as a valid signature algorithm for integrity checks. HMAC is easier, faster and requires smaller .chk files and openssl and gnutls has been using hmac now for years for this purpose. Since we need to move off of DSA anyway it's time to move to HMAC. This patch does this move. shlibsign now produces HMAC_256 by default. It moves the version number up because even though nss includes a type field, previous versions of NSS did not look at the type field when checking integrity. Bumping the version number will cause previous versions of NSS to fail early if presented with a newly generated integrity check file (even though it should fail later anyway). shlibsign now has the ability to generate 'legacy' check files so it can be used to generate check files for older versions of NSS. NSS can still accept older check files unless NSS_STRICT_INTEGRITY is set at compile time. This means tools which may be using old shlibsign to resign nss shared libraries will continue to work. At some point we can remove all DSA support (maybe after one enterprise release cycle). While completing this work, we also complete some integrity code cleanup. There are lots of magic numbers defining where things fall in the integrity check header. These are now moved to a structure and defined in the shsign.h header. Both shlibsign and shvfy have been updated to use this header. New test cases are not needed since fips.sh adequately tests our integrity code (both normal case and against mangled libraries which should fail). Though the lowhash test was updated to catch a particular issue we can run into when we use the LOWHASH code. On RHEL-7, we use the NSSLOWHASH_ interface in freebl in libc, which needs to run independently of nspr and nssutil. This requirement puts a pretty heavy burned on freebl to be self-contained when used for NSSLOWHASH_, including running integrity checks. The previous test program linked with nssutil and nspr (just like all of the rest of the nss tests) and weren't detecting issues when unimplemented stub functions where called. This patch includes fixing those lowhash tests and also implementing the stubs needed by the current integrity check code. cmd/lowhashtest/Makefile remove linking lowhashtest with all the libraries except freebl. cmd/lowhashtest/lowhashtest.c remove any dependency NSPR or NSSUTIL in the code. cmd/lowhashtest/manifest.mn remove spurious requires statements. cmd/shlibsign/shlibsign.c add hmac code. add ability to select the hash type from the command line. separate signature processing into their own functions for DSA and HMAC General cleanups. Use PR_ARRAY_SIZE rather then a custom define. move error printing outside utility functions (so we don't have to pass around filenames everywhere) Use NSSSignChkHeader instead of a Buf with magic offsets for the Check file Header. Add ability to make old style .chk files for old versions of NSS. Add option to revert to DSA Add option to use old version numbers: only valid if DSA is set. lib/freebl/Makefile All NSS_STRICT_INTEGRITY to be set at build time. Setting NSS_STRICT_INTEGRITY only accepts hmac256, hmac384, hmac512. If it's not set, NSS will accept older .chk file formats (like DSA-2). lib/freebl/nsslowhash.c lowhashtest files expect to set NSS_FIPS to force fips mode when testing the lowhash interface, but NSS_FIPS was not being looked at in the nsslow_GetFIPSEnabled. NOTE: setting NSS_FIPS to true will force FIPS mode if the system isn't already in FIPS mode. Setting it to FALSE will not turn it off if the system is already in FIPS mode. lib/freebl/shsign.h Update version. Add new defines for HMAC add new Header structure to remove magic offsets into a raw buffer in the code. lib/freebl/shvfy.c Add HMAC processing. Turn off DSA processing if NSS_STRICT_INTEGERITY is set. Refactor the signature processing. lib/freebl/stubs.c Add SECITEM_ItemsAreEqual for HMAC shvfy Add implementations for SECITEM_ItemsAreEqual, SECITEM_ZfreeItem, and PR_GetEnvSecure. The first is new. The second solves and existing bug which is only seen on RHEL7, and the last is needed for the fix to nsslowhash.c above. PR_GetEnvSecure() calls secure_getenv if _USE_GNU is set, otherwise it falls back to the normal getenv. This should be safe since it's only used in LOWHASH to get the NSS_FIPS environment variable, which only has the effect of making LOWHASH run in fips mode when it otherwise wouldn't. lib/freebl/stubs.c Add SECITEM_ItemsAreEqual for HMAC shvfy tests/lowhash/lowhash.sh Make the test executable so it can be run on it's own. Differential Revision: https://phabricator.services.mozilla.com/D164137
-rw-r--r--cmd/lowhashtest/Makefile8
-rw-r--r--cmd/lowhashtest/lowhashtest.c90
-rw-r--r--cmd/lowhashtest/manifest.mn3
-rw-r--r--cmd/shlibsign/shlibsign.c885
-rw-r--r--lib/freebl/Makefile3
-rw-r--r--lib/freebl/nsslowhash.c7
-rw-r--r--lib/freebl/shsign.h16
-rw-r--r--lib/freebl/shvfy.c438
-rw-r--r--lib/freebl/stubs.c43
-rw-r--r--lib/freebl/stubs.h1
-rwxr-xr-x[-rw-r--r--]tests/lowhash/lowhash.sh0
11 files changed, 1005 insertions, 489 deletions
diff --git a/cmd/lowhashtest/Makefile b/cmd/lowhashtest/Makefile
index cfac7700a..a9c64c1d5 100644
--- a/cmd/lowhashtest/Makefile
+++ b/cmd/lowhashtest/Makefile
@@ -28,9 +28,6 @@ include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
-include ../platlibs.mk
-
-
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
@@ -50,12 +47,7 @@ EXTRA_LIBS += \
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(NSSUTIL_LIB_DIR) \
- -lnssutil3 \
-lfreebl3 \
- -L$(NSPR_LIB_DIR) \
- -lplc4 \
- -lplds4 \
- -lnspr4 \
$(NULL)
#######################################################################
diff --git a/cmd/lowhashtest/lowhashtest.c b/cmd/lowhashtest/lowhashtest.c
index a711ebd4a..6a980fbbf 100644
--- a/cmd/lowhashtest/lowhashtest.c
+++ b/cmd/lowhashtest/lowhashtest.c
@@ -2,19 +2,85 @@
#include <string.h>
#include <assert.h>
-#include "nspr.h"
-
/* nss headers */
-#include "prtypes.h"
-#include "plgetopt.h"
#include "hasht.h"
#include "nsslowhash.h"
#include "secport.h"
-#include "hasht.h"
-#include "basicutil.h"
static char *progName = NULL;
+/* can't call NSPR or NSSUtil directly, so just include
+ * our own versions of SECU_ functions in basicutil.c.
+ * We need this test program to link without those functions
+ * so we can test that everyting works in a freebl only
+ * environment */
+const char *hex = "0123456789abcdef";
+
+const char printable[257] = {
+ "................" /* 0x */
+ "................" /* 1x */
+ " !\"#$%&'()*+,-./" /* 2x */
+ "0123456789:;<=>?" /* 3x */
+ "@ABCDEFGHIJKLMNO" /* 4x */
+ "PQRSTUVWXYZ[\\]^_" /* 5x */
+ "`abcdefghijklmno" /* 6x */
+ "pqrstuvwxyz{|}~." /* 7x */
+ "................" /* 8x */
+ "................" /* 9x */
+ "................" /* ax */
+ "................" /* bx */
+ "................" /* cx */
+ "................" /* dx */
+ "................" /* ex */
+ "................" /* fx */
+};
+
+static void
+SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
+{
+ const unsigned char *cp = (const unsigned char *)vp;
+ char buf[80];
+ char *bp;
+ char *ap;
+
+ fprintf(out, "%s [Len: %d]\n", msg, len);
+ memset(buf, ' ', sizeof buf);
+ bp = buf;
+ ap = buf + 50;
+ while (--len >= 0) {
+ unsigned char ch = *cp++;
+ *bp++ = hex[(ch >> 4) & 0xf];
+ *bp++ = hex[ch & 0xf];
+ *bp++ = ' ';
+ *ap++ = printable[ch];
+ if (ap - buf >= 66) {
+ *ap = 0;
+ fprintf(out, " %s\n", buf);
+ memset(buf, ' ', sizeof buf);
+ bp = buf;
+ ap = buf + 50;
+ }
+ }
+ if (bp > buf) {
+ *ap = 0;
+ fprintf(out, " %s\n", buf);
+ }
+}
+
+/* simple version o print error */
+static void
+SECU_PrintError(const char *prog, const char *string)
+{
+ fprintf(stderr, "%s: %s", prog, string);
+}
+
+/* simple version o print error */
+static void
+SECU_PrintError3(const char *prog, const char *string, const char *string2)
+{
+ fprintf(stderr, "%s: %s %s\n", prog, string, string2);
+}
+
static int
test_long_message(NSSLOWInitContext *initCtx,
HASH_HashType algoType, unsigned int hashLen,
@@ -28,7 +94,7 @@ test_long_message(NSSLOWInitContext *initCtx,
* buffer and call update 1,000 times.
*/
unsigned char buf[1000];
- (void)PORT_Memset(buf, 'a', sizeof(buf));
+ (void)memset(buf, 'a', sizeof(buf));
ctx = NSSLOWHASH_NewContext(initCtx, algoType);
if (ctx == NULL) {
@@ -42,8 +108,8 @@ test_long_message(NSSLOWInitContext *initCtx,
}
NSSLOWHASH_End(ctx, results, &len, hashLen);
- PR_ASSERT(len == hashLen);
- PR_ASSERT(PORT_Memcmp(expected, results, hashLen) == 0);
+ assert(len == hashLen);
+ assert(PORT_Memcmp(expected, results, hashLen) == 0);
if (PORT_Memcmp(expected, results, len) != 0) {
SECU_PrintError(progName, "Hash mismatch\n");
SECU_PrintBuf(stdout, "Expected: ", expected, hashLen);
@@ -140,8 +206,8 @@ testMessageDigest(NSSLOWInitContext *initCtx,
NSSLOWHASH_Begin(ctx);
NSSLOWHASH_Update(ctx, message, PORT_Strlen((const char *)message));
NSSLOWHASH_End(ctx, results, &len, hashLen);
- PR_ASSERT(len == hashLen);
- PR_ASSERT(PORT_Memcmp(expected, results, len) == 0);
+ assert(len == hashLen);
+ assert(PORT_Memcmp(expected, results, len) == 0);
if (PORT_Memcmp(expected, results, len) != 0) {
SECU_PrintError(progName, "Hash mismatch\n");
@@ -425,7 +491,7 @@ main(int argc, char **argv)
} else if (strcmp(argv[1], "SHA512") == 0) {
rv += testSHA512(initCtx);
} else {
- SECU_PrintError(progName, "Unsupported hash type %s\n", argv[0]);
+ SECU_PrintError3(progName, "Unsupported hash type", argv[0]);
Usage();
}
diff --git a/cmd/lowhashtest/manifest.mn b/cmd/lowhashtest/manifest.mn
index 00659ee11..8f438704c 100644
--- a/cmd/lowhashtest/manifest.mn
+++ b/cmd/lowhashtest/manifest.mn
@@ -6,7 +6,7 @@ CORE_DEPTH = ../..
MODULE = nss
-REQUIRES = seccmd dbm softoken
+REQUIRES =
INCLUDES += -I$(CORE_DEPTH)/nss/lib/freebl
@@ -16,4 +16,3 @@ CSRCS = \
lowhashtest.c \
$(NULL)
-USE_STATIC_LIBS = 1
diff --git a/cmd/shlibsign/shlibsign.c b/cmd/shlibsign/shlibsign.c
index ad8f3b84e..5745426ba 100644
--- a/cmd/shlibsign/shlibsign.c
+++ b/cmd/shlibsign/shlibsign.c
@@ -19,6 +19,9 @@
#define USES_LINKS 1
#endif
+#define COMPAT_MAJOR 0x01
+#define COMPAT_MINOR 0x02
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,22 +52,74 @@
/* freebl headers */
#include "shsign.h"
-#define NUM_ELEM(array) (sizeof(array) / sizeof(array[0]))
-CK_BBOOL true = CK_TRUE;
-CK_BBOOL false = CK_FALSE;
+/* nss headers for definition of HASH_HashType */
+#include "hasht.h"
+
+CK_BBOOL cktrue = CK_TRUE;
+CK_BBOOL ckfalse = CK_FALSE;
static PRBool verbose = PR_FALSE;
+static PRBool verify = PR_FALSE;
+static PRBool compat = PR_FALSE;
+
+typedef struct HashTableStruct {
+ char *name;
+ CK_MECHANISM_TYPE hash;
+ CK_MECHANISM_TYPE hmac;
+ CK_KEY_TYPE keyType;
+ HASH_HashType hashType;
+ CK_ULONG hashLength;
+} HashTable;
+
+#define CKR_INTERNAL_OUT_FAILURE 0x80111111
+#define CKR_INTERNAL_IN_FAILURE 0x80222222
+#define CKM_SHA1 CKM_SHA_1
+#define CKM_SHA1_HMAC CKM_SHA_1_HMAC
+#define CKK_SHA1_HMAC CKK_SHA_1_HMAC
+#define MKHASH(name, mech) \
+ { \
+ name, CKM_##mech, CKM_##mech##_HMAC, \
+ CKK_##mech##_HMAC, HASH_Alg##mech, mech##_LENGTH \
+ }
+static HashTable hashTable[] = {
+ MKHASH("sha-1", SHA1), MKHASH("sha1", SHA1), MKHASH("sha224", SHA224),
+ MKHASH("sha256", SHA256), MKHASH("sha384", SHA384),
+ MKHASH("sha512", SHA512)
+};
+static size_t hashTableSize = PR_ARRAY_SIZE(hashTable);
+
+const HashTable *
+findHash(const char *hashName)
+{
+ int i;
+
+ for (i = 0; i < hashTableSize; i++) {
+ if (PL_strcasecmp(hashTable[i].name, hashName) == 0) {
+ return &hashTable[i];
+ }
+ }
+ return NULL;
+}
static void
usage(const char *program_name)
{
+ int i;
+ const char *comma = "";
PRFileDesc *debug_out = PR_GetSpecialFD(PR_StandardError);
PR_fprintf(debug_out,
"type %s -H for more detail information.\n", program_name);
PR_fprintf(debug_out,
"Usage: %s [-v] [-V] [-o outfile] [-d dbdir] [-f pwfile]\n"
- " [-F] [-p pwd] -[P dbprefix ] "
+ " [-F] [-p pwd] -[P dbprefix ] [-t hash]"
+ " [-D] [-k keysize] [-c]"
"-i shared_library_name\n",
program_name);
+ PR_fprintf(debug_out, "Valid Hashes: ");
+ for (i = 0; i < hashTableSize; i++) {
+ PR_fprintf(debug_out, "%s%s", comma, hashTable[i].name);
+ comma = ", ";
+ }
+ PR_fprintf(debug_out, "\n");
exit(1);
}
@@ -72,10 +127,16 @@ static void
long_usage(const char *program_name)
{
PRFileDesc *debug_out = PR_GetSpecialFD(PR_StandardError);
+ int i;
+ const char *comma = "";
PR_fprintf(debug_out, "%s test program usage:\n", program_name);
PR_fprintf(debug_out, "\t-i <infile> shared_library_name to process\n");
PR_fprintf(debug_out, "\t-o <outfile> checksum outfile\n");
PR_fprintf(debug_out, "\t-d <path> database path location\n");
+ PR_fprintf(debug_out, "\t-t <hash> Hash for HMAC/or DSA\n");
+ PR_fprintf(debug_out, "\t-D Sign with DSA rather than HMAC\n");
+ PR_fprintf(debug_out, "\t-k <keysize> size of the DSA key\n");
+ PR_fprintf(debug_out, "\t-c Use compatible versions for old NSS\n");
PR_fprintf(debug_out, "\t-P <prefix> database prefix\n");
PR_fprintf(debug_out, "\t-f <file> password File : echo pw > file \n");
PR_fprintf(debug_out, "\t-F FIPS mode\n");
@@ -90,6 +151,12 @@ long_usage(const char *program_name)
PR_fprintf(debug_out, "\t pre-existing libraries with generated ");
PR_fprintf(debug_out, "checksum files\n");
PR_fprintf(debug_out, "\t and database in FIPS mode \n");
+ PR_fprintf(debug_out, "Valid Hashes: ");
+ for (i = 0; i < hashTableSize; i++) {
+ PR_fprintf(debug_out, "%s%s", comma, hashTable[i].name);
+ comma = ", ";
+ }
+ PR_fprintf(debug_out, "\n");
exit(1);
}
@@ -131,8 +198,7 @@ encodeInt(unsigned char *buf, int val)
}
static PRStatus
-writeItem(PRFileDesc *fd, CK_VOID_PTR pValue,
- CK_ULONG ulValueLen, char *file)
+writeItem(PRFileDesc *fd, CK_VOID_PTR pValue, CK_ULONG ulValueLen)
{
unsigned char buf[4];
int bytesWritten;
@@ -144,12 +210,10 @@ writeItem(PRFileDesc *fd, CK_VOID_PTR pValue,
encodeInt(buf, ulValueLen);
bytesWritten = PR_Write(fd, buf, 4);
if (bytesWritten != 4) {
- lperror(file);
return PR_FAILURE;
}
bytesWritten = PR_Write(fd, pValue, ulValueLen);
if (bytesWritten < 0 || (CK_ULONG)bytesWritten != ulValueLen) {
- lperror(file);
return PR_FAILURE;
}
return PR_SUCCESS;
@@ -701,6 +765,481 @@ getSlotList(CK_FUNCTION_LIST_PTR pFunctionList,
return pSlotList;
}
+CK_RV
+shlibSignDSA(CK_FUNCTION_LIST_PTR pFunctionList, CK_SLOT_ID slot,
+ CK_SESSION_HANDLE hRwSession, int keySize, PRFileDesc *ifd,
+ PRFileDesc *ofd, const HashTable *hash)
+{
+ CK_MECHANISM digestmech;
+ CK_ULONG digestLen = 0;
+ CK_BYTE digest[HASH_LENGTH_MAX];
+ CK_BYTE sign[64]; /* DSA2 SIGNATURE LENGTH */
+ CK_ULONG signLen = 0;
+ CK_ULONG expectedSigLen = sizeof(sign);
+ CK_MECHANISM signMech = {
+ CKM_DSA, NULL, 0
+ };
+ int bytesRead;
+ int bytesWritten;
+ unsigned char file_buf[512];
+ NSSSignChkHeader header;
+ int count = 0;
+ CK_RV crv = CKR_GENERAL_ERROR;
+ PRStatus rv = PR_SUCCESS;
+ const char *hashName = "sha256"; /* default hash value */
+ int i;
+
+ /*** DSA Key ***/
+ CK_MECHANISM dsaKeyPairGenMech;
+ CK_ATTRIBUTE dsaPubKeyTemplate[5];
+ CK_ATTRIBUTE dsaPrivKeyTemplate[5];
+ CK_OBJECT_HANDLE hDSApubKey = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE hDSAprivKey = CK_INVALID_HANDLE;
+ CK_BYTE dsaPubKey[384];
+ CK_ATTRIBUTE dsaPubKeyValue;
+
+ if ((keySize == 0) || (keySize > 1024)) {
+ CK_MECHANISM_INFO mechInfo;
+ crv = pFunctionList->C_GetMechanismInfo(slot,
+ CKM_DSA, &mechInfo);
+ if (crv != CKR_OK) {
+ pk11error("Couldn't get mechanism info for DSA", crv);
+ return crv;
+ }
+
+ if (keySize && (mechInfo.ulMaxKeySize < keySize)) {
+ PR_fprintf(PR_STDERR,
+ "token doesn't support DSA2 (Max key size=%d)\n",
+ mechInfo.ulMaxKeySize);
+ return crv;
+ }
+
+ if ((keySize == 0) && mechInfo.ulMaxKeySize >= 2048) {
+ keySize = 2048;
+ } else {
+ keySize = 1024;
+ }
+ }
+
+ /* DSA key init */
+ if (keySize == 1024) {
+ dsaPubKeyTemplate[0].type = CKA_PRIME;
+ dsaPubKeyTemplate[0].pValue = (CK_VOID_PTR)&prime;
+ dsaPubKeyTemplate[0].ulValueLen = sizeof(prime);
+ dsaPubKeyTemplate[1].type = CKA_SUBPRIME;
+ dsaPubKeyTemplate[1].pValue = (CK_VOID_PTR)&subprime;
+ dsaPubKeyTemplate[1].ulValueLen = sizeof(subprime);
+ dsaPubKeyTemplate[2].type = CKA_BASE;
+ dsaPubKeyTemplate[2].pValue = (CK_VOID_PTR)&base;
+ dsaPubKeyTemplate[2].ulValueLen = sizeof(base);
+ hashName = "sha-1"; /* use sha-1 for old dsa keys */
+ expectedSigLen = 32;
+ } else if (keySize == 2048) {
+ dsaPubKeyTemplate[0].type = CKA_PRIME;
+ dsaPubKeyTemplate[0].pValue = (CK_VOID_PTR)&prime2;
+ dsaPubKeyTemplate[0].ulValueLen = sizeof(prime2);
+ dsaPubKeyTemplate[1].type = CKA_SUBPRIME;
+ dsaPubKeyTemplate[1].pValue = (CK_VOID_PTR)&subprime2;
+ dsaPubKeyTemplate[1].ulValueLen = sizeof(subprime2);
+ dsaPubKeyTemplate[2].type = CKA_BASE;
+ dsaPubKeyTemplate[2].pValue = (CK_VOID_PTR)&base2;
+ dsaPubKeyTemplate[2].ulValueLen = sizeof(base2);
+ digestmech.mechanism = hash ? hash->hash : CKM_SHA256;
+ digestmech.pParameter = NULL;
+ digestmech.ulParameterLen = 0;
+ } else {
+ PR_fprintf(PR_STDERR, "Only keysizes 1024 and 2048 are supported");
+ return CKR_GENERAL_ERROR;
+ }
+ if (hash == NULL) {
+ hash = findHash(hashName);
+ }
+ if (hash == NULL) {
+ PR_fprintf(PR_STDERR,
+ "Internal error, couldn't find hash '%s' in table.\n",
+ hashName);
+ return CKR_GENERAL_ERROR;
+ }
+ digestmech.mechanism = hash->hash;
+ digestmech.pParameter = NULL;
+ digestmech.ulParameterLen = 0;
+ dsaPubKeyTemplate[3].type = CKA_TOKEN;
+ dsaPubKeyTemplate[3].pValue = &ckfalse; /* session object */
+ dsaPubKeyTemplate[3].ulValueLen = sizeof(ckfalse);
+ dsaPubKeyTemplate[4].type = CKA_VERIFY;
+ dsaPubKeyTemplate[4].pValue = &cktrue;
+ dsaPubKeyTemplate[4].ulValueLen = sizeof(cktrue);
+ dsaKeyPairGenMech.mechanism = CKM_DSA_KEY_PAIR_GEN;
+ dsaKeyPairGenMech.pParameter = NULL;
+ dsaKeyPairGenMech.ulParameterLen = 0;
+ dsaPrivKeyTemplate[0].type = CKA_TOKEN;
+ dsaPrivKeyTemplate[0].pValue = &ckfalse; /* session object */
+ dsaPrivKeyTemplate[0].ulValueLen = sizeof(ckfalse);
+ dsaPrivKeyTemplate[1].type = CKA_PRIVATE;
+ dsaPrivKeyTemplate[1].pValue = &cktrue;
+ dsaPrivKeyTemplate[1].ulValueLen = sizeof(cktrue);
+ dsaPrivKeyTemplate[2].type = CKA_SENSITIVE;
+ dsaPrivKeyTemplate[2].pValue = &cktrue;
+ dsaPrivKeyTemplate[2].ulValueLen = sizeof(cktrue);
+ dsaPrivKeyTemplate[3].type = CKA_SIGN,
+ dsaPrivKeyTemplate[3].pValue = &cktrue;
+ dsaPrivKeyTemplate[3].ulValueLen = sizeof(cktrue);
+ dsaPrivKeyTemplate[4].type = CKA_EXTRACTABLE;
+ dsaPrivKeyTemplate[4].pValue = &ckfalse;
+ dsaPrivKeyTemplate[4].ulValueLen = sizeof(ckfalse);
+
+ /* Generate a DSA key pair */
+ logIt("Generate a DSA key pair ... \n");
+ crv = pFunctionList->C_GenerateKeyPair(hRwSession, &dsaKeyPairGenMech,
+ dsaPubKeyTemplate,
+ PR_ARRAY_SIZE(dsaPubKeyTemplate),
+ dsaPrivKeyTemplate,
+ PR_ARRAY_SIZE(dsaPrivKeyTemplate),
+ &hDSApubKey, &hDSAprivKey);
+ if (crv != CKR_OK) {
+ pk11error("DSA key pair generation failed", crv);
+ return crv;
+ }
+
+ /* compute the digest */
+ memset(digest, 0, sizeof(digest));
+ crv = pFunctionList->C_DigestInit(hRwSession, &digestmech);
+ if (crv != CKR_OK) {
+ pk11error("C_DigestInit failed", crv);
+ return crv;
+ }
+
+ /* Digest the file */
+ while ((bytesRead = PR_Read(ifd, file_buf, sizeof(file_buf))) > 0) {
+ crv = pFunctionList->C_DigestUpdate(hRwSession, (CK_BYTE_PTR)file_buf,
+ bytesRead);
+ if (crv != CKR_OK) {
+ pk11error("C_DigestUpdate failed", crv);
+ return crv;
+ }
+ count += bytesRead;
+ }
+
+ if (bytesRead < 0) {
+ lperror("0 bytes read from input file");
+ return CKR_INTERNAL_IN_FAILURE;
+ }
+
+ digestLen = sizeof(digest);
+ crv = pFunctionList->C_DigestFinal(hRwSession, (CK_BYTE_PTR)digest,
+ &digestLen);
+ if (crv != CKR_OK) {
+ pk11error("C_DigestFinal failed", crv);
+ return crv;
+ }
+
+ if (digestLen != hash->hashLength) {
+ PR_fprintf(PR_STDERR, "digestLen has incorrect length %lu "
+ "it should be %lu \n",
+ digestLen, sizeof(digest));
+ return crv;
+ }
+
+ /* sign the hash */
+ memset(sign, 0, sizeof(sign));
+ /* SignUpdate */
+ crv = pFunctionList->C_SignInit(hRwSession, &signMech, hDSAprivKey);
+ if (crv != CKR_OK) {
+ pk11error("C_SignInit failed", crv);
+ return crv;
+ }
+
+ signLen = sizeof(sign);
+ crv = pFunctionList->C_Sign(hRwSession, (CK_BYTE *)digest, digestLen,
+ sign, &signLen);
+ if (crv != CKR_OK) {
+ pk11error("C_Sign failed", crv);
+ return crv;
+ }
+
+ if (signLen != expectedSigLen) {
+ PR_fprintf(PR_STDERR, "signLen has incorrect length %lu "
+ "it should be %lu \n",
+ signLen, expectedSigLen);
+ return crv;
+ }
+
+ if (verify) {
+ crv = pFunctionList->C_VerifyInit(hRwSession, &signMech, hDSApubKey);
+ if (crv != CKR_OK) {
+ pk11error("C_VerifyInit failed", crv);
+ return crv;
+ }
+ crv = pFunctionList->C_Verify(hRwSession, digest, digestLen,
+ sign, signLen);
+ if (crv != CKR_OK) {
+ pk11error("C_Verify failed", crv);
+ return crv;
+ }
+ }
+
+ if (verbose) {
+ int j;
+ PR_fprintf(PR_STDERR, "Library File Size: %d bytes\n", count);
+ PR_fprintf(PR_STDERR, " hash: %lu bytes\n", digestLen);
+#define STEP 10
+ for (i = 0; i < (int)digestLen; i += STEP) {
+ PR_fprintf(PR_STDERR, " ");
+ for (j = 0; j < STEP && (i + j) < (int)digestLen; j++) {
+ PR_fprintf(PR_STDERR, " %02x", digest[i + j]);
+ }
+ PR_fprintf(PR_STDERR, "\n");
+ }
+ PR_fprintf(PR_STDERR, " signature: %lu bytes\n", signLen);
+ for (i = 0; i < (int)signLen; i += STEP) {
+ PR_fprintf(PR_STDERR, " ");
+ for (j = 0; j < STEP && (i + j) < (int)signLen; j++) {
+ PR_fprintf(PR_STDERR, " %02x", sign[i + j]);
+ }
+ PR_fprintf(PR_STDERR, "\n");
+ }
+ }
+
+ /*
+ * we write the key out in a straight binary format because very
+ * low level libraries need to read an parse this file. Ideally we should
+ * just derEncode the public key (which would be pretty simple, and be
+ * more general), but then we'd need to link the ASN.1 decoder with the
+ * freebl libraries.
+ */
+
+ header.magic1 = NSS_SIGN_CHK_MAGIC1;
+ header.magic2 = NSS_SIGN_CHK_MAGIC2;
+ header.majorVersion = compat ? COMPAT_MAJOR : NSS_SIGN_CHK_MAJOR_VERSION;
+ header.minorVersion = compat ? COMPAT_MINOR : NSS_SIGN_CHK_MINOR_VERSION;
+ encodeInt(header.offset, sizeof(header)); /* offset to data start */
+ encodeInt(header.type, CKK_DSA);
+ bytesWritten = PR_Write(ofd, &header, sizeof(header));
+ if (bytesWritten != sizeof(header)) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+
+ /* get DSA Public KeyValue */
+ memset(dsaPubKey, 0, sizeof(dsaPubKey));
+ dsaPubKeyValue.type = CKA_VALUE;
+ dsaPubKeyValue.pValue = (CK_VOID_PTR)&dsaPubKey;
+ dsaPubKeyValue.ulValueLen = sizeof(dsaPubKey);
+
+ crv = pFunctionList->C_GetAttributeValue(hRwSession, hDSApubKey,
+ &dsaPubKeyValue, 1);
+ if (crv != CKR_OK && crv != CKR_ATTRIBUTE_TYPE_INVALID) {
+ pk11error("C_GetAttributeValue failed", crv);
+ return crv;
+ }
+
+ /* CKA_PRIME */
+ rv = writeItem(ofd, dsaPubKeyTemplate[0].pValue,
+ dsaPubKeyTemplate[0].ulValueLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+ /* CKA_SUBPRIME */
+ rv = writeItem(ofd, dsaPubKeyTemplate[1].pValue,
+ dsaPubKeyTemplate[1].ulValueLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+ /* CKA_BASE */
+ rv = writeItem(ofd, dsaPubKeyTemplate[2].pValue,
+ dsaPubKeyTemplate[2].ulValueLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+ /* DSA Public Key value */
+ rv = writeItem(ofd, dsaPubKeyValue.pValue,
+ dsaPubKeyValue.ulValueLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+ /* DSA SIGNATURE */
+ rv = writeItem(ofd, &sign, signLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+
+ return CKR_OK;
+}
+
+CK_RV
+shlibSignHMAC(CK_FUNCTION_LIST_PTR pFunctionList, CK_SLOT_ID slot,
+ CK_SESSION_HANDLE hRwSession, int keySize, PRFileDesc *ifd,
+ PRFileDesc *ofd, const HashTable *hash)
+{
+ CK_MECHANISM hmacMech = { 0, NULL, 0 };
+ CK_MECHANISM hmacKeyGenMech = { 0, NULL, 0 };
+ CK_BYTE keyBuf[HASH_LENGTH_MAX];
+ CK_ULONG keyLen = 0;
+ CK_BYTE sign[HASH_LENGTH_MAX];
+ CK_ULONG signLen = 0;
+ int bytesRead;
+ int bytesWritten;
+ unsigned char file_buf[512];
+ NSSSignChkHeader header;
+ int count = 0;
+ CK_RV crv = CKR_GENERAL_ERROR;
+ PRStatus rv = PR_SUCCESS;
+ int i;
+
+ /*** HMAC Key ***/
+ CK_ATTRIBUTE hmacKeyTemplate[7];
+ CK_ATTRIBUTE hmacKeyValue;
+ CK_OBJECT_HANDLE hHMACKey = CK_INVALID_HANDLE;
+
+ if (hash == NULL) {
+ hash = findHash("sha256");
+ }
+ if (hash == NULL) {
+ PR_fprintf(PR_STDERR,
+ "Internal error:Could find sha256 entry in table.\n");
+ }
+
+ hmacKeyTemplate[0].type = CKA_TOKEN;
+ hmacKeyTemplate[0].pValue = &ckfalse; /* session object */
+ hmacKeyTemplate[0].ulValueLen = sizeof(ckfalse);
+ hmacKeyTemplate[1].type = CKA_PRIVATE;
+ hmacKeyTemplate[1].pValue = &cktrue;
+ hmacKeyTemplate[1].ulValueLen = sizeof(cktrue);
+ hmacKeyTemplate[2].type = CKA_SENSITIVE;
+ hmacKeyTemplate[2].pValue = &ckfalse;
+ hmacKeyTemplate[2].ulValueLen = sizeof(cktrue);
+ hmacKeyTemplate[3].type = CKA_SIGN;
+ hmacKeyTemplate[3].pValue = &cktrue;
+ hmacKeyTemplate[3].ulValueLen = sizeof(cktrue);
+ hmacKeyTemplate[4].type = CKA_EXTRACTABLE;
+ hmacKeyTemplate[4].pValue = &ckfalse;
+ hmacKeyTemplate[4].ulValueLen = sizeof(ckfalse);
+ hmacKeyTemplate[5].type = CKA_VALUE_LEN;
+ hmacKeyTemplate[5].pValue = (void *)&hash->hashLength;
+ hmacKeyTemplate[5].ulValueLen = sizeof(hash->hashLength);
+ hmacKeyTemplate[6].type = CKA_KEY_TYPE;
+ hmacKeyTemplate[6].pValue = (void *)&hash->keyType;
+ hmacKeyTemplate[6].ulValueLen = sizeof(hash->keyType);
+ hmacKeyGenMech.mechanism = CKM_GENERIC_SECRET_KEY_GEN;
+ hmacMech.mechanism = hash->hmac;
+
+ /* Generate a DSA key pair */
+ logIt("Generate an HMAC key ... \n");
+ crv = pFunctionList->C_GenerateKey(hRwSession, &hmacKeyGenMech,
+ hmacKeyTemplate,
+ PR_ARRAY_SIZE(hmacKeyTemplate),
+ &hHMACKey);
+ if (crv != CKR_OK) {
+ pk11error("HMAC key generation failed", crv);
+ return crv;
+ }
+
+ /* compute the digest */
+ memset(sign, 0, sizeof(sign));
+ crv = pFunctionList->C_SignInit(hRwSession, &hmacMech, hHMACKey);
+ if (crv != CKR_OK) {
+ pk11error("C_SignInit failed", crv);
+ return crv;
+ }
+
+ /* Digest the file */
+ while ((bytesRead = PR_Read(ifd, file_buf, sizeof(file_buf))) > 0) {
+ crv = pFunctionList->C_SignUpdate(hRwSession, (CK_BYTE_PTR)file_buf,
+ bytesRead);
+ if (crv != CKR_OK) {
+ pk11error("C_SignUpdate failed", crv);
+ return crv;
+ }
+ count += bytesRead;
+ }
+
+ if (bytesRead < 0) {
+ lperror("0 bytes read from input file");
+ return CKR_INTERNAL_IN_FAILURE;
+ }
+
+ signLen = sizeof(sign);
+ crv = pFunctionList->C_SignFinal(hRwSession, (CK_BYTE_PTR)sign,
+ &signLen);
+ if (crv != CKR_OK) {
+ pk11error("C_SignFinal failed", crv);
+ return crv;
+ }
+
+ if (signLen != hash->hashLength) {
+ PR_fprintf(PR_STDERR, "digestLen has incorrect length %lu "
+ "it should be %lu \n",
+ signLen, hash->hashLength);
+ return crv;
+ }
+ /* get HMAC KeyValue */
+ memset(keyBuf, 0, sizeof(keyBuf));
+ hmacKeyValue.type = CKA_VALUE;
+ hmacKeyValue.pValue = (CK_VOID_PTR)&keyBuf;
+ hmacKeyValue.ulValueLen = sizeof(keyBuf);
+
+ crv = pFunctionList->C_GetAttributeValue(hRwSession, hHMACKey,
+ &hmacKeyValue, 1);
+ if (crv != CKR_OK && crv != CKR_ATTRIBUTE_TYPE_INVALID) {
+ pk11error("C_GetAttributeValue failed", crv);
+ return crv;
+ }
+ keyLen = hmacKeyValue.ulValueLen;
+
+ if (verbose) {
+ int j;
+ PR_fprintf(PR_STDERR, "Library File Size: %d bytes\n", count);
+ PR_fprintf(PR_STDERR, " key: %lu bytes\n", keyLen);
+#define STEP 10
+ for (i = 0; i < (int)keyLen; i += STEP) {
+ PR_fprintf(PR_STDERR, " ");
+ for (j = 0; j < STEP && (i + j) < (int)keyLen; j++) {
+ PR_fprintf(PR_STDERR, " %02x", keyBuf[i + j]);
+ }
+ PR_fprintf(PR_STDERR, "\n");
+ }
+ PR_fprintf(PR_STDERR, " signature: %lu bytes\n", signLen);
+ for (i = 0; i < (int)signLen; i += STEP) {
+ PR_fprintf(PR_STDERR, " ");
+ for (j = 0; j < STEP && (i + j) < (int)signLen; j++) {
+ PR_fprintf(PR_STDERR, " %02x", sign[i + j]);
+ }
+ PR_fprintf(PR_STDERR, "\n");
+ }
+ }
+
+ /*
+ * we write the key out in a straight binary format because very
+ * low level libraries need to read an parse this file. Ideally we should
+ * just derEncode the public key (which would be pretty simple, and be
+ * more general), but then we'd need to link the ASN.1 decoder with the
+ * freebl libraries.
+ */
+
+ header.magic1 = NSS_SIGN_CHK_MAGIC1;
+ header.magic2 = NSS_SIGN_CHK_MAGIC2;
+ header.majorVersion = NSS_SIGN_CHK_MAJOR_VERSION;
+ header.minorVersion = NSS_SIGN_CHK_MINOR_VERSION;
+ encodeInt(header.offset, sizeof(header)); /* offset to data start */
+ encodeInt(header.type, NSS_SIGN_CHK_FLAG_HMAC | hash->hashType);
+ bytesWritten = PR_Write(ofd, &header, sizeof(header));
+ if (bytesWritten != sizeof(header)) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+
+ /* HMACKey */
+ rv = writeItem(ofd, keyBuf, keyLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+ /* HMAC SIGNATURE */
+ rv = writeItem(ofd, &sign, signLen);
+ if (rv != PR_SUCCESS) {
+ return CKR_INTERNAL_OUT_FAILURE;
+ }
+
+ return CKR_OK;
+}
+
int
main(int argc, char **argv)
{
@@ -708,19 +1247,15 @@ main(int argc, char **argv)
char *program_name;
char *libname = NULL;
PRLibrary *lib = NULL;
- PRFileDesc *fd;
- PRStatus rv = PR_SUCCESS;
+ PRFileDesc *ifd = NULL;
+ PRFileDesc *ofd = NULL;
const char *input_file = NULL; /* read/create encrypted data from here */
char *output_file = NULL; /* write new encrypted data here */
- int bytesRead;
- int bytesWritten;
- unsigned char file_buf[512];
- int count = 0;
unsigned int keySize = 0;
- int i;
- PRBool verify = PR_FALSE;
static PRBool FIPSMODE = PR_FALSE;
+ static PRBool useDSA = PR_FALSE;
PRBool successful = PR_FALSE;
+ const HashTable *hash = NULL;
#ifdef USES_LINKS
int ret;
@@ -741,29 +1276,10 @@ main(int argc, char **argv)
CK_SESSION_HANDLE hRwSession;
CK_SLOT_ID *pSlotList = NULL;
CK_ULONG slotIndex = 0;
- CK_MECHANISM digestmech;
- CK_ULONG digestLen = 0;
- CK_BYTE digest[32]; /* SHA256_LENGTH */
- CK_BYTE sign[64]; /* DSA SIGNATURE LENGTH */
- CK_ULONG signLen = 0;
- CK_MECHANISM signMech = {
- CKM_DSA, NULL, 0
- };
-
- /*** DSA Key ***/
-
- CK_MECHANISM dsaKeyPairGenMech;
- CK_ATTRIBUTE dsaPubKeyTemplate[5];
- CK_ATTRIBUTE dsaPrivKeyTemplate[5];
- CK_OBJECT_HANDLE hDSApubKey = CK_INVALID_HANDLE;
- CK_OBJECT_HANDLE hDSAprivKey = CK_INVALID_HANDLE;
-
- CK_BYTE dsaPubKey[384];
- CK_ATTRIBUTE dsaPubKeyValue;
program_name = strrchr(argv[0], '/');
program_name = program_name ? (program_name + 1) : argv[0];
- optstate = PL_CreateOptState(argc, argv, "i:o:f:Fd:hH?k:p:P:vVs:");
+ optstate = PL_CreateOptState(argc, argv, "i:o:f:Fd:hH?k:p:P:vVs:t:Dc");
if (optstate == NULL) {
lperror("PL_CreateOptState failed");
return 1;
@@ -781,6 +1297,14 @@ main(int argc, char **argv)
checkPath(configDir);
break;
+ case 'D':
+ useDSA = PR_TRUE;
+ break;
+
+ case 'c':
+ compat = PR_TRUE;
+ break;
+
case 'i':
if (!optstate->value) {
PL_DestroyOptState(optstate);
@@ -835,6 +1359,18 @@ main(int argc, char **argv)
dbPrefix = PL_strdup(optstate->value);
break;
+ case 't':
+ if (!optstate->value) {
+ PL_DestroyOptState(optstate);
+ usage(program_name);
+ }
+ hash = findHash(optstate->value);
+ if (hash == NULL) {
+ PR_fprintf(PR_STDERR, "Invalid hash '%s'\n",
+ optstate->value);
+ usage(program_name);
+ }
+ break;
case 'v':
verbose = PR_TRUE;
break;
@@ -930,86 +1466,6 @@ main(int argc, char **argv)
goto cleanup;
}
- if ((keySize == 0) || (keySize > 1024)) {
- CK_MECHANISM_INFO mechInfo;
- crv = pFunctionList->C_GetMechanismInfo(pSlotList[slotIndex],
- CKM_DSA, &mechInfo);
- if (crv != CKR_OK) {
- pk11error("Couldn't get mechanism info for DSA", crv);
- goto cleanup;
- }
-
- if (keySize && (mechInfo.ulMaxKeySize < keySize)) {
- PR_fprintf(PR_STDERR,
- "token doesn't support DSA2 (Max key size=%d)\n",
- mechInfo.ulMaxKeySize);
- goto cleanup;
- }
-
- if ((keySize == 0) && mechInfo.ulMaxKeySize >= 2048) {
- keySize = 2048;
- } else {
- keySize = 1024;
- }
- }
-
- /* DSA key init */
- if (keySize == 1024) {
- dsaPubKeyTemplate[0].type = CKA_PRIME;
- dsaPubKeyTemplate[0].pValue = (CK_VOID_PTR)&prime;
- dsaPubKeyTemplate[0].ulValueLen = sizeof(prime);
- dsaPubKeyTemplate[1].type = CKA_SUBPRIME;
- dsaPubKeyTemplate[1].pValue = (CK_VOID_PTR)&subprime;
- dsaPubKeyTemplate[1].ulValueLen = sizeof(subprime);
- dsaPubKeyTemplate[2].type = CKA_BASE;
- dsaPubKeyTemplate[2].pValue = (CK_VOID_PTR)&base;
- dsaPubKeyTemplate[2].ulValueLen = sizeof(base);
- digestmech.mechanism = CKM_SHA_1;
- digestmech.pParameter = NULL;
- digestmech.ulParameterLen = 0;
- } else if (keySize == 2048) {
- dsaPubKeyTemplate[0].type = CKA_PRIME;
- dsaPubKeyTemplate[0].pValue = (CK_VOID_PTR)&prime2;
- dsaPubKeyTemplate[0].ulValueLen = sizeof(prime2);
- dsaPubKeyTemplate[1].type = CKA_SUBPRIME;
- dsaPubKeyTemplate[1].pValue = (CK_VOID_PTR)&subprime2;
- dsaPubKeyTemplate[1].ulValueLen = sizeof(subprime2);
- dsaPubKeyTemplate[2].type = CKA_BASE;
- dsaPubKeyTemplate[2].pValue = (CK_VOID_PTR)&base2;
- dsaPubKeyTemplate[2].ulValueLen = sizeof(base2);
- digestmech.mechanism = CKM_SHA256;
- digestmech.pParameter = NULL;
- digestmech.ulParameterLen = 0;
- } else {
- /* future - generate pqg */
- PR_fprintf(PR_STDERR, "Only keysizes 1024 and 2048 are supported");
- goto cleanup;
- }
- dsaPubKeyTemplate[3].type = CKA_TOKEN;
- dsaPubKeyTemplate[3].pValue = &false; /* session object */
- dsaPubKeyTemplate[3].ulValueLen = sizeof(false);
- dsaPubKeyTemplate[4].type = CKA_VERIFY;
- dsaPubKeyTemplate[4].pValue = &true;
- dsaPubKeyTemplate[4].ulValueLen = sizeof(true);
- dsaKeyPairGenMech.mechanism = CKM_DSA_KEY_PAIR_GEN;
- dsaKeyPairGenMech.pParameter = NULL;
- dsaKeyPairGenMech.ulParameterLen = 0;
- dsaPrivKeyTemplate[0].type = CKA_TOKEN;
- dsaPrivKeyTemplate[0].pValue = &false; /* session object */
- dsaPrivKeyTemplate[0].ulValueLen = sizeof(false);
- dsaPrivKeyTemplate[1].type = CKA_PRIVATE;
- dsaPrivKeyTemplate[1].pValue = &true;
- dsaPrivKeyTemplate[1].ulValueLen = sizeof(true);
- dsaPrivKeyTemplate[2].type = CKA_SENSITIVE;
- dsaPrivKeyTemplate[2].pValue = &true;
- dsaPrivKeyTemplate[2].ulValueLen = sizeof(true);
- dsaPrivKeyTemplate[3].type = CKA_SIGN,
- dsaPrivKeyTemplate[3].pValue = &true;
- dsaPrivKeyTemplate[3].ulValueLen = sizeof(true);
- dsaPrivKeyTemplate[4].type = CKA_EXTRACTABLE;
- dsaPrivKeyTemplate[4].pValue = &false;
- dsaPrivKeyTemplate[4].ulValueLen = sizeof(false);
-
crv = pFunctionList->C_OpenSession(pSlotList[slotIndex],
CKF_RW_SESSION | CKF_SERIAL_SESSION,
NULL, NULL, &hRwSession);
@@ -1041,22 +1497,9 @@ main(int argc, char **argv)
logIt("A password was provided but the password was not used.\n");
}
- /* Generate a DSA key pair */
- logIt("Generate a DSA key pair ... \n");
- crv = pFunctionList->C_GenerateKeyPair(hRwSession, &dsaKeyPairGenMech,
- dsaPubKeyTemplate,
- NUM_ELEM(dsaPubKeyTemplate),
- dsaPrivKeyTemplate,
- NUM_ELEM(dsaPrivKeyTemplate),
- &hDSApubKey, &hDSAprivKey);
- if (crv != CKR_OK) {
- pk11error("DSA key pair generation failed", crv);
- goto cleanup;
- }
-
/* open the shared library */
- fd = PR_OpenFile(input_file, PR_RDONLY, 0);
- if (fd == NULL) {
+ ifd = PR_OpenFile(input_file, PR_RDONLY, 0);
+ if (ifd == NULL) {
lperror(input_file);
goto cleanup;
}
@@ -1102,179 +1545,42 @@ main(int argc, char **argv)
output_file = mkoutput(input_file);
}
- /* compute the digest */
- memset(digest, 0, sizeof(digest));
- crv = pFunctionList->C_DigestInit(hRwSession, &digestmech);
- if (crv != CKR_OK) {
- pk11error("C_DigestInit failed", crv);
- goto cleanup;
- }
-
- /* Digest the file */
- while ((bytesRead = PR_Read(fd, file_buf, sizeof(file_buf))) > 0) {
- crv = pFunctionList->C_DigestUpdate(hRwSession, (CK_BYTE_PTR)file_buf,
- bytesRead);
- if (crv != CKR_OK) {
- pk11error("C_DigestUpdate failed", crv);
- goto cleanup;
- }
- count += bytesRead;
- }
-
- /* close the input_File */
- PR_Close(fd);
- fd = NULL;
- if (bytesRead < 0) {
- lperror("0 bytes read from input file");
- goto cleanup;
- }
-
- digestLen = sizeof(digest);
- crv = pFunctionList->C_DigestFinal(hRwSession, (CK_BYTE_PTR)digest,
- &digestLen);
- if (crv != CKR_OK) {
- pk11error("C_DigestFinal failed", crv);
- goto cleanup;
- }
-
- if (digestLen != sizeof(digest)) {
- PR_fprintf(PR_STDERR, "digestLen has incorrect length %lu "
- "it should be %lu \n",
- digestLen, sizeof(digest));
- goto cleanup;
- }
-
- /* sign the hash */
- memset(sign, 0, sizeof(sign));
- /* SignUpdate */
- crv = pFunctionList->C_SignInit(hRwSession, &signMech, hDSAprivKey);
- if (crv != CKR_OK) {
- pk11error("C_SignInit failed", crv);
- goto cleanup;
- }
-
- signLen = sizeof(sign);
- crv = pFunctionList->C_Sign(hRwSession, (CK_BYTE *)digest, digestLen,
- sign, &signLen);
- if (crv != CKR_OK) {
- pk11error("C_Sign failed", crv);
- goto cleanup;
- }
-
- if (signLen != sizeof(sign)) {
- PR_fprintf(PR_STDERR, "signLen has incorrect length %lu "
- "it should be %lu \n",
- signLen, sizeof(sign));
- goto cleanup;
- }
-
- if (verify) {
- crv = pFunctionList->C_VerifyInit(hRwSession, &signMech, hDSApubKey);
- if (crv != CKR_OK) {
- pk11error("C_VerifyInit failed", crv);
- goto cleanup;
- }
- crv = pFunctionList->C_Verify(hRwSession, digest, digestLen,
- sign, signLen);
- if (crv != CKR_OK) {
- pk11error("C_Verify failed", crv);
- goto cleanup;
- }
- }
-
if (verbose) {
- int j;
- PR_fprintf(PR_STDERR, "Library File: %s %d bytes\n", input_file, count);
+ PR_fprintf(PR_STDERR, "Library File: %s\n", input_file);
PR_fprintf(PR_STDERR, "Check File: %s\n", output_file);
#ifdef USES_LINKS
if (link_file) {
PR_fprintf(PR_STDERR, "Link: %s\n", link_file);
}
#endif
- PR_fprintf(PR_STDERR, " hash: %lu bytes\n", digestLen);
-#define STEP 10
- for (i = 0; i < (int)digestLen; i += STEP) {
- PR_fprintf(PR_STDERR, " ");
- for (j = 0; j < STEP && (i + j) < (int)digestLen; j++) {
- PR_fprintf(PR_STDERR, " %02x", digest[i + j]);
- }
- PR_fprintf(PR_STDERR, "\n");
- }
- PR_fprintf(PR_STDERR, " signature: %lu bytes\n", signLen);
- for (i = 0; i < (int)signLen; i += STEP) {
- PR_fprintf(PR_STDERR, " ");
- for (j = 0; j < STEP && (i + j) < (int)signLen; j++) {
- PR_fprintf(PR_STDERR, " %02x", sign[i + j]);
- }
- PR_fprintf(PR_STDERR, "\n");
- }
}
/* open the target signature file */
- fd = PR_Open(output_file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666);
- if (fd == NULL) {
+ ofd = PR_Open(output_file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666);
+ if (ofd == NULL) {
lperror(output_file);
goto cleanup;
}
- /*
- * we write the key out in a straight binary format because very
- * low level libraries need to read an parse this file. Ideally we should
- * just derEncode the public key (which would be pretty simple, and be
- * more general), but then we'd need to link the ASN.1 decoder with the
- * freebl libraries.
- */
-
- file_buf[0] = NSS_SIGN_CHK_MAGIC1;
- file_buf[1] = NSS_SIGN_CHK_MAGIC2;
- file_buf[2] = NSS_SIGN_CHK_MAJOR_VERSION;
- file_buf[3] = NSS_SIGN_CHK_MINOR_VERSION;
- encodeInt(&file_buf[4], 12); /* offset to data start */
- encodeInt(&file_buf[8], CKK_DSA);
- bytesWritten = PR_Write(fd, file_buf, 12);
- if (bytesWritten != 12) {
+ if (useDSA) {
+ crv = shlibSignDSA(pFunctionList, pSlotList[slotIndex], hRwSession,
+ keySize, ifd, ofd, hash);
+ } else {
+ crv = shlibSignHMAC(pFunctionList, pSlotList[slotIndex], hRwSession,
+ keySize, ifd, ofd, hash);
+ }
+ if (crv == CKR_INTERNAL_OUT_FAILURE) {
lperror(output_file);
- goto cleanup;
}
-
- /* get DSA Public KeyValue */
- memset(dsaPubKey, 0, sizeof(dsaPubKey));
- dsaPubKeyValue.type = CKA_VALUE;
- dsaPubKeyValue.pValue = (CK_VOID_PTR)&dsaPubKey;
- dsaPubKeyValue.ulValueLen = sizeof(dsaPubKey);
-
- crv = pFunctionList->C_GetAttributeValue(hRwSession, hDSApubKey,
- &dsaPubKeyValue, 1);
- if (crv != CKR_OK && crv != CKR_ATTRIBUTE_TYPE_INVALID) {
- pk11error("C_GetAttributeValue failed", crv);
- goto cleanup;
+ if (crv == CKR_INTERNAL_IN_FAILURE) {
+ lperror(input_file);
}
- /* CKA_PRIME */
- rv = writeItem(fd, dsaPubKeyTemplate[0].pValue,
- dsaPubKeyTemplate[0].ulValueLen, output_file);
- if (rv != PR_SUCCESS)
- goto cleanup;
- /* CKA_SUBPRIME */
- rv = writeItem(fd, dsaPubKeyTemplate[1].pValue,
- dsaPubKeyTemplate[1].ulValueLen, output_file);
- if (rv != PR_SUCCESS)
- goto cleanup;
- /* CKA_BASE */
- rv = writeItem(fd, dsaPubKeyTemplate[2].pValue,
- dsaPubKeyTemplate[2].ulValueLen, output_file);
- if (rv != PR_SUCCESS)
- goto cleanup;
- /* DSA Public Key value */
- rv = writeItem(fd, dsaPubKeyValue.pValue,
- dsaPubKeyValue.ulValueLen, output_file);
- if (rv != PR_SUCCESS)
- goto cleanup;
- /* DSA SIGNATURE */
- rv = writeItem(fd, &sign, signLen, output_file);
- if (rv != PR_SUCCESS)
- goto cleanup;
- PR_Close(fd);
+ PR_Close(ofd);
+ ofd = NULL;
+ /* close the input_File */
+ PR_Close(ifd);
+ ifd = NULL;
#ifdef USES_LINKS
if (link_file) {
@@ -1286,7 +1592,6 @@ main(int argc, char **argv)
}
}
#endif
-
successful = PR_TRUE;
cleanup:
@@ -1318,6 +1623,12 @@ cleanup:
PL_strfree(link_file);
}
#endif
+ if (ifd) {
+ PR_Close(ifd);
+ }
+ if (ofd) {
+ PR_Close(ofd);
+ }
disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
if (!disableUnload && lib) {
diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile
index 228549ede..a15db872f 100644
--- a/lib/freebl/Makefile
+++ b/lib/freebl/Makefile
@@ -101,6 +101,9 @@ endif
ifdef NSS_NO_INIT_SUPPORT
DEFINES += -DNSS_NO_INIT_SUPPORT
endif
+ifdef NSS_STRICT_INTEGRITY
+ DEFINES += -DNSS_STRICT_INTEGRITY_
+endif
ifdef FREEBL_PRELINK_COMMAND
DEFINES +=-DFREEBL_PRELINK_COMMAND=\"$(FREEBL_PRELINK_COMMAND)\"
diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c
index 22f97810f..e950e0865 100644
--- a/lib/freebl/nsslowhash.c
+++ b/lib/freebl/nsslowhash.c
@@ -6,6 +6,7 @@
#include "stubs.h"
#endif
#include "prtypes.h"
+#include "prenv.h"
#include "secerr.h"
#include "blapi.h"
#include "hasht.h"
@@ -30,6 +31,12 @@ nsslow_GetFIPSEnabled(void)
FILE *f;
char d;
size_t size;
+ const char *env;
+
+ env = PR_GetEnvSecure("NSS_FIPS");
+ if (env && (*env == 'y' || *env == 'f' || *env == '1' || *env == 't')) {
+ return 1;
+ }
f = fopen("/proc/sys/crypto/fips_enabled", "r");
if (!f)
diff --git a/lib/freebl/shsign.h b/lib/freebl/shsign.h
index 590c0e6b3..d1a595a39 100644
--- a/lib/freebl/shsign.h
+++ b/lib/freebl/shsign.h
@@ -8,7 +8,19 @@
#define SGN_SUFFIX ".chk"
#define NSS_SIGN_CHK_MAGIC1 0xf1
#define NSS_SIGN_CHK_MAGIC2 0xc5
-#define NSS_SIGN_CHK_MAJOR_VERSION 0x01
-#define NSS_SIGN_CHK_MINOR_VERSION 0x02
+/* new hmac based signatures */
+#define NSS_SIGN_CHK_MAJOR_VERSION 0x02
+#define NSS_SIGN_CHK_MINOR_VERSION 0x01
+#define NSS_SIGN_CHK_TYPE_FLAGS 0xff000000
+#define NSS_SIGN_CHK_FLAG_HMAC 0x80000000
+typedef struct NSSSignChkHeaderStr NSSSignChkHeader;
+struct NSSSignChkHeaderStr {
+ unsigned char magic1;
+ unsigned char magic2;
+ unsigned char majorVersion;
+ unsigned char minorVersion;
+ unsigned char offset[4];
+ unsigned char type[4];
+};
#endif /* _SHSIGN_H_ */
diff --git a/lib/freebl/shvfy.c b/lib/freebl/shvfy.c
index 0428bf6c0..e713f64b0 100644
--- a/lib/freebl/shvfy.c
+++ b/lib/freebl/shvfy.c
@@ -19,6 +19,7 @@
#include "pqg.h"
#include "blapii.h"
#include "secitem.h"
+#include "pkcs11t.h"
#ifndef NSS_FIPS_DISABLED
@@ -321,228 +322,315 @@ BLAPI_SHVerifyFile(const char *shName)
return blapi_SHVerifyFile(shName, PR_FALSE);
}
+#ifndef NSS_STRICT_INTEGRITY
+/* This allows checks with old shlibsign .chk files. If NSS_STRICT_INTEGRITY
+ * is set, we don't accept DSA */
static PRBool
-blapi_SHVerifyFile(const char *shName, PRBool self)
+blapi_SHVerifyDSACheck(PRFileDesc *shFD, const SECHashObject *hashObj,
+ DSAPublicKey *key, const SECItem *signature)
{
- char *checkName = NULL;
- PRFileDesc *checkFD = NULL;
- PRFileDesc *shFD = NULL;
void *hashcx = NULL;
- const SECHashObject *hashObj = NULL;
- SECItem signature = { 0, NULL, 0 };
SECItem hash;
- int bytesRead, offset;
- SECStatus rv;
- DSAPublicKey key;
- int count;
- (void)count; /* Suppress unused var warning (Bug 1738028) */
-#ifdef FREEBL_USE_PRELINK
- int pid = 0;
-#endif
-
- PRBool result = PR_FALSE; /* if anything goes wrong,
- * the signature does not verify */
- unsigned char buf[4096];
+ int bytesRead;
unsigned char hashBuf[HASH_LENGTH_MAX];
+ unsigned char buf[4096];
+ SECStatus rv;
- PORT_Memset(&key, 0, sizeof(key));
+ hash.type = siBuffer;
hash.data = hashBuf;
hash.len = sizeof(hashBuf);
- /* If our integrity check was never ran or failed, fail any other
- * integrity checks to prevent any token going into FIPS mode. */
- if (!self && (BL_FIPSEntryOK(PR_FALSE) != SECSuccess)) {
+ /* hash our library file */
+ hashcx = hashObj->create();
+ if (hashcx == NULL) {
return PR_FALSE;
}
+ hashObj->begin(hashcx);
- if (!shName) {
- goto loser;
+ while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) {
+ hashObj->update(hashcx, buf, bytesRead);
}
+ hashObj->end(hashcx, hash.data, &hash.len, hash.len);
+ hashObj->destroy(hashcx, PR_TRUE);
- /* figure out the name of our check file */
- checkName = mkCheckFileName(shName);
- if (!checkName) {
- goto loser;
- }
+ /* verify the hash against the check file */
+ rv = DSA_VerifyDigest(key, signature, &hash);
+ PORT_Memset(hashBuf, 0, sizeof hashBuf);
+ return (rv == SECSuccess) ? PR_TRUE : PR_FALSE;
+}
+#endif
- /* open the check File */
- checkFD = PR_Open(checkName, PR_RDONLY, 0);
- if (checkFD == NULL) {
-#ifdef DEBUG_SHVERIFY
- fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n",
- checkName, (int)PR_GetError(), (int)PR_GetOSError());
-#endif /* DEBUG_SHVERIFY */
- goto loser;
+#ifdef NSS_STRICT_INTEGRITY
+/* don't allow MD2, MD5, SHA1 or SHA224 as your integrity hash */
+static PRBool
+blapi_HashAllowed(SECHashObject *hashObj)
+{
+ switch (hashObj->type) {
+ case HASH_AlgSHA256:
+ case HASH_AlgSHA384:
+ case HASH_AlgSHA512:
+ return PR_TRUE;
+ default:
+ break;
}
+ return PR_FALSE;
+}
+#endif
- /* read and Verify the headerthe header */
- bytesRead = PR_Read(checkFD, buf, 12);
- if (bytesRead != 12) {
- goto loser;
- }
- if ((buf[0] != NSS_SIGN_CHK_MAGIC1) || (buf[1] != NSS_SIGN_CHK_MAGIC2)) {
- goto loser;
- }
- if ((buf[2] != NSS_SIGN_CHK_MAJOR_VERSION) ||
- (buf[3] < NSS_SIGN_CHK_MINOR_VERSION)) {
- goto loser;
- }
-#ifdef notdef
- if (decodeInt(&buf[8]) != CKK_DSA) {
- goto loser;
- }
+static PRBool
+blapi_SHVerifyHMACCheck(PRFileDesc *shFD, const SECHashObject *hashObj,
+ const SECItem *key, const SECItem *signature)
+{
+ HMACContext *hmaccx = NULL;
+ SECItem hash;
+ int bytesRead;
+ unsigned char hashBuf[HASH_LENGTH_MAX];
+ unsigned char buf[4096];
+ SECStatus rv;
+ PRBool result = PR_FALSE;
+
+#ifdef NSS_STRICT_INTEGRITY
+ if (!blapi_HashAllowed(hashObj)) {
+ return PR_FALSE;
#endif
- /* seek past any future header extensions */
- offset = decodeInt(&buf[4]);
- if (PR_Seek(checkFD, offset, PR_SEEK_SET) < 0) {
- goto loser;
- }
+ hash.type = siBuffer;
+ hash.data = hashBuf;
+ hash.len = hashObj->length;
- /* read the key */
- rv = readItem(checkFD, &key.params.prime);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = readItem(checkFD, &key.params.subPrime);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = readItem(checkFD, &key.params.base);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = readItem(checkFD, &key.publicValue);
- if (rv != SECSuccess) {
- goto loser;
- }
- /* read the siganture */
- rv = readItem(checkFD, &signature);
- if (rv != SECSuccess) {
- goto loser;
- }
+ /* create an hmac for the library file */
+ hmaccx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
+ if (hmaccx == NULL) {
+ return PR_FALSE;
+ }
+ HMAC_Begin(hmaccx);
+
+ while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) {
+ HMAC_Update(hmaccx, buf, bytesRead);
+ }
+ rv = HMAC_Finish(hmaccx, hash.data, &hash.len, hash.len);
- /* done with the check file */
- PR_Close(checkFD);
- checkFD = NULL;
+ HMAC_Destroy(hmaccx, PR_TRUE);
- hashObj = HASH_GetRawHashObject(PQG_GetHashType(&key.params));
- if (hashObj == NULL) {
- goto loser;
+ /* verify the hmac against the check file */
+ if (rv == SECSuccess) {
+ result = SECITEM_ItemsAreEqual(signature, &hash);
+ }
+ PORT_Memset(hashBuf, 0, sizeof hashBuf);
+ return result;
}
+ static PRBool
+ blapi_SHVerifyFile(const char *shName, PRBool self)
+ {
+ char *checkName = NULL;
+ PRFileDesc *checkFD = NULL;
+ PRFileDesc *shFD = NULL;
+ const SECHashObject *hashObj = NULL;
+ SECItem signature = { 0, NULL, 0 };
+ int bytesRead, offset, type;
+ SECStatus rv;
+ SECItem hmacKey = { 0, NULL, 0 };
+#ifdef FREEBL_USE_PRELINK
+ int pid = 0;
+#endif
+ PRBool result = PR_FALSE; /* if anything goes wrong,
+ * the signature does not verify */
+ NSSSignChkHeader header;
+#ifndef NSS_STRICT_INTEGRITY
+ DSAPublicKey key;
+
+ PORT_Memset(&key, 0, sizeof(key));
+#endif
+
+ /* If our integrity check was never ran or failed, fail any other
+ * integrity checks to prevent any token going into FIPS mode. */
+ if (!self && (BL_FIPSEntryOK(PR_FALSE) != SECSuccess)) {
+ return PR_FALSE;
+ }
+
+ if (!shName) {
+ goto loser;
+ }
+
+ /* figure out the name of our check file */
+ checkName = mkCheckFileName(shName);
+ if (!checkName) {
+ goto loser;
+ }
+
+ /* open the check File */
+ checkFD = PR_Open(checkName, PR_RDONLY, 0);
+ if (checkFD == NULL) {
+#ifdef DEBUG_SHVERIFY
+ fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n",
+ checkName, (int)PR_GetError(), (int)PR_GetOSError());
+#endif /* DEBUG_SHVERIFY */
+ goto loser;
+ }
+
+ /* read and Verify the headerthe header */
+ bytesRead = PR_Read(checkFD, &header, sizeof(header));
+ if (bytesRead != sizeof(header)) {
+ goto loser;
+ }
+ if ((header.magic1 != NSS_SIGN_CHK_MAGIC1) ||
+ (header.magic2 != NSS_SIGN_CHK_MAGIC2)) {
+ goto loser;
+ }
+ /* we've bumped the version number so that newly signed .check
+ * files will fail nicely on old version of nss */
+ if (header.majorVersion > NSS_SIGN_CHK_MAJOR_VERSION) {
+ goto loser;
+ }
+ if (header.minorVersion < NSS_SIGN_CHK_MINOR_VERSION) {
+ goto loser;
+ }
+ type = decodeInt(header.type);
+
+ /* seek past any future header extensions */
+ offset = decodeInt(header.offset);
+ if (PR_Seek(checkFD, offset, PR_SEEK_SET) < 0) {
+ goto loser;
+ }
+
+ switch (type) {
+ case CKK_DSA:
+#ifdef NSS_STRICT_INTEGRITY
+ goto loser;
+#else
+ /* accept old dsa check files if NSS_STRICT_INTEGRITY is not set*/
+ /* read the key */
+ rv = readItem(checkFD, &key.params.prime);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = readItem(checkFD, &key.params.subPrime);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = readItem(checkFD, &key.params.base);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = readItem(checkFD, &key.publicValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* read the signature */
+ rv = readItem(checkFD, &signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ hashObj = HASH_GetRawHashObject(PQG_GetHashType(&key.params));
+ break;
+#endif
+ default:
+ if ((type & NSS_SIGN_CHK_TYPE_FLAGS) != NSS_SIGN_CHK_FLAG_HMAC) {
+ goto loser;
+ }
+ /* read the HMAC Key */
+ rv = readItem(checkFD, &hmacKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* read the siganture */
+ rv = readItem(checkFD, &signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ hashObj = HASH_GetRawHashObject(type & ~NSS_SIGN_CHK_TYPE_FLAGS);
+ }
+
+ /* done with the check file */
+ PR_Close(checkFD);
+ checkFD = NULL;
+
+ if (hashObj == NULL) {
+ goto loser;
+ }
+
/* open our library file */
#ifdef FREEBL_USE_PRELINK
- shFD = bl_OpenUnPrelink(shName, &pid);
+ shFD = bl_OpenUnPrelink(shName, &pid);
#else
shFD = PR_Open(shName, PR_RDONLY, 0);
#endif
- if (shFD == NULL) {
+ if (shFD == NULL) {
#ifdef DEBUG_SHVERIFY
- fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n",
- shName, (int)PR_GetError(), (int)PR_GetOSError());
+ fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n",
+ shName, (int)PR_GetError(), (int)PR_GetOSError());
#endif /* DEBUG_SHVERIFY */
- goto loser;
- }
+ goto loser;
+ }
- /* hash our library file with SHA1 */
- hashcx = hashObj->create();
- if (hashcx == NULL) {
- goto loser;
- }
- hashObj->begin(hashcx);
+ switch (type) {
+ case CKK_DSA:
+#ifndef NSS_STRICT_INTEGRITY
+ result = blapi_SHVerifyDSACheck(shFD, hashObj, &key, &signature);
+#endif
+ break;
+ default:
+ if ((type & NSS_SIGN_CHK_TYPE_FLAGS) != NSS_SIGN_CHK_FLAG_HMAC) {
+ break;
+ }
+ result = blapi_SHVerifyHMACCheck(shFD, hashObj, &hmacKey, &signature);
+ break;
+ }
- count = 0;
- while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) {
- hashObj->update(hashcx, buf, bytesRead);
- count += bytesRead;
- }
#ifdef FREEBL_USE_PRELINK
- bl_CloseUnPrelink(shFD, pid);
+ bl_CloseUnPrelink(shFD, pid);
#else
PR_Close(shFD);
#endif
- shFD = NULL;
-
- hashObj->end(hashcx, hash.data, &hash.len, hash.len);
+ shFD = NULL;
- /* verify the hash against the check file */
- if (DSA_VerifyDigest(&key, &signature, &hash) == SECSuccess) {
- result = PR_TRUE;
- }
-#ifdef DEBUG_SHVERIFY
- {
- int i, j;
- fprintf(stderr, "File %s: %d bytes\n", shName, count);
- fprintf(stderr, " hash: %d bytes\n", hash.len);
-#define STEP 10
- for (i = 0; i < hash.len; i += STEP) {
- fprintf(stderr, " ");
- for (j = 0; j < STEP && (i + j) < hash.len; j++) {
- fprintf(stderr, " %02x", hash.data[i + j]);
- }
- fprintf(stderr, "\n");
+ loser:
+ PORT_Memset(&header, 0, sizeof header);
+ if (checkName != NULL) {
+ PORT_Free(checkName);
}
- fprintf(stderr, " signature: %d bytes\n", signature.len);
- for (i = 0; i < signature.len; i += STEP) {
- fprintf(stderr, " ");
- for (j = 0; j < STEP && (i + j) < signature.len; j++) {
- fprintf(stderr, " %02x", signature.data[i + j]);
- }
- fprintf(stderr, "\n");
+ if (checkFD != NULL) {
+ PR_Close(checkFD);
}
- fprintf(stderr, "Verified : %s\n", result ? "TRUE" : "FALSE");
- }
-#endif /* DEBUG_SHVERIFY */
-
-loser:
- PORT_Memset(buf, 0, sizeof buf);
- PORT_Memset(hashBuf, 0, sizeof hashBuf);
- if (checkName != NULL) {
- PORT_Free(checkName);
- }
- if (checkFD != NULL) {
- PR_Close(checkFD);
- }
- if (shFD != NULL) {
- PR_Close(shFD);
- }
- if (hashcx != NULL) {
- if (hashObj) {
- hashObj->destroy(hashcx, PR_TRUE);
+ if (shFD != NULL) {
+ PR_Close(shFD);
}
- }
- if (signature.data != NULL) {
- SECITEM_ZfreeItem(&signature, PR_FALSE);
- }
- if (key.params.prime.data != NULL) {
- SECITEM_ZfreeItem(&key.params.prime, PR_FALSE);
- }
- if (key.params.subPrime.data != NULL) {
- SECITEM_ZfreeItem(&key.params.subPrime, PR_FALSE);
- }
- if (key.params.base.data != NULL) {
- SECITEM_ZfreeItem(&key.params.base, PR_FALSE);
- }
- if (key.publicValue.data != NULL) {
- SECITEM_ZfreeItem(&key.publicValue, PR_FALSE);
+ if (hmacKey.data != NULL) {
+ SECITEM_ZfreeItem(&hmacKey, PR_FALSE);
+ }
+ if (signature.data != NULL) {
+ SECITEM_ZfreeItem(&signature, PR_FALSE);
+ }
+#ifndef NSS_STRICT_INTEGRITY
+ if (key.params.prime.data != NULL) {
+ SECITEM_ZfreeItem(&key.params.prime, PR_FALSE);
+ }
+ if (key.params.subPrime.data != NULL) {
+ SECITEM_ZfreeItem(&key.params.subPrime, PR_FALSE);
+ }
+ if (key.params.base.data != NULL) {
+ SECITEM_ZfreeItem(&key.params.base, PR_FALSE);
+ }
+ if (key.publicValue.data != NULL) {
+ SECITEM_ZfreeItem(&key.publicValue, PR_FALSE);
+ }
+#endif
+ return result;
}
- return result;
-}
-
-PRBool
-BLAPI_VerifySelf(const char *name)
-{
- if (name == NULL) {
- /*
+ PRBool
+ BLAPI_VerifySelf(const char *name)
+ {
+ if (name == NULL) {
+ /*
* If name is NULL, freebl is statically linked into softoken.
* softoken will call BLAPI_SHVerify next to verify itself.
*/
- return PR_TRUE;
+ return PR_TRUE;
+ }
+ return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE);
}
- return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE);
-}
#else /* NSS_FIPS_DISABLED */
diff --git a/lib/freebl/stubs.c b/lib/freebl/stubs.c
index 122e5b251..82b5b2e78 100644
--- a/lib/freebl/stubs.c
+++ b/lib/freebl/stubs.c
@@ -170,6 +170,7 @@ STUB_DECLARE(char *, PR_GetEnvSecure, (const char *));
STUB_DECLARE(SECItem *, SECITEM_AllocItem_Util, (PLArenaPool * arena, SECItem *item, unsigned int len));
STUB_DECLARE(SECComparison, SECITEM_CompareItem_Util, (const SECItem *a, const SECItem *b));
+STUB_DECLARE(PRBool, SECITEM_ItemsAreEqual_Util, (const SECItem *a, const SECItem *b));
STUB_DECLARE(SECStatus, SECITEM_CopyItem_Util, (PLArenaPool * arena, SECItem *to, const SECItem *from));
STUB_DECLARE(void, SECITEM_FreeItem_Util, (SECItem * zap, PRBool freeit));
STUB_DECLARE(void, SECITEM_ZfreeItem_Util, (SECItem * zap, PRBool freeit));
@@ -573,8 +574,11 @@ extern char *
PR_GetEnvSecure_stub(const char *var)
{
STUB_SAFE_CALL1(PR_GetEnvSecure, var);
- abort();
- return NULL;
+#ifdef __USE_GNU
+ return secure_getenv(var);
+#else
+ return getenv(var);
+#endif
}
extern void
@@ -622,6 +626,30 @@ SECITEM_CompareItem_stub(const SECItem *a, const SECItem *b)
return SECEqual;
}
+extern PRBool
+SECITEM_ItemsAreEqual_stub(const SECItem *a, const SECItem *b)
+{
+ STUB_SAFE_CALL2(SECITEM_ItemsAreEqual_Util, a, b);
+ /* two nulls are equal */
+ if (!a && !b) {
+ return PR_TRUE;
+ }
+ /* only one NULL is not equal */
+ if (!a || !b) {
+ return PR_FALSE;
+ }
+ /* we know both secitems have been set, now make sure the lengths
+ * are equal */
+ if (a->len != b->len) {
+ return PR_FALSE;
+ }
+ /* lengths are equal, safe to verify the data */
+ if (PORT_Memcmp(a->data, b->data, b->len) != 0) {
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
extern SECStatus
SECITEM_CopyItem_stub(PLArenaPool *arena, SECItem *to, const SECItem *from)
{
@@ -646,7 +674,16 @@ extern void
SECITEM_ZfreeItem_stub(SECItem *zap, PRBool freeit)
{
STUB_SAFE_CALL2(SECITEM_ZfreeItem_Util, zap, freeit);
- abort();
+ if (zap) {
+ if (zap->data) {
+ PORT_Memset(zap->data, 0, zap->len);
+ PORT_Free_stub(zap->data);
+ }
+ PORT_Memset(zap, 0, sizeof(SECItem));
+ if (freeit) {
+ PORT_Free_stub(zap);
+ }
+ }
}
extern int
diff --git a/lib/freebl/stubs.h b/lib/freebl/stubs.h
index e63cf7a5d..e6d9ed03a 100644
--- a/lib/freebl/stubs.h
+++ b/lib/freebl/stubs.h
@@ -35,6 +35,7 @@
#define SECITEM_AllocItem SECITEM_AllocItem_stub
#define SECITEM_CompareItem SECITEM_CompareItem_stub
+#define SECITEM_ItemsAreEqual SECITEM_ItemsAreEqual_stub
#define SECITEM_CopyItem SECITEM_CopyItem_stub
#define SECITEM_FreeItem SECITEM_FreeItem_stub
#define SECITEM_ZfreeItem SECITEM_ZfreeItem_stub
diff --git a/tests/lowhash/lowhash.sh b/tests/lowhash/lowhash.sh
index 6de255be4..6de255be4 100644..100755
--- a/tests/lowhash/lowhash.sh
+++ b/tests/lowhash/lowhash.sh