Add FIPS RNG tests.
authorAndy Polyakov <appro@openssl.org>
Sat, 7 May 2005 22:06:40 +0000 (22:06 +0000)
committerAndy Polyakov <appro@openssl.org>
Sat, 7 May 2005 22:06:40 +0000 (22:06 +0000)
Submitted by: Steve Marquess

fips/fips.c
fips/fips.h
fips/fips_err.h
fips/fips_test_suite.c
fips/fipshashes.c
fips/rand/Makefile
fips/rand/fips_rand.c
fips/rand/fips_rand_selftest.c [new file with mode: 0644]
fips/rand/fips_rngvs.c [new file with mode: 0644]

index 8f19c0ecec9213168f7b4cde93998b665972f38a..75fcfe13b2977a72279ec43f5cdbf4331e6e6d99 100644 (file)
@@ -239,6 +239,14 @@ int FIPS_mode_set(int onoff,const char *path)
            goto end;
            }
 
+       /* Perform RNG KAT before seeding */
+       if (!FIPS_selftest_rng())
+           {
+           fips_selftest_fail = 1;
+           ret = 0;
+           goto end;
+           }
+
        /* automagically seed PRNG if not already seeded */
        if(!FIPS_rand_seeded())
            {
index e8ebaf3679d8b6b1e5e656b00c6968fcaacfcc77..451138a33635d539432064f23ccb800d3bcb50b1 100644 (file)
@@ -99,6 +99,7 @@ void ERR_load_FIPS_strings(void);
 #define FIPS_F_FIPS_SELFTEST_AES                        104
 #define FIPS_F_FIPS_SELFTEST_DES                        107
 #define FIPS_F_FIPS_SELFTEST_DSA                        109
+#define FIPS_F_FIPS_SELFTEST_RNG                        118
 #define FIPS_F_FIPS_SELFTEST_RSA                        108
 #define FIPS_F_FIPS_SELFTEST_SHA1                       103
 #define FIPS_F_HASH_FINAL                               100
index 4f79f79862ecae465d4349733210ce8efc1f57a5..aa70f22fcb69380a423551a4c3438929eb680422 100644 (file)
@@ -82,6 +82,7 @@ static ERR_STRING_DATA FIPS_str_functs[]=
 {ERR_FUNC(FIPS_F_FIPS_SELFTEST_AES),   "FIPS_selftest_aes"},
 {ERR_FUNC(FIPS_F_FIPS_SELFTEST_DES),   "FIPS_selftest_des"},
 {ERR_FUNC(FIPS_F_FIPS_SELFTEST_DSA),   "FIPS_selftest_dsa"},
+{ERR_FUNC(FIPS_F_FIPS_SELFTEST_RNG),   "FIPS_selftest_rng"},
 {ERR_FUNC(FIPS_F_FIPS_SELFTEST_RSA),   "FIPS_selftest_rsa"},
 {ERR_FUNC(FIPS_F_FIPS_SELFTEST_SHA1),  "FIPS_selftest_sha1"},
 {ERR_FUNC(FIPS_F_HASH_FINAL),  "HASH_FINAL"},
index 60ee8d856b3054ed78c21d12128bfede4b2e9443..2532e51f429a633c41f154c692aab6a35e2f2d31 100644 (file)
@@ -228,19 +228,22 @@ int main(int argc,char **argv)
         /* Corrupted KAT tests */
         if (!strcmp(argv[1], "aes")) {
             FIPS_corrupt_aes();
-            printf("3. AES encryption/decryption with corrupted KAT...\n");
+            printf("AES encryption/decryption with corrupted KAT...\n");
         } else if (!strcmp(argv[1], "des")) {
             FIPS_corrupt_des();
-            printf("5. DES-ECB encryption/decryption with corrupted KAT...\n");
+            printf("DES-ECB encryption/decryption with corrupted KAT...\n");
         } else if (!strcmp(argv[1], "dsa")) {
             FIPS_corrupt_dsa();
-            printf("6. DSA key generation and signature validation with corrupted KAT...\n");
+            printf("DSA key generation and signature validation with corrupted KAT...\n");
         } else if (!strcmp(argv[1], "rsa")) {
             FIPS_corrupt_rsa();
-            printf("4. RSA key generation and encryption/decryption with corrupted KAT...\n");
+            printf("RSA key generation and encryption/decryption with corrupted KAT...\n");
         } else if (!strcmp(argv[1], "sha1")) {
             FIPS_corrupt_sha1();
-            printf("7. SHA-1 hash with corrupted KAT...\n");
+            printf("SHA-1 hash with corrupted KAT...\n");
+       } else if (!strcmp(argv[1], "rng")) {
+           FIPS_corrupt_rng();
+           printf("RNG test with corrupted KAT...\n");
         } else {
             printf("Bad argument \"%s\"\n", argv[1]);
             exit(1);
index 9a0f0752506e8a9a59f0a01e5b6c5f159ac679c7..6090e9efa3e52a008559740545015bb84ca95a3c 100644 (file)
@@ -1,8 +1,8 @@
 const char * const FIPS_source_hashes[] = {
-"HMAC-SHA1(fips.c)= 2f46f538f12228814cfdc8c6b37261258686fc8c",
+"HMAC-SHA1(fips.c)= 23f2470208ebbc7daeae50ad7b13e7cd7e269477",
 "HMAC-SHA1(fips_err_wrapper.c)= d3e2be316062510312269e98f964cb87e7577898",
-"HMAC-SHA1(fips.h)= 564e34c12d6743a9be06d5da74608a71937c872a",
-"HMAC-SHA1(fips_err.h)= 32ad0130f639b8f6ff417d3dfda553f5a1d7512d",
+"HMAC-SHA1(fips.h)= 87423b80f7635f08fbea23897c64e999166360a2",
+"HMAC-SHA1(fips_err.h)= d356c4436362dba2974f767e06c6be1c90dbfe9f",
 "HMAC-SHA1(aes/fips_aes_core.c)= b70bbbd675efe0613da0d57055310926a0104d55",
 "HMAC-SHA1(aes/asm/fips-ax86-elf.s)= 361df58c4838e55cf0b5fa1427c81c253e551388",
 "HMAC-SHA1(aes/fips_aes_selftest.c)= 98b01502221e7fe529fd981222f2cbb52eb4cbe0",
@@ -18,8 +18,9 @@ const char * const FIPS_source_hashes[] = {
 "HMAC-SHA1(dsa/fips_dsa_ossl.c)= 8bb943c0fd1adf04f6a845f4d1727c5472697e93",
 "HMAC-SHA1(dsa/fips_dsa_gen.c)= 78c879484fd849312ca4828b957df3842b70efc0",
 "HMAC-SHA1(dsa/fips_dsa_selftest.c)= 7c2ba8d82feda2aadc8b769a3b6c4c25a6356e01",
-"HMAC-SHA1(rand/fips_rand.c)= 29139e29f56f3ecd99f527af8742d5afb12f409a",
+"HMAC-SHA1(rand/fips_rand.c)= 7e3964447a81cfe4e75df981827d14a5fe0c2923",
 "HMAC-SHA1(rand/fips_rand.h)= bf009ea8963e79b1e414442ede9ae7010a03160b",
+"HMAC-SHA1(rand/fips_rand_selftest.c)= d9c8985e08feecefafe667ad0119d444b42f807c",
 "HMAC-SHA1(rsa/fips_rsa_eay.c)= 2596773a7af8f037427217b79f56858296961d66",
 "HMAC-SHA1(rsa/fips_rsa_gen.c)= 713d2e0d7a1a682b1794f1224b7afe01272ba755",
 "HMAC-SHA1(rsa/fips_rsa_selftest.c)= dcd0970a4de2d7f0d2333d6a3efb1ae350209b57",
index e11a5b3154375fa6f5ac4ea027d854ec2ec72daf..71780b21470fcd4326658621a46c579f7706153c 100644 (file)
@@ -22,8 +22,8 @@ TEST= fips_randtest.c
 APPS=
 
 LIB=$(TOP)/libcrypto.a
-LIBSRC=fips_rand.c
-LIBOBJ=fips_rand.o
+LIBSRC=fips_rand.c fips_rand_selftest.c
+LIBOBJ=fips_rand.o fips_rand_selftest.o
 
 SRC= $(LIBSRC)
 
@@ -62,6 +62,22 @@ tags:
 
 tests:
 
+top_fips_rngvs:
+       (cd $(TOP); $(MAKE) DIRS=fips FDIRS=$(DIR) TARGET=fips_rngvs sub_target)
+
+fips_rngvs: fips_rngvs.o $(TOP)/libcrypto.a
+       $(CC) $(CFLAGS) -o fips_rngvs fips_rngvs.o $(PEX_LIBS) $(TOP)/libcrypto.a $(EX_LIBS)
+       TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a fips_rngvs
+
+Q=../testvectors/rng/req
+A=../testvectors/rng/rsp
+
+fips_test: top_fips_rngvs
+       -rm -rf $A
+       mkdir $A
+       ./fips_rngvs mct < $Q/MCT.req > $A/MCT.rsp
+       ./fips_rngvs vst < $Q/VST.req > $A/VST.rsp
+
 lint:
        lint -DLINT $(INCLUDES) $(SRC)>fluff
 
index 45cf1c57069c686f8ba19937fb9e77388e1e24ff..7df2dc804e4424114beeccbea0225744556409bb 100644 (file)
@@ -90,6 +90,7 @@ static DES_cblock key1;
 static DES_cblock key2;
 static DES_key_schedule ks1,ks2;
 static int key_set;
+static int key_init;
 static int test_mode;
 static unsigned char test_faketime[8];
 
@@ -153,7 +154,7 @@ static void fips_gettime(unsigned char buf[8])
 
     if(test_mode)
        {
-       fprintf(OPENSSL_stderr(),"WARNING!!! PRNG IN TEST MODE!!!\n");
+       /* fprintf(OPENSSL_stderr(),"WARNING!!! PRNG IN TEST MODE!!!\n"); */
        memcpy(buf,test_faketime,sizeof test_faketime);
        return;
        }
@@ -202,22 +203,23 @@ static void fips_rand_cleanup(void)
     {
     OPENSSL_cleanse(seed,sizeof seed);
     n_seed=0;
+    o_seed=0;
+    key_init=0;
     }
 
 void FIPS_rand_seed(const void *buf_, FIPS_RAND_SIZE_T num)
     {
     const char *buf=buf_;
     FIPS_RAND_SIZE_T n;
-    static int init;
 
     /* If the key hasn't been set, we can't seed! */
     if(!key_set)
        return;
 
     CRYPTO_w_lock(CRYPTO_LOCK_RAND);
-    if(!init)
+    if(!key_init)
        {
-       init=1;
+       key_init=1;
        DES_set_key(&key1,&ks1);
        DES_set_key(&key2,&ks2);
        }
diff --git a/fips/rand/fips_rand_selftest.c b/fips/rand/fips_rand_selftest.c
new file mode 100644 (file)
index 0000000..3634677
--- /dev/null
@@ -0,0 +1,120 @@
+/* ====================================================================\r
+ * Copyright (c) 2003 The OpenSSL Project.  All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer. \r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in\r
+ *    the documentation and/or other materials provided with the\r
+ *    distribution.\r
+ *\r
+ * 3. All advertising materials mentioning features or use of this\r
+ *    software must display the following acknowledgment:\r
+ *    "This product includes software developed by the OpenSSL Project\r
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"\r
+ *\r
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to\r
+ *    endorse or promote products derived from this software without\r
+ *    prior written permission. For written permission, please contact\r
+ *    openssl-core@openssl.org.\r
+ *\r
+ * 5. Products derived from this software may not be called "OpenSSL"\r
+ *    nor may "OpenSSL" appear in their names without prior written\r
+ *    permission of the OpenSSL Project.\r
+ *\r
+ * 6. Redistributions of any form whatsoever must retain the following\r
+ *    acknowledgment:\r
+ *    "This product includes software developed by the OpenSSL Project\r
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY\r
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR\r
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
+ * OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+#include <openssl/err.h>\r
+#include <openssl/fips.h>\r
+#include <openssl/rand.h>\r
+#include <openssl/fips_rand.h>\r
+\r
+#ifdef OPENSSL_FIPS\r
+static struct\r
+    {\r
+    unsigned char key1[8];\r
+    unsigned char key2[8];\r
+    unsigned char seed[8];\r
+    unsigned char dt[8];\r
+    } init_iv[] =\r
+    {\r
+    { \r
+    { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c },\r
+    { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 },\r
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },\r
+    { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x3c },\r
+    },\r
+    {\r
+    { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c },\r
+    { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 },\r
+    { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },\r
+    { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x40 },\r
+    },\r
+    {\r
+    { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c },\r
+    { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 },\r
+    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },\r
+    { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x7b },\r
+    },\r
+    };\r
+\r
+static const unsigned char expected_ret[][8]=\r
+    {\r
+    { 0x94, 0x4d, 0xc7, 0x21, 0x0d, 0x6d, 0x7f, 0xd7 },\r
+    { 0x02, 0x43, 0x3c, 0x94, 0x17, 0xa3, 0x32, 0x6f },\r
+    { 0xe7, 0xe2, 0xb2, 0x96, 0x4f, 0x36, 0xed, 0x41 },\r
+    };\r
+\r
+void FIPS_corrupt_rng()\r
+    {\r
+    init_iv[0].dt[0]++;\r
+    }\r
+\r
+int FIPS_selftest_rng()\r
+    {\r
+    int n;\r
+\r
+    for(n=0 ; n < 3 ; ++n)\r
+       {\r
+       unsigned char actual_ret[8];\r
+\r
+       FIPS_rand_method()->cleanup();\r
+       FIPS_set_prng_key(init_iv[n].key1,init_iv[n].key2); \r
+       FIPS_rand_seed(init_iv[n].seed,8);\r
+       FIPS_test_mode(1,init_iv[n].dt);\r
+       if ((FIPS_rand_method()->bytes(actual_ret, 8) <=0) || (memcmp(actual_ret,expected_ret[n],sizeof actual_ret)))\r
+           {\r
+           FIPS_test_mode(0,NULL);\r
+           FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED);\r
+           return 0;\r
+           }\r
+       }\r
+    FIPS_test_mode(0,NULL);\r
+    return 1;\r
+    }\r
+\r
+#endif\r
diff --git a/fips/rand/fips_rngvs.c b/fips/rand/fips_rngvs.c
new file mode 100644 (file)
index 0000000..e616664
--- /dev/null
@@ -0,0 +1,222 @@
+/*\r
+ * Crude test driver for processing the VST and MCT testvector files generated by the CMVP\r
+ * RNGVS product.\r
+ *\r
+ * Note the input files are assumed to have a _very_ specific format as described in the\r
+ * NIST document "The Random Number Generator Validation System (RNGVS)", May 25, 2004.\r
+ *\r
+*/\r
+\r
+#include <openssl/bn.h>\r
+#include <openssl/dsa.h>\r
+#include <openssl/fips.h>\r
+#include <openssl/err.h>\r
+#include <openssl/rand.h>\r
+#include <openssl/fips_rand.h>\r
+#include <string.h>\r
+\r
+int hex2bin(const char *in, unsigned char *out)\r
+    {\r
+    int n1, n2;\r
+    unsigned char ch;\r
+\r
+    for (n1=0,n2=0 ; in[n1] && in[n1] != '\n' ; )\r
+       { /* first byte */\r
+       if ((in[n1] >= '0') && (in[n1] <= '9'))\r
+           ch = in[n1++] - '0';\r
+       else if ((in[n1] >= 'A') && (in[n1] <= 'F'))\r
+           ch = in[n1++] - 'A' + 10;\r
+       else if ((in[n1] >= 'a') && (in[n1] <= 'f'))\r
+           ch = in[n1++] - 'a' + 10;\r
+       else\r
+           return -1;\r
+       if(!in[n1])\r
+           {\r
+           out[n2++]=ch;\r
+           break;\r
+           }\r
+       out[n2] = ch << 4;\r
+       /* second byte */\r
+       if ((in[n1] >= '0') && (in[n1] <= '9'))\r
+           ch = in[n1++] - '0';\r
+       else if ((in[n1] >= 'A') && (in[n1] <= 'F'))\r
+           ch = in[n1++] - 'A' + 10;\r
+       else if ((in[n1] >= 'a') && (in[n1] <= 'f'))\r
+           ch = in[n1++] - 'a' + 10;\r
+       else\r
+           return -1;\r
+       out[n2++] |= ch;\r
+       }\r
+    return n2;\r
+    }\r
+\r
+int bin2hex(const unsigned char *in,int len,char *out)\r
+    {\r
+    int n1, n2;\r
+    unsigned char ch;\r
+\r
+    for (n1=0,n2=0 ; n1 < len ; ++n1)\r
+       {\r
+       ch=in[n1] >> 4;\r
+       if (ch <= 0x09)\r
+           out[n2++]=ch+'0';\r
+       else\r
+           out[n2++]=ch-10+'a';\r
+       ch=in[n1] & 0x0f;\r
+       if(ch <= 0x09)\r
+           out[n2++]=ch+'0';\r
+       else\r
+           out[n2++]=ch-10+'a';\r
+       }\r
+    out[n2]='\0';\r
+    return n2;\r
+    }\r
+\r
+void pv(const char *tag,const unsigned char *val,int len)\r
+    {\r
+    char obuf[2048];\r
+\r
+    bin2hex(val,len,obuf);\r
+    printf("%s = %s\n",tag,obuf);\r
+    }\r
+\r
+void vst()\r
+    {\r
+    unsigned char key1[8];\r
+    unsigned char key2[8];\r
+    unsigned char v[8];\r
+    unsigned char dt[8];\r
+    unsigned char ret[8];\r
+    char buf[1024];\r
+    int n;\r
+\r
+    while(fgets(buf,sizeof buf,stdin) != NULL)\r
+       {\r
+       if(!strncmp(buf,"Key1 = ",7))\r
+           {\r
+           n=hex2bin(buf+7,key1);\r
+           pv("Key1",key1,n);\r
+           }\r
+       else if(!strncmp(buf,"Key2 = ",7))\r
+           {\r
+           n=hex2bin(buf+7,key2);\r
+           pv("Key1",key2,n);\r
+           }\r
+       else if(!strncmp(buf,"DT = ",5))\r
+           {\r
+           n=hex2bin(buf+5,dt);\r
+           pv("DT",dt,n);\r
+           }\r
+       else if(!strncmp(buf,"V = ",4))\r
+           {\r
+           n=hex2bin(buf+4,v);\r
+           pv("V",v,n);\r
+\r
+           FIPS_rand_method()->cleanup();\r
+           FIPS_set_prng_key(key1,key2);\r
+           FIPS_rand_seed(v,8);\r
+           FIPS_test_mode(1,dt);\r
+           if (FIPS_rand_method()->bytes(ret,8) <= 0)\r
+               {\r
+               FIPS_test_mode(0,NULL);\r
+               FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED);\r
+               return;\r
+               }\r
+\r
+           pv("R",ret,8);\r
+           putc('\n',stdout);\r
+           }\r
+       else\r
+           fputs(buf,stdout);\r
+       }\r
+    }\r
+\r
+\r
+void mct()\r
+    {\r
+    unsigned char key1[8];\r
+    unsigned char key2[8];\r
+    unsigned char v[8];\r
+    unsigned char dt[8];\r
+    unsigned char ret[8];\r
+    char buf[1024];\r
+    int n;\r
+\r
+    BIGNUM *bn;\r
+    BIGNUM *pbn;\r
+    bn = BN_new();\r
+\r
+    while(fgets(buf,sizeof buf,stdin) != NULL)\r
+       {\r
+       if(!strncmp(buf,"Key1 = ",7))\r
+           {\r
+           n=hex2bin(buf+7,key1);\r
+           pv("Key1",key1,n);\r
+           }\r
+       else if(!strncmp(buf,"Key2 = ",7))\r
+           {\r
+           n=hex2bin(buf+7,key2);\r
+           pv("Key1",key2,n);\r
+           }\r
+       else if(!strncmp(buf,"DT = ",5))\r
+           {\r
+           n=hex2bin(buf+5,dt);\r
+           pv("DT",dt,n);\r
+           }\r
+       else if(!strncmp(buf,"V = ",4))\r
+           {\r
+           int iter;\r
+           n=hex2bin(buf+4,v);\r
+           pv("V",v,n);\r
+\r
+           FIPS_rand_method()->cleanup();\r
+           FIPS_set_prng_key(key1,key2);\r
+           FIPS_rand_seed(v,8);\r
+           for (iter=0; iter < 10000; ++iter)\r
+               {\r
+               FIPS_test_mode(1,dt);\r
+               if (FIPS_rand_method()->bytes(ret,8) <= 0)\r
+                   {\r
+                   FIPS_test_mode(0,NULL);\r
+                   FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED);\r
+                   return;\r
+                   }\r
+               pbn = BN_bin2bn(dt,8,bn);\r
+               n = BN_add(bn,bn,BN_value_one());\r
+               n = BN_bn2bin(bn,dt);\r
+               }\r
+\r
+           pv("R",ret,8);\r
+           putc('\n',stdout);\r
+           }\r
+       else\r
+           fputs(buf,stdout);\r
+       }\r
+    BN_free(bn);\r
+    }\r
+\r
+int main(int argc,char **argv)\r
+    {\r
+    if(argc != 2)\r
+       {\r
+       fprintf(stderr,"%s [mct|vst]\n",argv[0]);\r
+       exit(1);\r
+       }\r
+    if(!FIPS_mode_set(1,argv[0]))\r
+       {\r
+       ERR_load_crypto_strings();\r
+       ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE));\r
+       exit(1);\r
+       }\r
+    if(!strcmp(argv[1],"mct"))\r
+       mct();\r
+    else if(!strcmp(argv[1],"vst"))\r
+       vst();\r
+    else\r
+       {\r
+       fprintf(stderr,"Don't know how to %s.\n",argv[1]);\r
+       exit(1);\r
+       }\r
+\r
+    return 0;\r
+    }\r