crypto: drbg - panic on continuous self test error
[deliverable/linux.git] / crypto / drbg.c
index 54cfd4820abc8f321fe1dac7c0212107d16d521d..96138396ce019dc29e82be1bd46b5785e63719ed 100644 (file)
@@ -98,6 +98,7 @@
  */
 
 #include <crypto/drbg.h>
+#include <linux/string.h>
 
 /***************************************************************
  * Backend cipher definitions available to DRBG
@@ -222,15 +223,6 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags)
  * function. Thus, the function implicitly knows the size of the
  * buffer.
  *
- * The FIPS test can be called in an endless loop until it returns
- * true. Although the code looks like a potential for a deadlock, it
- * is not the case, because returning a false cannot mathematically
- * occur (except once when a reseed took place and the updated state
- * would is now set up such that the generation of new value returns
- * an identical one -- this is most unlikely and would happen only once).
- * Thus, if this function repeatedly returns false and thus would cause
- * a deadlock, the integrity of the entire kernel is lost.
- *
  * @drbg DRBG handle
  * @buf output buffer of random data to be checked
  *
@@ -257,6 +249,8 @@ static bool drbg_fips_continuous_test(struct drbg_state *drbg,
                return false;
        }
        ret = memcmp(drbg->prev, buf, drbg_blocklen(drbg));
+       if (!ret)
+               panic("DRBG continuous self test failed\n");
        memcpy(drbg->prev, buf, drbg_blocklen(drbg));
        /* the test shall pass when the two compared values are not equal */
        return ret != 0;
@@ -283,38 +277,6 @@ static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf)
 
        conversion->conv = cpu_to_be32(val);
 }
-
-/*
- * Increment buffer
- *
- * @dst buffer to increment
- * @add value to add
- */
-static inline void drbg_add_buf(unsigned char *dst, size_t dstlen,
-                               const unsigned char *add, size_t addlen)
-{
-       /* implied: dstlen > addlen */
-       unsigned char *dstptr;
-       const unsigned char *addptr;
-       unsigned int remainder = 0;
-       size_t len = addlen;
-
-       dstptr = dst + (dstlen-1);
-       addptr = add + (addlen-1);
-       while (len) {
-               remainder += *dstptr + *addptr;
-               *dstptr = remainder & 0xff;
-               remainder >>= 8;
-               len--; dstptr--; addptr--;
-       }
-       len = dstlen - addlen;
-       while (len && remainder > 0) {
-               remainder = *dstptr + 1;
-               *dstptr = remainder & 0xff;
-               remainder >>= 8;
-               len--; dstptr--;
-       }
-}
 #endif /* defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR) */
 
 /******************************************************************
@@ -323,6 +285,13 @@ static inline void drbg_add_buf(unsigned char *dst, size_t dstlen,
 
 #ifdef CONFIG_CRYPTO_DRBG_CTR
 #define CRYPTO_DRBG_CTR_STRING "CTR "
+MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes256");
+MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes256");
+MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes192");
+MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192");
+MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128");
+MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128");
+
 static int drbg_kcapi_sym(struct drbg_state *drbg, const unsigned char *key,
                          unsigned char *outval, const struct drbg_string *in);
 static int drbg_init_sym_kernel(struct drbg_state *drbg);
@@ -522,9 +491,9 @@ static int drbg_ctr_df(struct drbg_state *drbg,
        ret = 0;
 
 out:
-       memset(iv, 0, drbg_blocklen(drbg));
-       memset(temp, 0, drbg_statelen(drbg));
-       memset(pad, 0, drbg_blocklen(drbg));
+       memzero_explicit(iv, drbg_blocklen(drbg));
+       memzero_explicit(temp, drbg_statelen(drbg));
+       memzero_explicit(pad, drbg_blocklen(drbg));
        return ret;
 }
 
@@ -554,7 +523,6 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed,
        unsigned char *temp_p, *df_data_p; /* pointer to iterate over buffers */
        unsigned int len = 0;
        struct drbg_string cipherin;
-       unsigned char prefix = DRBG_PREFIX1;
 
        memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
        if (3 > reseed)
@@ -574,7 +542,7 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed,
         */
        while (len < (drbg_statelen(drbg))) {
                /* 10.2.1.2 step 2.1 */
-               drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
+               crypto_inc(drbg->V, drbg_blocklen(drbg));
                /*
                 * 10.2.1.2 step 2.2 */
                ret = drbg_kcapi_sym(drbg, drbg->C, temp + len, &cipherin);
@@ -599,9 +567,9 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed,
        ret = 0;
 
 out:
-       memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
+       memzero_explicit(temp, drbg_statelen(drbg) + drbg_blocklen(drbg));
        if (2 != reseed)
-               memset(df_data, 0, drbg_statelen(drbg));
+               memzero_explicit(df_data, drbg_statelen(drbg));
        return ret;
 }
 
@@ -617,7 +585,6 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
        int len = 0;
        int ret = 0;
        struct drbg_string data;
-       unsigned char prefix = DRBG_PREFIX1;
 
        memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
 
@@ -629,7 +596,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
        }
 
        /* 10.2.1.5.2 step 4.1 */
