Add non-FIPS algorithm blocking and selftest checking.
authorDr. Stephen Henson <steve@openssl.org>
Tue, 15 Feb 2011 16:03:47 +0000 (16:03 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 15 Feb 2011 16:03:47 +0000 (16:03 +0000)
CHANGES
crypto/evp/evp.h
crypto/evp/evp_err.c
crypto/fips_err.h
fips/des/fips_des_selftest.c
fips/dsa/fips_dsa_sign.c
fips/fips.h
fips/rsa/fips_rsa_sign.c
fips/utl/fips_enc.c
fips/utl/fips_md.c

diff --git a/CHANGES b/CHANGES
index 315bf8e..237234d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,10 +4,13 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Add selftest checks and algorithm block of non-fips algorithms in
+     FIPS mode. Remove DES2 from selftests.
+     [Steve Henson]
+
   *) Add ECDSA code to fips module. Add tiny fips_ecdsa_check to just
      return internal method without any ENGINE dependencies. Add new
-     tiny fips sign and verify functions. Initial incomplete algorithm
-     test program.
+     tiny fips sign and verify functions.
      [Steve Henson]
 
   *) New build option no-ec2m to disable characteristic 2 code.
index 042dc1c..240d9d5 100644 (file)
@@ -1319,6 +1319,7 @@ void ERR_load_EVP_strings(void);
 #define EVP_R_DECODE_ERROR                              114
 #define EVP_R_DIFFERENT_KEY_TYPES                       101
 #define EVP_R_DIFFERENT_PARAMETERS                      153
+#define EVP_R_DISABLED_FOR_FIPS                                 163
 #define EVP_R_ENCODE_ERROR                              115
 #define EVP_R_EVP_PBE_CIPHERINIT_ERROR                  119
 #define EVP_R_EXPECTING_AN_RSA_KEY                      127
index 92e0493..a9e2656 100644 (file)
@@ -162,6 +162,7 @@ static ERR_STRING_DATA EVP_str_reasons[]=
 {ERR_REASON(EVP_R_DECODE_ERROR)          ,"decode error"},
 {ERR_REASON(EVP_R_DIFFERENT_KEY_TYPES)   ,"different key types"},
 {ERR_REASON(EVP_R_DIFFERENT_PARAMETERS)  ,"different parameters"},
+{ERR_REASON(EVP_R_DISABLED_FOR_FIPS)     ,"disabled for fips"},
 {ERR_REASON(EVP_R_ENCODE_ERROR)          ,"encode error"},
 {ERR_REASON(EVP_R_EVP_PBE_CIPHERINIT_ERROR),"evp pbe cipherinit error"},
 {ERR_REASON(EVP_R_EXPECTING_AN_RSA_KEY)  ,"expecting an rsa key"},
index d2d9eb0..4ea1839 100644 (file)
@@ -80,6 +80,8 @@ static ERR_STRING_DATA FIPS_str_functs[]=
 {ERR_FUNC(FIPS_F_FIPS_CHECK_DSA),      "FIPS_CHECK_DSA"},
 {ERR_FUNC(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT),       "FIPS_check_incore_fingerprint"},
 {ERR_FUNC(FIPS_F_FIPS_CHECK_RSA),      "fips_check_rsa"},
+{ERR_FUNC(FIPS_F_FIPS_CIPHERINIT),     "FIPS_CIPHERINIT"},
+{ERR_FUNC(FIPS_F_FIPS_DIGESTINIT),     "FIPS_DIGESTINIT"},
 {ERR_FUNC(FIPS_F_FIPS_DSA_CHECK),      "FIPS_DSA_CHECK"},
 {ERR_FUNC(FIPS_F_FIPS_MODE_SET),       "FIPS_mode_set"},
 {ERR_FUNC(FIPS_F_FIPS_PKEY_SIGNATURE_TEST),    "fips_pkey_signature_test"},
index 7b7543b..6ce556e 100644 (file)
@@ -111,14 +111,6 @@ int FIPS_selftest_des()
     int n, ret = 0;
     EVP_CIPHER_CTX ctx;
     FIPS_cipher_ctx_init(&ctx);
