Blob Blame History Raw
diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c
--- a/cmd/fipstest/fipstest.c
+++ b/cmd/fipstest/fipstest.c
@@ -2330,16 +2330,44 @@ sha_get_hashType(int hashbits)
             hashType = HASH_AlgSHA512;
             break;
         default:
             break;
     }
     return hashType;
 }
 
+HASH_HashType
+hash_string_to_hashType(const char * src)
+{
+    HASH_HashType shaAlg = HASH_AlgNULL;
+    if (strncmp(src, "SHA-1", 5) == 0) {
+         shaAlg = HASH_AlgSHA1;
+    } else if (strncmp(src, "SHA-224", 7) == 0) {
+        shaAlg = HASH_AlgSHA224;
+    } else if (strncmp(src, "SHA-256", 7) == 0) {
+        shaAlg = HASH_AlgSHA256;
+    } else if (strncmp(src, "SHA-384", 7) == 0) {
+        shaAlg = HASH_AlgSHA384;
+    } else if (strncmp(src, "SHA-512", 7) == 0) {
+        shaAlg = HASH_AlgSHA512;
+    } else if (strncmp(src, "SHA1", 4) == 0) {
+         shaAlg = HASH_AlgSHA1;
+    } else if (strncmp(src, "SHA224", 6) == 0) {
+        shaAlg = HASH_AlgSHA224;
+    } else if (strncmp(src, "SHA256", 6) == 0) {
+        shaAlg = HASH_AlgSHA256;
+    } else if (strncmp(src, "SHA384", 6) == 0) {
+        shaAlg = HASH_AlgSHA384;
+    } else if (strncmp(src, "SHA512", 6) == 0) {
+        shaAlg = HASH_AlgSHA512;
+    }
+    return shaAlg;
+}
+
 /*
  * Perform the ECDSA Key Pair Generation Test.
  *
  * reqfn is the pathname of the REQUEST file.
  *
  * The output RESPONSE file is written to stdout.
  */
 void
@@ -2623,27 +2651,18 @@ ecdsa_siggen_test(char *reqfn)
             *dst++ = tolower(*src);
             src += 2; /* skip the hyphen */
             *dst++ = *src++;
             *dst++ = *src++;
             *dst++ = *src++;
             *dst = '\0';
             src++; /* skip the comma */
             /* set the SHA Algorithm */