-       drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
+       crypto_inc(drbg->V, drbg_blocklen(drbg));
        drbg_string_fill(&data, drbg->V, drbg_blocklen(drbg));
        while (len < buflen) {
                int outlen = 0;
@@ -643,7 +610,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
                          drbg_blocklen(drbg) : (buflen - len);
                if (!drbg_fips_continuous_test(drbg, drbg->scratchpad)) {
                        /* 10.2.1.5.2 step 6 */
-                       drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
+                       crypto_inc(drbg->V, drbg_blocklen(drbg));
                        continue;
                }
                /* 10.2.1.5.2 step 4.3 */
@@ -651,7 +618,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
                len += outlen;
                /* 10.2.1.5.2 step 6 */
                if (len < buflen)
-                       drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1);
+                       crypto_inc(drbg->V, drbg_blocklen(drbg));
        }
 
        /* 10.2.1.5.2 step 6 */
@@ -660,7 +627,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
                len = ret;
 
 out:
-       memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
+       memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
        return len;
 }
 
@@ -685,6 +652,15 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg);
 
 #ifdef CONFIG_CRYPTO_DRBG_HMAC
 #define CRYPTO_DRBG_HMAC_STRING "HMAC "
+MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512");
+MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512");
+MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384");
+MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384");
+MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256");
+MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256");
+MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1");
+MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1");
+
 /* update function of HMAC DRBG as defined in 10.1.2.2 */
 static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
                            int reseed)
@@ -796,6 +772,47 @@ static struct drbg_state_ops drbg_hmac_ops = {
 
 #ifdef CONFIG_CRYPTO_DRBG_HASH
 #define CRYPTO_DRBG_HASH_STRING "HASH "
+MODULE_ALIAS_CRYPTO("drbg_pr_sha512");
+MODULE_ALIAS_CRYPTO("drbg_nopr_sha512");
+MODULE_ALIAS_CRYPTO("drbg_pr_sha384");
+MODULE_ALIAS_CRYPTO("drbg_nopr_sha384");
+MODULE_ALIAS_CRYPTO("drbg_pr_sha256");
+MODULE_ALIAS_CRYPTO("drbg_nopr_sha256");
+MODULE_ALIAS_CRYPTO("drbg_pr_sha1");
+MODULE_ALIAS_CRYPTO("drbg_nopr_sha1");
+
+/*
+ * Increment buffer
+ *
+ * @dst buffer to increment
+ * @add value to add
+ */
+static inline void drbg_add_buf(unsigned char *dst, size_t dstlen,
+                               const unsigned char *add, size_t addlen)
+{
+       /* implied: dstlen > addlen */
+       unsigned char *dstptr;
+       const unsigned char *addptr;
+       unsigned int remainder = 0;
+       size_t len = addlen;
+
+       dstptr = dst + (dstlen-1);
+       addptr = add + (addlen-1);
+       while (len) {
+               remainder += *dstptr + *addptr;
+               *dstptr = remainder & 0xff;
+               remainder >>= 8;
+               len--; dstptr--; addptr--;
+       }
+       len = dstlen - addlen;
+       while (len && remainder > 0) {
+               remainder = *dstptr + 1;
+               *dstptr = remainder & 0xff;
+               remainder >>= 8;
+               len--; dstptr--;
+       }
+}
+
 /*
  * scratchpad usage: as drbg_hash_update and drbg_hash_df are used
  * interlinked, the scratchpad is used as follows:
@@ -848,7 +865,7 @@ static int drbg_hash_df(struct drbg_state *drbg,
        }
 
 out:
-       memset(tmp, 0, drbg_blocklen(drbg));
+       memzero_explicit(tmp, drbg_blocklen(drbg));
        return ret;
 }
 
@@ -892,7 +909,7 @@ static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed,
        ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2);
 
 out:
-       memset(drbg->scratchpad, 0, drbg_statelen(drbg));
+       memzero_explicit(drbg->scratchpad, drbg_statelen(drbg));
        return ret;
 }
 
@@ -927,7 +944,7 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg,
                     drbg->scratchpad, drbg_blocklen(drbg));
 
 out:
-       memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
+       memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
        return ret;
 }
 
@@ -942,7 +959,6 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
        unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg);
        struct drbg_string data;
        LIST_HEAD(datalist);
-       unsigned char prefix = DRBG_PREFIX1;
 
        memset(src, 0, drbg_statelen(drbg));
        memset(dst, 0, drbg_blocklen(drbg));
@@ -963,7 +979,7 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
                outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
                          drbg_blocklen(drbg) : (buflen - len);
                if (!drbg_fips_continuous_test(drbg, dst)) {
-                       drbg_add_buf(src, drbg_statelen(drbg), &prefix, 1);
+                       crypto_inc(src, drbg_statelen(drbg));
                        continue;
                }
                /* 10.1.1.4 step hashgen 4.2 */
@@ -971,11 +987,11 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
                len += outlen;
                /* 10.1.1.4 hashgen step 4.3 */
                if (len < buflen)
-                       drbg_add_buf(src, drbg_statelen(drbg), &prefix, 1);
+                       crypto_inc(src, drbg_statelen(drbg));
        }
 
 out:
-       memset(drbg->scratchpad, 0,
+       memzero_explicit(drbg->scratchpad,
               (drbg_statelen(drbg) + drbg_blocklen(drbg)));
        return len;
 }
@@ -1024,7 +1040,7 @@ static int drbg_hash_generate(struct drbg_state *drbg,
        drbg_add_buf(drbg->V, drbg_statelen(drbg), u.req, 8);
 
 out:
-       memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
+       memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
        return len;
 }
 
This page took 0.030254 seconds and 5 git commands to generate.