-    /* Encrypt/decrypt with 2-key 3DES and compare to known answers */
-    for(n=0 ; n < 2 ; ++n)
-       {
-       if (!fips_cipher_test(&ctx, EVP_des_ede_ecb(),
-                               tests2[n].key, NULL,
-                               tests2[n].plaintext, tests2[n].ciphertext, 8))
-               goto err;
-       }
 
     /* Encrypt/decrypt with 3DES and compare to known answers */
     for(n=0 ; n < 2 ; ++n)
index ab28cdf..1668930 100644 (file)
@@ -84,6 +84,7 @@ DSA_SIG * FIPS_dsa_sign_ctx(DSA *dsa, EVP_MD_CTX *ctx)
 
 DSA_SIG * FIPS_dsa_sign_digest(DSA *dsa, const unsigned char *dig, int dlen)
        {
+       FIPS_selftest_check();
        return dsa->meth->dsa_do_sign(dig, dlen, dsa);
        }
 
@@ -101,6 +102,7 @@ int FIPS_dsa_verify_ctx(DSA *dsa, EVP_MD_CTX *ctx, DSA_SIG *s)
 int FIPS_dsa_verify_digest(DSA *dsa,
                                const unsigned char *dig, int dlen, DSA_SIG *s)
        {
+       FIPS_selftest_check();
        return dsa->meth->dsa_do_verify(dig,dlen,s,dsa);
        }
 
index 38a27bb..64115da 100644 (file)
@@ -114,6 +114,9 @@ void FIPS_set_locking_callbacks(void (*func)(int mode, int type,
                                int (*add_cb)(int *pointer, int amount,
                                        int type, const char *file, int line));
 
+#define FIPS_ERROR_IGNORED(alg) OpenSSLDie(__FILE__, __LINE__, \
+               alg " previous FIPS forbidden algorithm error ignored");
+
 /* Where necessary redirect standard OpenSSL APIs to FIPS versions */
 
 #if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI)
@@ -179,6 +182,8 @@ void ERR_load_FIPS_strings(void);
 #define FIPS_F_FIPS_CHECK_DSA                           104
 #define FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT            105
 #define FIPS_F_FIPS_CHECK_RSA                           106
+#define FIPS_F_FIPS_CIPHERINIT                          128
+#define FIPS_F_FIPS_DIGESTINIT                          127
 #define FIPS_F_FIPS_DSA_CHECK                           107
 #define FIPS_F_FIPS_MODE_SET                            108
 #define FIPS_F_FIPS_PKEY_SIGNATURE_TEST                         109
index f54d890..46d0d40 100644 (file)
@@ -219,6 +219,8 @@ int FIPS_rsa_sign_digest(RSA *rsa, const unsigned char *md, int md_len,
        /* Largest DigestInfo: 19 (max encoding) + max MD */
        unsigned char tmpdinfo[19 + EVP_MAX_MD_SIZE];
 
+       FIPS_selftest_check();
+
        md_type = M_EVP_MD_type(mhash);
 
        if (rsa_pad_mode == RSA_X931_PADDING)
@@ -326,6 +328,8 @@ int FIPS_rsa_verify_digest(RSA *rsa, const unsigned char *dig, int diglen,
                return(0);
                }
 
+       FIPS_selftest_check();
+
        md_type = M_EVP_MD_type(mhash);
 
        s= OPENSSL_malloc((unsigned int)siglen);
index d7f3261..b3db931 100644 (file)
@@ -78,9 +78,53 @@ EVP_CIPHER_CTX *FIPS_cipher_ctx_new(void)
        return ctx;
        }
 