-            if (strncmp(src, "SHA-1", 5) == 0) {
-                shaAlg = HASH_AlgSHA1;
-            } else if (strncmp(src, "SHA-224", 7) == 0) {
-                shaAlg = HASH_AlgSHA224;
-            } else if (strncmp(src, "SHA-256", 7) == 0) {
-                shaAlg = HASH_AlgSHA256;
-            } else if (strncmp(src, "SHA-384", 7) == 0) {
-                shaAlg = HASH_AlgSHA384;
-            } else if (strncmp(src, "SHA-512", 7) == 0) {
-                shaAlg = HASH_AlgSHA512;
-            } else {
+            shaAlg = hash_string_to_hashType(src);
+            if (shaAlg == HASH_AlgNULL){
                 fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             if (ecparams != NULL) {
                 PORT_FreeArena(ecparams->arena, PR_FALSE);
                 ecparams = NULL;
             }
             encodedparams = getECParams(curve);
@@ -2793,27 +2812,18 @@ ecdsa_sigver_test(char *reqfn)
             *dst++ = tolower(*src);
             src += 2; /* skip the hyphen */
             *dst++ = *src++;
             *dst++ = *src++;
             *dst++ = *src++;
             *dst = '\0';
             src++; /* skip the comma */
             /* set the SHA Algorithm */
-            if (strncmp(src, "SHA-1", 5) == 0) {
-                shaAlg = HASH_AlgSHA1;
-            } else if (strncmp(src, "SHA-224", 7) == 0) {
-                shaAlg = HASH_AlgSHA224;
-            } else if (strncmp(src, "SHA-256", 7) == 0) {
-                shaAlg = HASH_AlgSHA256;
-            } else if (strncmp(src, "SHA-384", 7) == 0) {
-                shaAlg = HASH_AlgSHA384;
-            } else if (strncmp(src, "SHA-512", 7) == 0) {
-                shaAlg = HASH_AlgSHA512;
-            } else {
+            shaAlg = hash_string_to_hashType(src);
+            if (shaAlg == HASH_AlgNULL) {
                 fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             encodedparams = getECParams(curve);
             if (encodedparams == NULL) {
                 fprintf(stderr, "Unknown curve %s.", curve);
                 goto loser;
             }
@@ -2951,16 +2961,932 @@ ecdsa_sigver_test(char *reqfn)
     }
 loser:
     if (ecpub.ecParams.arena != NULL) {
         PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
     }
     fclose(ecdsareq);
 }
 
+/*
+ * Perform the ECDH Functional Test.
+ *
+ * reqfn is the pathname of the REQUEST file.
+ *
+ * The output RESPONSE file is written to stdout.
+ */
+#define MAX_ECC_PARAMS 256
+void
+ecdh_functional(char *reqfn, PRBool response)
+{
+    char buf[256];   /* holds one line from the input REQUEST file.
+                         * needs to be large enough to hold the longest
+                         * line "Qx = <144 hex digits>\n".
+                         */
+    FILE *ecdhreq;  /* input stream from the REQUEST file */
+    FILE *ecdhresp; /* output stream to the RESPONSE file */
+    char curve[16];  /* "nistxddd" */
+    unsigned char hashBuf[HASH_LENGTH_MAX];
+    ECParams *ecparams[MAX_ECC_PARAMS] = {NULL};
+    ECPrivateKey *ecpriv = NULL;
+    ECParams *current_ecparams = NULL;
+    SECItem pubkey;
+    SECItem ZZ;
+    unsigned int i;
+    unsigned int len = 0;
+    unsigned int uit_len = 0;
+    int current_curve = -1;
+    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
+
+    ecdhreq = fopen(reqfn, "r");
+    ecdhresp = stdout;
+    strcpy(curve, "nist");
+    pubkey.data = NULL;
+    while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
+        /* a comment or blank line */
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        if (buf[0] == '[') {
+            /* [Ex] */
+            if (buf[1] == 'E' && buf[3] == ']') {
+                current_curve = buf[2] - 'A';
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            /* [Curve selected: x-nnn */
+            if (strncmp(buf, "[Curve ", 7) == 0) {
+                const char *src;
+                char *dst;
+                SECItem *encodedparams;
+
+                if ((current_curve < 0) || (current_curve > MAX_ECC_PARAMS)) {
+                    fprintf(stderr, "No curve type defined\n");
+                    goto loser;
+                }
+
+                src = &buf[1];
+                /* skip passed the colon */
+                while (*src && *src != ':') src++;
+                if (*src != ':') {
+                    fprintf(stderr,
+                        "No colon in curve selected statement\n%s", buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                dst = &curve[4];
+                *dst++ = tolower(*src);
+                src += 2; /* skip the hyphen */
+                *dst++ = *src++;
+                *dst++ = *src++;
+                *dst++ = *src++;
+                *dst = '\0';
+                if (ecparams[current_curve] != NULL) {
+                    PORT_FreeArena(ecparams[current_curve]->arena, PR_FALSE);
+                    ecparams[current_curve] = NULL;
+                }
+                encodedparams = getECParams(curve);
+                if (encodedparams == NULL) {
+                    fprintf(stderr, "Unknown curve %s.", curve);
+                    goto loser;
+                }
+                if (EC_DecodeParams(encodedparams, &ecparams[current_curve])
+                                                        != SECSuccess) {
+                    fprintf(stderr, "Curve %s not supported.\n", curve);
+                    goto loser;
+                }
+                SECITEM_FreeItem(encodedparams, PR_TRUE);
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            /* [Ex - SHAxxx] */
+            if (buf[1] == 'E' && buf[3] == ' ') {
+                const char *src;
+                current_curve = buf[2] - 'A';
+                if ((current_curve < 0) || (current_curve > 256)) {
+                    fprintf(stderr, "bad curve type defined (%c)\n", buf[2]);
+                    goto loser;
+                }
+                    current_ecparams = ecparams[current_curve];
+                if (current_ecparams == NULL) {
+                    fprintf(stderr, "no curve defined for type %c defined\n",
+                            buf[2]);
+                    goto loser;
+                }
+                /* skip passed the colon */
+                src = &buf[1];
+                while (*src && *src != '-') src++;
+                if (*src != '-') {
+                    fprintf(stderr,
+                        "No data in curve selected statement\n%s",buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                hash = hash_string_to_hashType(src);
+                if (hash == HASH_AlgNULL){
+                    fprintf(ecdhresp, "ERROR: Unable to find SHAAlg type");
+                    goto loser;
+                }
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        /* COUNT = ... */
+        if (strncmp(buf, "COUNT", 5) == 0) {
+            fputs(buf, ecdhresp);
+            if (current_ecparams == NULL) {
+                fprintf(stderr, "no curve defined for type %c defined\n",
+                            buf[2]);
+                goto loser;
+            }
+            len = (current_ecparams->fieldID.size + 7) >> 3;
+            if (pubkey.data != NULL) {
+                PORT_Free(pubkey.data);
+                pubkey.data = NULL;
+            }
+            SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(current_ecparams));
+            if (pubkey.data == NULL) {
+                goto loser;
+            }
+            pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
+            continue;
+        }
+        /* QeCAVSx = ... */
+        if (strncmp(buf, "QeCAVSx", 7) == 0) {
+            fputs(buf, ecdhresp);
+            i = 7;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(&pubkey.data[1], len, &buf[i]);
+            continue;
+        }
+        /* QeCAVSy = ... */
+        if (strncmp(buf, "QeCAVSy", 7) == 0) {
+            fputs(buf, ecdhresp);
+            i = 7;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(&pubkey.data[1 + len], len, &buf[i]);
+            if (current_ecparams == NULL) {
+                fprintf(stderr, "no curve defined\n");
+                goto loser;
+            }
+            /* validate CAVS public key */
+            if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
+                fprintf(stderr,"BAD key detected\n");
+                goto loser;
+            }
+
+            /* generate ECC key pair */
+            if (EC_NewKey(current_ecparams, &ecpriv) != SECSuccess) {
+                fprintf(stderr,"Failed to generate new key\n");
+                goto loser;
+            }
+            /* validate UIT generated public key */
+            if (EC_ValidatePublicKey(current_ecparams, &ecpriv->publicValue) !=
+                    SECSuccess) {
+                fprintf(stderr,"generate key did not validate\n");
+                goto loser;
+            }
+            /* output UIT public key */
+            uit_len = ecpriv->publicValue.len;
+            if (uit_len % 2 == 0) {
+                fprintf(stderr,"generate key had invalid public value len\n");
+                goto loser;
+            }
+            uit_len = (uit_len - 1) / 2;
+            if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+                fprintf(stderr,"generate key was compressed\n");
+                goto loser;
+            }
+            fputs("QeIUTx = ", ecdhresp);
+            to_hex_str(buf, &ecpriv->publicValue.data[1], uit_len);
+            fputs(buf, ecdhresp);
+            fputc('\n', ecdhresp);
+            fputs("QeIUTy = ", ecdhresp);
+            to_hex_str(buf, &ecpriv->publicValue.data[1 + uit_len], uit_len);
+            fputs(buf, ecdhresp);
+            fputc('\n', ecdhresp);
+            /* ECDH */
+            if (ECDH_Derive(&pubkey,current_ecparams, &ecpriv->privateValue,
+                        PR_FALSE, &ZZ) != SECSuccess) {
+                fprintf(stderr,"Derive failed\n");
+                goto loser;
+            }
+            /* output hash of ZZ */
+            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
+                fprintf(stderr,"hash of derived key failed\n");
+                goto loser;
+            }
+            SECITEM_FreeItem(&ZZ, PR_FALSE);
+            fputs("HashZZ = ", ecdhresp);
+            to_hex_str(buf, hashBuf, fips_hashLen(hash));
+            fputs(buf, ecdhresp);
+            fputc('\n', ecdhresp);
+            fputc('\n', ecdhresp);
+            PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
+            ecpriv = NULL;
+            continue;
+        }
+    }
+loser:
+    if (ecpriv != NULL) {
+        PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
+    }
+    for (i=0; i < MAX_ECC_PARAMS; i++) {
+        if (ecparams[i] != NULL) {
+            PORT_FreeArena(ecparams[i]->arena, PR_FALSE);
+            ecparams[i] = NULL;
+        }
+    }
+    if (pubkey.data != NULL) {
+        PORT_Free(pubkey.data);
+    }
+    fclose(ecdhreq);
+}
+
+#define MATCH_OPENSSL 1 
+/*
+ * Perform the ECDH Validity Test.
+ *
+ * reqfn is the pathname of the REQUEST file.
+ *
+ * The output RESPONSE file is written to stdout.
+ */
+void
+ecdh_verify(char *reqfn, PRBool response)
+{
+    char buf[256];   /* holds one line from the input REQUEST file.
+                         * needs to be large enough to hold the longest
+                         * line "Qx = <144 hex digits>\n".
+                         */
+    FILE *ecdhreq;  /* input stream from the REQUEST file */
+    FILE *ecdhresp; /* output stream to the RESPONSE file */
+    char curve[16];  /* "nistxddd" */
+    unsigned char hashBuf[HASH_LENGTH_MAX];
+    unsigned char cavsHashBuf[HASH_LENGTH_MAX];
+    unsigned char private_data[MAX_ECKEY_LEN];
+    ECParams *ecparams[MAX_ECC_PARAMS] =  {NULL};
+    ECParams *current_ecparams = NULL;
+    SECItem pubkey;
+    SECItem ZZ;
+    SECItem private_value;
+    unsigned int i;
+    unsigned int len = 0;
+    int current_curve = -1;
+    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
+
+    ecdhreq = fopen(reqfn, "r");
+    ecdhresp = stdout;
+    strcpy(curve, "nist");
+    pubkey.data = NULL;
+    while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
+        /* a comment or blank line */
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        if (buf[0] == '[') {
+            /* [Ex] */
+            if (buf[1] == 'E' && buf[3] == ']') {
+                current_curve = buf[2] - 'A';
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            /* [Curve selected: x-nnn */
+            if (strncmp(buf, "[Curve ", 7) == 0) {
+                const char *src;
+                char *dst;
+                SECItem *encodedparams;
+
+                if ((current_curve < 0) || (current_curve > MAX_ECC_PARAMS)) {
+                    fprintf(stderr, "No curve type defined\n");
+                    goto loser;
+                }
+
+                src = &buf[1];
+                /* skip passed the colon */
+                while (*src && *src != ':') src++;
+                if (*src != ':') {
+                    fprintf(stderr,
+                        "No colon in curve selected statement\n%s", buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                dst = &curve[4];
+                *dst++ = tolower(*src);
+                src += 2; /* skip the hyphen */
+                *dst++ = *src++;
+                *dst++ = *src++;
+                *dst++ = *src++;
+                *dst = '\0';
+                if (ecparams[current_curve] != NULL) {
+                    PORT_FreeArena(ecparams[current_curve]->arena, PR_FALSE);
+                    ecparams[current_curve] = NULL;
+                }
+                encodedparams = getECParams(curve);
+                if (encodedparams == NULL) {
+                    fprintf(stderr, "Unknown curve %s.\n", curve);
+                    goto loser;
+                }
+                if (EC_DecodeParams(encodedparams, &ecparams[current_curve])
+                                                        != SECSuccess) {
+                    fprintf(stderr, "Curve %s not supported.\n", curve);
+                    goto loser;
+                }
+                SECITEM_FreeItem(encodedparams, PR_TRUE);
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            /* [Ex - SHAxxx] */
+            if (buf[1] == 'E' && buf[3] == ' ') {
+                const char *src;
+                current_curve = buf[2] - 'A';
+                if ((current_curve < 0) || (current_curve > 256)) {
+                    fprintf(stderr, "bad curve type defined (%c)\n", buf[2]);
+                    goto loser;
+                }
+                    current_ecparams = ecparams[current_curve];
+                if (current_ecparams == NULL) {
+                    fprintf(stderr, "no curve defined for type %c defined\n",
+                            buf[2]);
+                    goto loser;
+                }
+                /* skip passed the colon */
+                src = &buf[1];
+                while (*src && *src != '-') src++;
+                if (*src != '-') {
+                    fprintf(stderr,
+                        "No data in curve selected statement\n%s",buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                hash = hash_string_to_hashType(src);
+                if (hash == HASH_AlgNULL){
+                    fprintf(ecdhresp, "ERROR: Unable to find SHAAlg type");
+                    goto loser;
+                }
+                fputs(buf, ecdhresp);
+                continue;
+            }
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        /* COUNT = ... */
+        if (strncmp(buf, "COUNT", 5) == 0) {
+            fputs(buf, ecdhresp);
+            if (current_ecparams == NULL) {
+                fprintf(stderr, "no curve defined for type %c defined\n",
+                            buf[2]);
+                goto loser;
+            }
+            len = (current_ecparams->fieldID.size + 7) >> 3;
+            if (pubkey.data != NULL) {
+                PORT_Free(pubkey.data);
+                pubkey.data = NULL;
+            }
+            SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(current_ecparams));
+            if (pubkey.data == NULL) {
+                goto loser;
+            }
+            pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
+            continue;
+        }
+        /* QeCAVSx = ... */
+        if (strncmp(buf, "QeCAVSx", 7) == 0) {
+            fputs(buf, ecdhresp);
+            i = 7;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(&pubkey.data[1], len, &buf[i]);
+            continue;
+        }
+        /* QeCAVSy = ... */
+        if (strncmp(buf, "QeCAVSy", 7) == 0) {
+            fputs(buf, ecdhresp);
+            i = 7;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(&pubkey.data[1 + len], len, &buf[i]);
+            continue;
+        }
+        if (strncmp(buf, "deIUT", 5) == 0) {
+            fputs(buf, ecdhresp);
+            i = 5;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(private_data, len, &buf[i]);
+            private_value.data = private_data;
+            private_value.len = len;
+            continue;
+        }
+        if (strncmp(buf, "QeIUTx", 6) == 0) {
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        if (strncmp(buf, "QeIUTy", 6) == 0) {
+            fputs(buf, ecdhresp);
+            continue;
+        }
+        if (strncmp(buf, "CAVSHashZZ", 10) == 0) {
+            fputs(buf, ecdhresp);
+            i = 10;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
+            if (current_ecparams == NULL) {
+                fprintf(stderr, "no curve defined for type defined\n");
+                goto loser;
+            }
+            /* validate CAVS public key */
+            if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
+#ifdef MATCH_OPENSSL
+		fprintf(ecdhresp, "Result = F\n");
+#else
+		fprintf(ecdhresp, "Result = F # key didn't validate\n");
+#endif
+                continue;
+            }
+
+            /* ECDH */
+            if (ECDH_Derive(&pubkey, current_ecparams, &private_value,
+                        PR_FALSE, &ZZ) != SECSuccess) {
+                fprintf(stderr,"Derive failed\n");
+                goto loser;
+            }
+            /* output  ZZ */
+#ifndef MATCH_OPENSSL
+            fputs("Z = ", ecdhresp);
+            to_hex_str(buf, ZZ.data, ZZ.len);
+            fputs(buf, ecdhresp);
+            fputc('\n', ecdhresp);
+#endif
+
+            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
+                fprintf(stderr,"hash of derived key failed\n");
+                goto loser;
+            }
+            SECITEM_FreeItem(&ZZ, PR_FALSE);
+#ifndef MATCH_NIST
+            fputs("IUTHashZZ = ", ecdhresp);
+            to_hex_str(buf, hashBuf, fips_hashLen(hash));
+            fputs(buf, ecdhresp);
+            fputc('\n', ecdhresp);
+#endif
+            if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
+#ifdef MATCH_OPENSSL
+		fprintf(ecdhresp, "Result = F\n");
+#else
+		fprintf(ecdhresp, "Result = F # hash doesn't match\n");
+#endif
+            } else {
+		fprintf(ecdhresp, "Result = P\n");
+            }
+#ifndef MATCH_OPENSSL
+            fputc('\n', ecdhresp);
+#endif
+            continue;
+        }
+    }
+loser:
+    for (i=0; i < MAX_ECC_PARAMS; i++) {
+        if (ecparams[i] != NULL) {
+            PORT_FreeArena(ecparams[i]->arena, PR_FALSE);
+            ecparams[i] = NULL;
+        }
+    }
+    if (pubkey.data != NULL) {
+        PORT_Free(pubkey.data);
+    }
+    fclose(ecdhreq);
+}
+
+/*
+ * Perform the DH Functional Test.
+ *
+ * reqfn is the pathname of the REQUEST file.
+ *
+ * The output RESPONSE file is written to stdout.
+ */
+#define MAX_ECC_PARAMS 256
+void
+dh_functional(char *reqfn, PRBool response)
+{
+    char buf[1024];   /* holds one line from the input REQUEST file.
+                         * needs to be large enough to hold the longest
+                         * line "YephCAVS = <512 hex digits>\n".
+                         */
+    FILE *dhreq;  /* input stream from the REQUEST file */
+    FILE *dhresp; /* output stream to the RESPONSE file */
+    unsigned char hashBuf[HASH_LENGTH_MAX];
+    DSAPrivateKey *dsapriv = NULL;
+    PQGParams pqg = { 0 };
+    unsigned char pubkeydata[DSA_MAX_P_BITS/8];
+    SECItem pubkey;
+    SECItem ZZ;
+    unsigned int i,j;
+    unsigned int pgySize;
+    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
+
+    dhreq = fopen(reqfn, "r");
+    dhresp = stdout;
+    while (fgets(buf, sizeof buf, dhreq) != NULL) {
+        /* a comment or blank line */
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
+            fputs(buf, dhresp);
+            continue;
+        }
+        if (buf[0] == '[') {
+            /* [Fx - SHAxxx] */
+            if (buf[1] == 'F' && buf[3] == ' ') {
+                const char *src;
+                /* skip passed the colon */
+                src = &buf[1];
+                while (*src && *src != '-') src++;
+                if (*src != '-') {
+                    fprintf(stderr, "No hash specified\n%s",buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                hash = hash_string_to_hashType(src);
+                if (hash == HASH_AlgNULL){
+                    fprintf(dhresp, "ERROR: Unable to find SHAAlg type");
+                    goto loser;
+                }
+                /* clear the PQG parameters */
+                if (pqg.prime.data) { /* P */
+                    SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
+                }
+                if (pqg.subPrime.data) { /* Q */
+                    SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
+                }
+                if (pqg.base.data) { /* G */
+                    SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
+                }
+                pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
+                SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
+                SECITEM_AllocItem(NULL, &pqg.base, pgySize);
+                pqg.prime.len = pqg.base.len = pgySize;
+
+                /* set q to the max allows */
+                SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS/ 8);
+                pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
+                fputs(buf, dhresp);
+                continue;
+            }
+            fputs(buf, dhresp);
+            continue;
+        }
+        if (buf[0] == 'P') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.prime.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.prime.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.prime.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* Q = ... */
+        if (buf[0] == 'Q') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.subPrime.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* G = ... */
+        if (buf[0] == 'G') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.base.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.base.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.base.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* COUNT = ... */
+        if (strncmp(buf, "COUNT", 5) == 0) {
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* YephemCAVS = ... */
+        if (strncmp(buf, "YephemCAVS", 10) == 0) {
+            fputs(buf, dhresp);
+            i = 10;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
+            pubkey.data = pubkeydata;
+            pubkey.len = pqg.prime.len;
+
+            /* generate FCC key pair, nist uses pqg rather then pg,
+             * so use DSA to generate the key */
+            if (DSA_NewKey(&pqg, &dsapriv) != SECSuccess) {
+                fprintf(stderr,"Failed to generate new key\n");
+                goto loser;
+            }
+            fputs("XephemIUT = ", dhresp);
+            to_hex_str(buf, dsapriv->privateValue.data, dsapriv->privateValue.len);
+            fputs(buf, dhresp);
+            fputc('\n', dhresp);
+            fputs("YephemIUT = ", dhresp);
+            to_hex_str(buf, dsapriv->publicValue.data, dsapriv->publicValue.len);
+            fputs(buf, dhresp);
+            fputc('\n', dhresp);
+            /* DH */
+            if (DH_Derive(&pubkey,&pqg.prime, &dsapriv->privateValue,
+                        &ZZ, pqg.prime.len) != SECSuccess) {
+                fprintf(stderr,"Derive failed\n");
+                goto loser;
+            }
+            /* output hash of ZZ */
+            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
+                fprintf(stderr,"hash of derived key failed\n");
+                goto loser;
+            }
+            SECITEM_FreeItem(&ZZ, PR_FALSE);
+            fputs("HashZZ = ", dhresp);
+            to_hex_str(buf, hashBuf, fips_hashLen(hash));
+            fputs(buf, dhresp);
+            fputc('\n', dhresp);
+            fputc('\n', dhresp);
+            PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
+            dsapriv = NULL;
+            continue;
+        }
+    }
+loser:
+    if (dsapriv != NULL) {
+        PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
+    }
+    fclose(dhreq);
+}
+
+#define MATCH_OPENSSL 1 
+/*
+ * Perform the DH Validity Test.
+ *
+ * reqfn is the pathname of the REQUEST file.
+ *
+ * The output RESPONSE file is written to stdout.
+ */
+void
+dh_verify(char *reqfn, PRBool response)
+{
+    char buf[1024];   /* holds one line from the input REQUEST file.
+                         * needs to be large enough to hold the longest
+                         * line "YephCAVS = <512 hex digits>\n".
+                         */
+    FILE *dhreq;  /* input stream from the REQUEST file */
+    FILE *dhresp; /* output stream to the RESPONSE file */
+    unsigned char hashBuf[HASH_LENGTH_MAX];
+    unsigned char cavsHashBuf[HASH_LENGTH_MAX];
+    PQGParams pqg = { 0 };
+    unsigned char pubkeydata[DSA_MAX_P_BITS/8];
+    unsigned char privkeydata[DSA_MAX_P_BITS/8];
+    SECItem pubkey;
+    SECItem privkey;
+    SECItem ZZ;
+    unsigned int i,j;
+    unsigned int pgySize;
+    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
+
+    dhreq = fopen(reqfn, "r");
+    dhresp = stdout;
+    while (fgets(buf, sizeof buf, dhreq) != NULL) {
+        /* a comment or blank line */
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
+            fputs(buf, dhresp);
+            continue;
+        }
+        if (buf[0] == '[') {
+            /* [Fx - SHAxxx] */
+            if (buf[1] == 'F' && buf[3] == ' ') {
+                const char *src;
+                /* skip passed the colon */
+                src = &buf[1];
+                while (*src && *src != '-') src++;
+                if (*src != '-') {
+                    fprintf(stderr, "No hash specified\n%s",buf);
+                    goto loser;
+                }
+                src++;
+                /* skip to the first non-space */
+                while (*src && *src == ' ') src++;
+                hash = hash_string_to_hashType(src);
+                if (hash == HASH_AlgNULL){
+                    fprintf(dhresp, "ERROR: Unable to find SHAAlg type");
+                    goto loser;
+                }
+                /* clear the PQG parameters */
+                if (pqg.prime.data) { /* P */
+                    SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
+                }
+                if (pqg.subPrime.data) { /* Q */
+                    SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
+                }
+                if (pqg.base.data) { /* G */
+                    SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
+                }
+                pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
+                SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
+                SECITEM_AllocItem(NULL, &pqg.base, pgySize);
+                pqg.prime.len = pqg.base.len = pgySize;
+
+                /* set q to the max allows */
+                SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS/ 8);
+                pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
+                fputs(buf, dhresp);
+                continue;
+            }
+            fputs(buf, dhresp);
+            continue;
+        }
+        if (buf[0] == 'P') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.prime.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.prime.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.prime.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* Q = ... */
+        if (buf[0] == 'Q') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.subPrime.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* G = ... */
+        if (buf[0] == 'G') {
+            i = 1;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            for (j = 0; j < pqg.base.len; i += 2, j++) {
+                if (!isxdigit(buf[i])) {
+                    pqg.base.len = j;
+                    break;
+                }
+                hex_to_byteval(&buf[i], &pqg.base.data[j]);
+            }
+
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* COUNT = ... */
+        if (strncmp(buf, "COUNT", 5) == 0) {
+            fputs(buf, dhresp);
+            continue;
+        }
+
+        /* YephemCAVS = ... */
+        if (strncmp(buf, "YephemCAVS", 10) == 0) {
+            fputs(buf, dhresp);
+            i = 10;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
+            pubkey.data = pubkeydata;
+            pubkey.len = pqg.prime.len;
+            continue;
+        }
+        /* XephemUIT = ... */
+        if (strncmp(buf, "XephemIUT", 9) == 0) {
+            fputs(buf, dhresp);
+            i = 9;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(privkeydata, pqg.subPrime.len, &buf[i]);
+            privkey.data = privkeydata;
+            privkey.len = pqg.subPrime.len;
+            continue;
+        }
+        /* YephemUIT = ... */
+        if (strncmp(buf, "YephemIUT", 9) == 0) {
+            fputs(buf, dhresp);
+            continue;
+        }
+        /* CAVSHashZZ = ... */
+        if (strncmp(buf, "CAVSHashZZ", 10) == 0) {
+            fputs(buf, dhresp);
+            i = 10;
+            while (isspace(buf[i]) || buf[i] == '=') {
+                i++;
+            }
+            from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
+            /* do the DH operation*/
+            if (DH_Derive(&pubkey,&pqg.prime, &privkey,
+                        &ZZ, pqg.prime.len) != SECSuccess) {
+                fprintf(stderr,"Derive failed\n");
+                goto loser;
+            }
+            /* output  ZZ */
+#ifndef MATCH_OPENSSL
+            fputs("Z = ", dhresp);
+            to_hex_str(buf, ZZ.data, ZZ.len);
+            fputs(buf, dhresp);
+            fputc('\n', dhresp);
+#endif
+            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
+                fprintf(stderr,"hash of derived key failed\n");
+                goto loser;
+            }
+            SECITEM_FreeItem(&ZZ, PR_FALSE);
+#ifndef MATCH_NIST_
+            fputs("IUTHashZZ = ", dhresp);
+            to_hex_str(buf, hashBuf, fips_hashLen(hash));
+            fputs(buf, dhresp);
+            fputc('\n', dhresp);
+#endif
+            if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
+		fprintf(dhresp, "Result = F\n");
+            } else {
+		fprintf(dhresp, "Result = P\n");
+            }
+#ifndef MATCH_OPENSSL
+            fputc('\n', dhresp);
+#endif
+            continue;
+        }
+    }
+loser:
+    fclose(dhreq);
+}
+
 PRBool
 isblankline(char *b)
 {
     while (isspace(*b))
         b++;
     if ((*b == '\n') || (*b == 0)) {
         return PR_TRUE;
     }
@@ -5337,27 +6263,18 @@ rsa_siggen_test(char *reqfn)
 
         /* SHAAlg = ... */
         if (strncmp(buf, "SHAAlg", 6) == 0) {
             i = 6;
             while (isspace(buf[i]) || buf[i] == '=') {
                 i++;
             }
             /* set the SHA Algorithm */
-            if (strncmp(&buf[i], "SHA1", 4) == 0) {
-                shaAlg = HASH_AlgSHA1;
-            } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
-                shaAlg = HASH_AlgSHA224;
-            } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
-                shaAlg = HASH_AlgSHA256;
-            } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
-                shaAlg = HASH_AlgSHA384;
-            } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
-                shaAlg = HASH_AlgSHA512;
-            } else {
+            shaAlg = hash_string_to_hashType(&buf[i]);
+            if (shaAlg == HASH_AlgNULL) {
                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             fputs(buf, rsaresp);
             continue;
         }
         /* Msg = ... */
         if (strncmp(buf, "Msg", 3) == 0) {
@@ -5532,27 +6449,18 @@ rsa_sigver_test(char *reqfn)
 
         /* SHAAlg = ... */
         if (strncmp(buf, "SHAAlg", 6) == 0) {
             i = 6;
             while (isspace(buf[i]) || buf[i] == '=') {
                 i++;
             }
             /* set the SHA Algorithm */
-            if (strncmp(&buf[i], "SHA1", 4) == 0) {
-                shaAlg = HASH_AlgSHA1;
-            } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
-                shaAlg = HASH_AlgSHA224;
-            } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
-                shaAlg = HASH_AlgSHA256;
-            } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
-                shaAlg = HASH_AlgSHA384;
-            } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
-                shaAlg = HASH_AlgSHA512;
-            } else {
+            shaAlg = hash_string_to_hashType(&buf[i]);
+            if (shaAlg == HASH_AlgNULL) {
                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             fputs(buf, rsaresp);
             continue;
         }
 
         /* e = ... public Key */
@@ -6103,16 +7011,44 @@ main(int argc, char **argv)
         } else if (strcmp(argv[2], "siggen") == 0) {
             /* Signature Generation Test */
             ecdsa_siggen_test(argv[3]);
         } else if (strcmp(argv[2], "sigver") == 0) {
             /* Signature Verification Test */
             ecdsa_sigver_test(argv[3]);
         }
         /*************/
+        /*   ECDH   */
+        /*************/
+    } else if (strcmp(argv[1], "ecdh") == 0) {
+        /* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
+        if (strcmp(argv[2], "init-func") == 0) {
+            ecdh_functional(argv[3], 0);
+        } else if (strcmp(argv[2], "resp-func") == 0) {
+            ecdh_functional(argv[3], 1);
+        } else if (strcmp(argv[2], "init-verify") == 0) {
+            ecdh_verify(argv[3], 0);
+        } else if (strcmp(argv[2], "resp-verify") == 0) {
+            ecdh_verify(argv[3], 1);
+        }
+        /*************/
+        /*   DH   */
+        /*************/
+    } else if (strcmp(argv[1], "dh") == 0) {
+        /* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
+        if (strcmp(argv[2], "init-func") == 0) {
+            dh_functional(argv[3], 0);
+        } else if (strcmp(argv[2], "resp-func") == 0) {
+            dh_functional(argv[3], 1);
+        } else if (strcmp(argv[2], "init-verify") == 0) {
+            dh_verify(argv[3], 0);
+        } else if (strcmp(argv[2], "resp-verify") == 0) {
+            dh_verify(argv[3], 1);
+        }
+        /*************/
         /*   RNG     */
         /*************/
     } else if (strcmp(argv[1], "rng") == 0) {
         /* argv[2]=vst|mct argv[3]=<test name>.req */
         if (strcmp(argv[2], "vst") == 0) {
             /* Variable Seed Test */
             rng_vst(argv[3]);
         } else if (strcmp(argv[2], "mct") == 0) {
diff --git a/cmd/fipstest/kas.sh b/cmd/fipstest/kas.sh
new file mode 100755
--- /dev/null
+++ b/cmd/fipstest/kas.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# 
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# A Bourne shell script for running the NIST DSA Validation System
+#
+# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
+# variables appropriately so that the fipstest command and the NSPR and NSS
+# shared libraries/DLLs are on the search path.  Then run this script in the
+# directory where the REQUEST (.req) files reside.  The script generates the
+# RESPONSE (.rsp) files in the same directory.
+BASEDIR=${1-.}
+TESTDIR=${BASEDIR}/KAS
+COMMAND=${2-run}
+REQDIR=${TESTDIR}/req
+RSPDIR=${TESTDIR}/resp
+
+
+#
+if [ ${COMMAND} = "verify" ]; then
+#
+# need verify for KAS tests
+
+# verify generated keys
+#    name=KeyPair
+#    echo ">>>>>  $name"
+#    fipstest dsa keyver ${RSPDIR}/$name.rsp | grep ^Result.=.F
+# verify generated pqg values
+#    name=PQGGen
+#    echo ">>>>>  $name"
+#    fipstest dsa pqgver ${RSPDIR}/$name.rsp | grep ^Result.=.F
+# verify PQGVer with known answer
+#    sh ./validate1.sh ${TESTDIR} PQGVer.req ' ' '-e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;'
+# verify signatures
+#    name=SigGen
+#    echo ">>>>>  $name"
+#    fipstest dsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F
+# verify SigVer with known answer
+#    sh ./validate1.sh ${TESTDIR} SigVer.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);;'
+    exit 0
+fi
+
+request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest ecdh init-func ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest ecdh resp-func ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest ecdh init-verify ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest ecdh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_init.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest dh init-func ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_resp.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest dh resp-func ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASValidityTest_FFCEphem_NOKC_ZZOnly_init.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest dh init-verify ${REQDIR}/$request > ${RSPDIR}/$response
+
+request=KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest dh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response
+
diff --git a/cmd/fipstest/runtest.sh b/cmd/fipstest/runtest.sh
--- a/cmd/fipstest/runtest.sh
+++ b/cmd/fipstest/runtest.sh
@@ -1,14 +1,14 @@
 #!/bin/sh
 # 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 #
 TESTDIR=${1-.}
 COMMAND=${2-run}
-TESTS="aes aesgcm dsa ecdsa hmac tls rng rsa sha tdea"
+TESTS="aes aesgcm dsa ecdsa hmac kas tls rng rsa sha tdea"
 for i in $TESTS
 do
     echo "********************Running $i tests"
     sh ./${i}.sh ${TESTDIR} ${COMMAND}
 done