commit 9c1979adf57603ccfc58e3c0655f1e74ee524ca8
Author: Hans Petter Jansson <hpj@cl.no>
Date:   Fri Apr 17 16:02:23 2020 +0200

    Add CKM_(EC)DSA_SHAxxx mechs.

diff --git a/nss/cmd/lib/pk11table.c b/nss/cmd/lib/pk11table.c
index ec5d889..d7b60e2 100644
--- a/nss/cmd/lib/pk11table.c
+++ b/nss/cmd/lib/pk11table.c
@@ -274,6 +274,10 @@ const Constant _consts[] = {
     mkEntry(CKM_DSA_KEY_PAIR_GEN, Mechanism),
     mkEntry(CKM_DSA, Mechanism),
     mkEntry(CKM_DSA_SHA1, Mechanism),
+    mkEntry(CKM_DSA_SHA224, Mechanism),
+    mkEntry(CKM_DSA_SHA256, Mechanism),
+    mkEntry(CKM_DSA_SHA384, Mechanism),
+    mkEntry(CKM_DSA_SHA512, Mechanism),
     mkEntry(CKM_DH_PKCS_KEY_PAIR_GEN, Mechanism),
     mkEntry(CKM_DH_PKCS_DERIVE, Mechanism),
     mkEntry(CKM_X9_42_DH_DERIVE, Mechanism),
@@ -439,6 +443,10 @@ const Constant _consts[] = {
     mkEntry(CKM_EC_KEY_PAIR_GEN, Mechanism),
     mkEntry(CKM_ECDSA, Mechanism),
     mkEntry(CKM_ECDSA_SHA1, Mechanism),
+    mkEntry(CKM_ECDSA_SHA224, Mechanism),
+    mkEntry(CKM_ECDSA_SHA256, Mechanism),
+    mkEntry(CKM_ECDSA_SHA384, Mechanism),
+    mkEntry(CKM_ECDSA_SHA512, Mechanism),
     mkEntry(CKM_ECDH1_DERIVE, Mechanism),
     mkEntry(CKM_ECDH1_COFACTOR_DERIVE, Mechanism),
     mkEntry(CKM_ECMQV_DERIVE, Mechanism),
diff --git a/nss/lib/pk11wrap/debug_module.c b/nss/lib/pk11wrap/debug_module.c
index 59b89c3..74ed3c7 100644
--- a/nss/lib/pk11wrap/debug_module.c
+++ b/nss/lib/pk11wrap/debug_module.c
@@ -424,10 +424,18 @@ print_mechanism(CK_MECHANISM_PTR m)
         CASE(CKM_DSA_KEY_PAIR_GEN);
         CASE(CKM_DSA_PARAMETER_GEN);
         CASE(CKM_DSA_SHA1);
+        CASE(CKM_DSA_SHA224);
+        CASE(CKM_DSA_SHA256);
+        CASE(CKM_DSA_SHA384);
+        CASE(CKM_DSA_SHA512);
         CASE(CKM_ECDH1_COFACTOR_DERIVE);
         CASE(CKM_ECDH1_DERIVE);
         CASE(CKM_ECDSA);
         CASE(CKM_ECDSA_SHA1);
+        CASE(CKM_ECDSA_SHA224);
+        CASE(CKM_ECDSA_SHA256);
+        CASE(CKM_ECDSA_SHA384);
+        CASE(CKM_ECDSA_SHA512);
         CASE(CKM_ECMQV_DERIVE);
         CASE(CKM_EC_KEY_PAIR_GEN); /* also CASE(CKM_ECDSA_KEY_PAIR_GEN); */
         CASE(CKM_EXTRACT_KEY_FROM_KEY);
diff --git a/nss/lib/pk11wrap/pk11mech.c b/nss/lib/pk11wrap/pk11mech.c
index cfbe45b..c7f5272 100644
--- a/nss/lib/pk11wrap/pk11mech.c
+++ b/nss/lib/pk11wrap/pk11mech.c
@@ -366,6 +366,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len)
             return CKK_RSA;
         case CKM_DSA:
         case CKM_DSA_SHA1:
+        case CKM_DSA_SHA224:
+        case CKM_DSA_SHA256:
+        case CKM_DSA_SHA384:
+        case CKM_DSA_SHA512:
         case CKM_DSA_KEY_PAIR_GEN:
             return CKK_DSA;
         case CKM_DH_PKCS_DERIVE:
@@ -376,6 +380,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len)
             return CKK_KEA;
         case CKM_ECDSA:
         case CKM_ECDSA_SHA1:
+        case CKM_ECDSA_SHA224:
+        case CKM_ECDSA_SHA256:
+        case CKM_ECDSA_SHA384:
+        case CKM_ECDSA_SHA512:
         case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
         case CKM_ECDH1_DERIVE:
             return CKK_EC; /* CKK_ECDSA is deprecated */
diff --git a/nss/lib/softoken/pkcs11.c b/nss/lib/softoken/pkcs11.c
index 05e3ac1..79f1a50 100644
--- a/nss/lib/softoken/pkcs11.c
+++ b/nss/lib/softoken/pkcs11.c
@@ -278,6 +278,10 @@ static const struct mechanismList mechanisms[] = {
     { CKM_DSA, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
     { CKM_DSA_PARAMETER_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE }, PR_TRUE },
     { CKM_DSA_SHA1, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
+    { CKM_DSA_SHA224, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
+    { CKM_DSA_SHA256, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
+    { CKM_DSA_SHA384, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
+    { CKM_DSA_SHA512, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
     /* -------------------- Diffie Hellman Operations --------------------- */
     /* no diffie hellman yet */
     { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_MIN_P_BITS, DH_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
@@ -287,6 +291,10 @@ static const struct mechanismList mechanisms[] = {
     { CKM_ECDH1_DERIVE, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_DERIVE | CKF_EC_BPNU }, PR_TRUE },
     { CKM_ECDSA, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
     { CKM_ECDSA_SHA1, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
+    { CKM_ECDSA_SHA224, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
+    { CKM_ECDSA_SHA256, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
+    { CKM_ECDSA_SHA384, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
+    { CKM_ECDSA_SHA512, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
     /* ------------------------- RC2 Operations --------------------------- */
     { CKM_RC2_KEY_GEN, { 1, 128, CKF_GENERATE }, PR_TRUE },
     { CKM_RC2_ECB, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c
index d7307cd..dc8819b 100644
--- a/nss/lib/softoken/pkcs11c.c
+++ b/nss/lib/softoken/pkcs11c.c
@@ -2473,6 +2473,36 @@ sftk_RSAHashSign(SFTKHashSignInfo *info, unsigned char *sig,
                         hash, hashLen);
 }
 
+static SECStatus
+sftk_DSAHashSign(SFTKHashSignInfo *info, unsigned char *sig,
+                 unsigned int *sigLen, unsigned int maxLen,
+                 const unsigned char *hash, unsigned int hashLen)
+{
+    PORT_Assert(info->key->keyType == NSSLOWKEYDSAKey);
+    if (info->key->keyType != NSSLOWKEYDSAKey) {
+        PORT_SetError(SEC_ERROR_INVALID_KEY);
+        return SECFailure;
+    }
+
+    return DSA_HashSign(info->hashOid, info->key, sig, sigLen, maxLen,
+                        hash, hashLen);
+}
+
+static SECStatus
+sftk_ECDSAHashSign(SFTKHashSignInfo *info, unsigned char *sig,
+                   unsigned int *sigLen, unsigned int maxLen,
+                   const unsigned char *hash, unsigned int hashLen)
+{
+    PORT_Assert(info->key->keyType == NSSLOWKEYECKey);
+    if (info->key->keyType != NSSLOWKEYECKey) {
+        PORT_SetError(SEC_ERROR_INVALID_KEY);
+        return SECFailure;
+    }
+
+    return ECDSA_HashSign(info->hashOid, info->key, sig, sigLen, maxLen,
+                          hash, hashLen);
+}
+
 /* XXX Old template; want to expunge it eventually. */
 static DERTemplate SECAlgorithmIDTemplate[] = {
     { DER_SEQUENCE,
@@ -2635,7 +2665,7 @@ nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen,
 static SECStatus
 nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
                   unsigned int *sigLen, unsigned int maxSigLen,
-                  void *dataBuf, unsigned int dataLen)
+                  const void *dataBuf, unsigned int dataLen)
 {
     SECItem signature, digest;
     SECStatus rv;
@@ -2653,6 +2683,22 @@ nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
     return rv;
 }
 
+SECStatus
+DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
+             unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
+             const unsigned char *hash, unsigned int hashLen)
+{
+    SECStatus rv;
+
+    rv = nsc_DSA_Sign_Stub(key, sig, sigLen, maxLen, hash, hashLen);
+
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+        sftk_fatalError = PR_TRUE;
+    }
+
+    return rv;
+}
+
 static SECStatus
 nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
                     void *dataBuf, unsigned int dataLen)
@@ -2670,7 +2716,7 @@ nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
 static SECStatus
 nsc_ECDSASignStub(void *ctx, void *sigBuf,
                   unsigned int *sigLen, unsigned int maxSigLen,
-                  void *dataBuf, unsigned int dataLen)
+                  const void *dataBuf, unsigned int dataLen)
 {
     SECItem signature, digest;
     SECStatus rv;
@@ -2688,6 +2734,22 @@ nsc_ECDSASignStub(void *ctx, void *sigBuf,
     return rv;
 }
 
+SECStatus
+ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
+               unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
+               const unsigned char *hash, unsigned int hashLen)
+{
+    SECStatus rv;
+
+    rv = nsc_ECDSASignStub(key, sig, sigLen, maxLen, hash, hashLen);
+
+    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+        sftk_fatalError = PR_TRUE;
+    }
+
+    return rv;
+}
+
 /* NSC_SignInit setups up the signing operations. There are three basic
  * types of signing:
  *      (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
@@ -2757,6 +2819,36 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
         info->hashOid = SEC_OID_##mmm;                  \
         goto finish_rsa;
 
+#define INIT_DSA_SIGN_MECH(mmm)                         \
+    case CKM_DSA_##mmm:                                 \
+        context->multi = PR_TRUE;                       \
+        crv = sftk_doSub##mmm(context);                 \
+        if (crv != CKR_OK)                              \
+            break;                                      \
+        context->update = (SFTKCipher)sftk_DSAHashSign; \
+        info = PORT_New(SFTKHashSignInfo);              \
+        if (info == NULL) {                             \
+            crv = CKR_HOST_MEMORY;                      \
+            break;                                      \
+        }                                               \
+        info->hashOid = SEC_OID_##mmm;                  \
+        goto finish_dsa;
+
+#define INIT_ECDSA_SIGN_MECH(mmm)                         \
+    case CKM_ECDSA_##mmm:                                 \
+        context->multi = PR_TRUE;                         \
+        crv = sftk_doSub##mmm(context);                   \
+        if (crv != CKR_OK)                                \
+            break;                                        \
+        context->update = (SFTKCipher)sftk_ECDSAHashSign; \
+        info = PORT_New(SFTKHashSignInfo);                \
+        if (info == NULL) {                               \
+            crv = CKR_HOST_MEMORY;                        \
+            break;                                        \
+        }                                                 \
+        info->hashOid = SEC_OID_##mmm;                    \
+        goto finish_ecdsa;
+
     switch (pMechanism->mechanism) {
         INIT_RSA_SIGN_MECH(MD5)
         INIT_RSA_SIGN_MECH(MD2)
@@ -2824,13 +2916,15 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
             context->maxLen = nsslowkey_PrivateModulusLen(info->key);
             break;
 
-        case CKM_DSA_SHA1:
-            context->multi = PR_TRUE;
-            crv = sftk_doSubSHA1(context);
-            if (crv != CKR_OK)
-                break;
-        /* fall through */
+        INIT_DSA_SIGN_MECH(SHA1)
+        INIT_DSA_SIGN_MECH(SHA224)
+        INIT_DSA_SIGN_MECH(SHA256)
+        INIT_DSA_SIGN_MECH(SHA384)
+        INIT_DSA_SIGN_MECH(SHA512)
+
         case CKM_DSA:
+            context->update = (SFTKCipher)nsc_DSA_Sign_Stub;
+        finish_dsa:
             if (key_type != CKK_DSA) {
                 crv = CKR_KEY_TYPE_INCONSISTENT;
                 break;
@@ -2839,20 +2933,32 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
             if (privKey == NULL) {
                 break;
             }
-            context->cipherInfo = privKey;
-            context->update = (SFTKCipher)nsc_DSA_Sign_Stub;
-            context->destroy = (privKey == key->objectInfo) ? (SFTKDestroy)sftk_Null : (SFTKDestroy)sftk_FreePrivKey;
-            context->maxLen = DSA_MAX_SIGNATURE_LEN;
 
+            /* OK, info is allocated only if we're doing hash and sign mechanism.
+             * It's necessary to be able to set the correct OID in the final
+             * signature.
+             */
+            if (info) {
+                info->key = privKey;
+                context->cipherInfo = info;
+                context->destroy = (SFTKDestroy)sftk_Space;
+            } else {
+                context->cipherInfo = privKey;
+                context->destroy = (privKey == key->objectInfo) ? (SFTKDestroy)sftk_Null : (SFTKDestroy)sftk_FreePrivKey;
+            }
+
+            context->maxLen = DSA_MAX_SIGNATURE_LEN;
             break;
 
-        case CKM_ECDSA_SHA1:
-            context->multi = PR_TRUE;
-            crv = sftk_doSubSHA1(context);
-            if (crv != CKR_OK)
-                break;
-        /* fall through */
+        INIT_ECDSA_SIGN_MECH(SHA1)
+        INIT_ECDSA_SIGN_MECH(SHA224)
+        INIT_ECDSA_SIGN_MECH(SHA256)
+        INIT_ECDSA_SIGN_MECH(SHA384)
+        INIT_ECDSA_SIGN_MECH(SHA512)
+
         case CKM_ECDSA:
+            context->update = (SFTKCipher)nsc_ECDSASignStub;
+        finish_ecdsa:
             if (key_type != CKK_EC) {
                 crv = CKR_KEY_TYPE_INCONSISTENT;
                 break;
@@ -2862,11 +2968,21 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
                 crv = CKR_HOST_MEMORY;
                 break;
             }
-            context->cipherInfo = privKey;
-            context->update = (SFTKCipher)nsc_ECDSASignStub;
-            context->destroy = (privKey == key->objectInfo) ? (SFTKDestroy)sftk_Null : (SFTKDestroy)sftk_FreePrivKey;
-            context->maxLen = MAX_ECKEY_LEN * 2;
 
+            /* OK, info is allocated only if we're doing hash and sign mechanism.
+             * It's necessary to be able to set the correct OID in the final
+             * signature.
+             */
+            if (info) {
+                info->key = privKey;
+                context->cipherInfo = info;
+                context->destroy = (SFTKDestroy)sftk_Space;
+            } else {
+                context->cipherInfo = privKey;
+                context->destroy = (privKey == key->objectInfo) ? (SFTKDestroy)sftk_Null : (SFTKDestroy)sftk_FreePrivKey;
+            }
+
+            context->maxLen = MAX_ECKEY_LEN * 2;
             break;
 
 #define INIT_HMAC_MECH(mmm)                                               \
@@ -3469,6 +3585,22 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
         info->hashOid = SEC_OID_##mmm;                    \
         goto finish_rsa;
 
+#define INIT_DSA_VFY_MECH(mmm)                            \
+    case CKM_DSA_##mmm:                                   \
+        context->multi = PR_TRUE;                         \
+        crv = sftk_doSub##mmm(context);                   \
+        if (crv != CKR_OK)                                \
+            break;                                        \
+        goto finish_dsa;
+
+#define INIT_ECDSA_VFY_MECH(mmm)                          \
+    case CKM_ECDSA_##mmm:                                 \
+        context->multi = PR_TRUE;                         \
+        crv = sftk_doSub##mmm(context);                   \
+        if (crv != CKR_OK)                                \
+            break;                                        \
+        goto finish_ecdsa;
+
     switch (pMechanism->mechanism) {
         INIT_RSA_VFY_MECH(MD5)
         INIT_RSA_VFY_MECH(MD2)
@@ -3533,13 +3665,15 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
             context->destroy = (SFTKDestroy)sftk_Space;
             context->verify = (SFTKVerify)sftk_RSACheckSignPSS;
             break;
-        case CKM_DSA_SHA1:
-            context->multi = PR_TRUE;
-            crv = sftk_doSubSHA1(context);
-            if (crv != CKR_OK)
-                break;
-        /* fall through */
+
+        INIT_DSA_VFY_MECH(SHA1)
+        INIT_DSA_VFY_MECH(SHA224)
+        INIT_DSA_VFY_MECH(SHA256)
+        INIT_DSA_VFY_MECH(SHA384)
+        INIT_DSA_VFY_MECH(SHA512)
+
         case CKM_DSA:
+        finish_dsa:
             if (key_type != CKK_DSA) {
                 crv = CKR_KEY_TYPE_INCONSISTENT;
                 break;
@@ -3552,13 +3686,15 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
             context->verify = (SFTKVerify)nsc_DSA_Verify_Stub;
             context->destroy = sftk_Null;
             break;
-        case CKM_ECDSA_SHA1:
-            context->multi = PR_TRUE;
-            crv = sftk_doSubSHA1(context);
-            if (crv != CKR_OK)
-                break;
-        /* fall through */
+
+        INIT_ECDSA_VFY_MECH(SHA1)
+        INIT_ECDSA_VFY_MECH(SHA224)
+        INIT_ECDSA_VFY_MECH(SHA256)
+        INIT_ECDSA_VFY_MECH(SHA384)
+        INIT_ECDSA_VFY_MECH(SHA512)
+
         case CKM_ECDSA:
+        finish_ecdsa:
             if (key_type != CKK_EC) {
                 crv = CKR_KEY_TYPE_INCONSISTENT;
                 break;
@@ -4673,6 +4809,73 @@ loser:
 #define PAIRWISE_DIGEST_LENGTH SHA224_LENGTH /* 224-bits */
 #define PAIRWISE_MESSAGE_LENGTH 20           /* 160-bits */
 
+static CK_RV
+pairwise_signverify_mech (CK_SESSION_HANDLE hSession,
+                          SFTKObject *publicKey, SFTKObject *privateKey,
+                          CK_MECHANISM mech,
+                          CK_ULONG signature_length,
+                          CK_ULONG pairwise_digest_length)
+{
+    /* Variables used for Signature/Verification functions. */
+    /* Must be at least 256 bits for DSA2 digest */
+    unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!";
+    unsigned char *signature;
+    CK_RV crv;
+
+    /* Allocate space for signature data. */
+    signature = (unsigned char *)PORT_ZAlloc(signature_length);
+    if (signature == NULL) {
+        return CKR_HOST_MEMORY;
+    }
+
+    /* Sign the known hash using the private key. */
+    crv = NSC_SignInit(hSession, &mech, privateKey->handle);
+    if (crv != CKR_OK) {
+        PORT_Free(signature);
+        return crv;
+    }
+
+    crv = NSC_Sign(hSession,
+                   known_digest,
+                   pairwise_digest_length,
+                   signature,
+                   &signature_length);
+    if (crv != CKR_OK) {
+        PORT_Free(signature);
+        return crv;
+    }
+
+    /* detect trivial signing transforms */
+    if ((signature_length >= pairwise_digest_length) &&
+        (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) {
+        PORT_Free(signature);
+        return CKR_DEVICE_ERROR;
+    }
+
+    /* Verify the known hash using the public key. */
+    crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
+    if (crv != CKR_OK) {
+        PORT_Free(signature);
+        return crv;
+    }
+
+    crv = NSC_Verify(hSession,
+                     known_digest,
+                     pairwise_digest_length,
+                     signature,
+                     signature_length);
+
+    /* Free signature data. */
+    PORT_Free(signature);
+
+    if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
+        (crv == CKR_SIGNATURE_INVALID)) {
+        return CKR_GENERAL_ERROR;
+    }
+
+    return crv;
+}
+
 /*
  * FIPS 140-2 pairwise consistency check utilized to validate key pair.
  *
@@ -4720,8 +4923,6 @@ sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
 
     /* Variables used for Signature/Verification functions. */
     /* Must be at least 256 bits for DSA2 digest */
-    unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!";
-    unsigned char *signature;
     CK_ULONG signature_length;
 
     if (keyType == CKK_RSA) {
@@ -4875,76 +5076,34 @@ sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
         }
     }
 
+#define SIGNVERIFY_CHECK_MECH(vfymech)                                               \
+    mech.mechanism = vfymech;                                                        \
+    crv = pairwise_signverify_mech (hSession, publicKey, privateKey,                 \
+                                    mech, signature_length, pairwise_digest_length); \
+    if (crv != CKR_OK)                                                               \
+        return crv;
+
     if (canSignVerify) {
-        /* Determine length of signature. */
         switch (keyType) {
             case CKK_RSA:
                 signature_length = modulusLen;
-                mech.mechanism = CKM_RSA_PKCS;
+                SIGNVERIFY_CHECK_MECH(CKM_RSA_PKCS)
                 break;
             case CKK_DSA:
                 signature_length = DSA_MAX_SIGNATURE_LEN;
                 pairwise_digest_length = subPrimeLen;
-                mech.mechanism = CKM_DSA;
+                SIGNVERIFY_CHECK_MECH(CKM_DSA)
+                SIGNVERIFY_CHECK_MECH(CKM_DSA_SHA224)
                 break;
             case CKK_EC:
                 signature_length = MAX_ECKEY_LEN * 2;
-                mech.mechanism = CKM_ECDSA;
+                SIGNVERIFY_CHECK_MECH(CKM_ECDSA)
+                SIGNVERIFY_CHECK_MECH(CKM_ECDSA_SHA224)
                 break;
             default:
                 return CKR_DEVICE_ERROR;
         }
 
-        /* Allocate space for signature data. */
-        signature = (unsigned char *)PORT_ZAlloc(signature_length);
-        if (signature == NULL) {
-            return CKR_HOST_MEMORY;
-        }
-
-        /* Sign the known hash using the private key. */
-        crv = NSC_SignInit(hSession, &mech, privateKey->handle);
-        if (crv != CKR_OK) {
-            PORT_Free(signature);
-            return crv;
-        }
-
-        crv = NSC_Sign(hSession,
-                       known_digest,
-                       pairwise_digest_length,
-                       signature,
-                       &signature_length);
-        if (crv != CKR_OK) {
-            PORT_Free(signature);
-            return crv;
-        }
-
-        /* detect trivial signing transforms */
-        if ((signature_length >= pairwise_digest_length) &&
-            (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) {
-            PORT_Free(signature);
-            return CKR_DEVICE_ERROR;
-        }
-
-        /* Verify the known hash using the public key. */
-        crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
-        if (crv != CKR_OK) {
-            PORT_Free(signature);
-            return crv;
-        }
-
-        crv = NSC_Verify(hSession,
-                         known_digest,
-                         pairwise_digest_length,
-                         signature,
-                         signature_length);
-
-        /* Free signature data. */
-        PORT_Free(signature);
-
-        if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
-            (crv == CKR_SIGNATURE_INVALID)) {
-            return CKR_GENERAL_ERROR;
-        }
         if (crv != CKR_OK) {
             return crv;
         }
diff --git a/nss/lib/softoken/softoken.h b/nss/lib/softoken/softoken.h
index 4626e78..1a22b07 100644
--- a/nss/lib/softoken/softoken.h
+++ b/nss/lib/softoken/softoken.h
@@ -35,6 +35,16 @@ RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
                   const unsigned char *sig, unsigned int sigLen,
                   const unsigned char *hash, unsigned int hashLen);
 
+extern SECStatus
+DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
+             unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
+             const unsigned char *hash, unsigned int hashLen);
+
+extern SECStatus
+ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
+               unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
+               const unsigned char *hash, unsigned int hashLen);
+
 /*
 ** Prepare a buffer for padded CBC encryption, growing to the appropriate
 ** boundary, filling with the appropriate padding.
diff --git a/nss/lib/util/pkcs11t.h b/nss/lib/util/pkcs11t.h
index 6ee6609..e42fcba 100644
--- a/nss/lib/util/pkcs11t.h
+++ b/nss/lib/util/pkcs11t.h
@@ -593,6 +593,10 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
 #define CKM_DSA_KEY_PAIR_GEN 0x00000010
 #define CKM_DSA 0x00000011
 #define CKM_DSA_SHA1 0x00000012
+#define CKM_DSA_SHA224 0x00000013
+#define CKM_DSA_SHA256 0x00000014
+#define CKM_DSA_SHA384 0x00000015
+#define CKM_DSA_SHA512 0x00000016
 #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
 #define CKM_DH_PKCS_DERIVE 0x00000021
 
@@ -851,6 +855,10 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
 
 #define CKM_ECDSA 0x00001041
 #define CKM_ECDSA_SHA1 0x00001042
+#define CKM_ECDSA_SHA224 0x00001043
+#define CKM_ECDSA_SHA256 0x00001044
+#define CKM_ECDSA_SHA384 0x00001045
+#define CKM_ECDSA_SHA512 0x00001046
 
 /* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
  * are new for v2.11 */