+/* The purpose of these is to trap programs that attempt to use non FIPS
+ * algorithms in FIPS mode and ignore the errors.
+ */
+
+static int bad_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                   const unsigned char *iv, int enc)
+       { FIPS_ERROR_IGNORED("Cipher init"); return 0;}
+
+static int bad_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                        const unsigned char *in, size_t inl)
+       { FIPS_ERROR_IGNORED("Cipher update"); return 0;}
+
+/* NB: no cleanup because it is allowed after failed init */
+
+static int bad_set_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
+       { FIPS_ERROR_IGNORED("Cipher set_asn1"); return 0;}
+static int bad_get_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
+       { FIPS_ERROR_IGNORED("Cipher get_asn1"); return 0;}
+static int bad_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+       { FIPS_ERROR_IGNORED("Cipher ctrl"); return 0;}
+
+static const EVP_CIPHER bad_cipher =
+       {
+       0,
+       0,
+       0,
+       0,
+       0,
+       bad_init,
+       bad_do_cipher,
+       NULL,
+       0,
+       bad_set_asn1,
+       bad_get_asn1,
+       bad_ctrl,
+       NULL
+       };
+
 int FIPS_cipherinit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
             const unsigned char *key, const unsigned char *iv, int enc)
        {
+       if(FIPS_selftest_failed())
+               {
+               FIPSerr(FIPS_F_FIPS_CIPHERINIT,FIPS_R_FIPS_SELFTEST_FAILED);
+               ctx->cipher = &bad_cipher;
+               return 0;
+               }
        if (enc == -1)
                enc = ctx->encrypt;
        else
@@ -91,6 +135,14 @@ int FIPS_cipherinit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
                }
        if (cipher)
                {
+               /* Only FIPS ciphers allowed */
+               if (FIPS_mode() && !(cipher->flags & EVP_CIPH_FLAG_FIPS) &&
+                       !(ctx->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW))
+                       {
+                       EVPerr(EVP_F_FIPS_CIPHERINIT, EVP_R_DISABLED_FOR_FIPS);
+                       ctx->cipher = &bad_cipher;
+                       return 0;
+                       }
                /* Ensure a context left lying around from last time is cleared
                 * (the previous check attempted to avoid this if the same
                 * ENGINE and EVP_CIPHER could be used). */
@@ -208,6 +260,7 @@ int FIPS_cipher_ctx_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
                EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
                return 0;
        }
+       FIPS_selftest_check();
 
        if(!ctx->cipher->ctrl) {
                EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
@@ -226,5 +279,6 @@ int FIPS_cipher_ctx_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 int FIPS_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                        const unsigned char *in, unsigned int inl)
        {
+       FIPS_selftest_check();
        return ctx->cipher->do_cipher(ctx,out,in,inl);
        }
index 19595dd..3714950 100644 (file)
@@ -135,9 +135,51 @@ EVP_MD_CTX *FIPS_md_ctx_create(void)
        return ctx;
        }
 
+/* The purpose of these is to trap programs that attempt to use non FIPS
+ * algorithms in FIPS mode and ignore the errors.
+ */
+
+static int bad_init(EVP_MD_CTX *ctx)
+       { FIPS_ERROR_IGNORED("Digest init"); return 0;}
+
+static int bad_update(EVP_MD_CTX *ctx,const void *data,size_t count)
+       { FIPS_ERROR_IGNORED("Digest update"); return 0;}
+
+static int bad_final(EVP_MD_CTX *ctx,unsigned char *md)
+       { FIPS_ERROR_IGNORED("Digest Final"); return 0;}
+
+static const EVP_MD bad_md =
+       {
+       0,
+       0,
+       0,
+       0,
+       bad_init,
+       bad_update,
+       bad_final,
+       NULL,
+       NULL,
+       NULL,
+       0,
+       {0,0,0,0},
+       };
+
 int FIPS_digestinit(EVP_MD_CTX *ctx, const EVP_MD *type)
        {
        M_EVP_MD_CTX_clear_flags(ctx,EVP_MD_CTX_FLAG_CLEANED);
+       if(FIPS_selftest_failed())
+               {
+               FIPSerr(FIPS_F_FIPS_DIGESTINIT,FIPS_R_FIPS_SELFTEST_FAILED);
+               ctx->digest = &bad_md;
+               return 0;
+               }
+       if(FIPS_mode() && !(type->flags & EVP_MD_FLAG_FIPS) &&
+               !(ctx->flags & EVP_MD_CTX_FLAG_NON_FIPS_ALLOW))
+               {
+               EVPerr(EVP_F_FIPS_DIGESTINIT, EVP_R_DISABLED_FOR_FIPS);
+               ctx->digest = &bad_md;
+               return 0;
+               }
        if (ctx->digest != type)
                {
                if (ctx->digest && ctx->digest->ctx_size)
@@ -162,6 +204,7 @@ int FIPS_digestinit(EVP_MD_CTX *ctx, const EVP_MD *type)
 
 int FIPS_digestupdate(EVP_MD_CTX *ctx, const void *data, size_t count)
        {
+       FIPS_selftest_check();
        return ctx->update(ctx,data,count);
        }
 
@@ -170,6 +213,8 @@ int FIPS_digestfinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
        {
        int ret;
 
+       FIPS_selftest_check();
+
        OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
        ret=ctx->digest->final(ctx,md);
        if (size != NULL)