The efforts to eliminate the dual-representation of zero and to ensure
[openssl.git] / crypto / bn / bn.h
index d7a5fce6ea426c2dc22e866982da7e8e9824b512..a01f193daaf212b8b16333280e2f465eb73032ec 100644 (file)
 extern "C" {
 #endif
 
+/* These preprocessor symbols control various aspects of the bignum headers and
+ * library code. They're not defined by any "normal" configuration, as they are
+ * intended for development and testing purposes. NB: defining all three can be
+ * useful for debugging application code as well as openssl itself.
+ *
+ * BN_DEBUG - turn on various debugging alterations to the bignum code
+ * BN_DEBUG_RAND - uses random poisoning of unused words to trip up
+ * mismanagement of bignum internals. You must also define BN_DEBUG.
+ * BN_STRICT - disables anything (not already caught by BN_DEBUG) that uses the
+ * old ambiguity over zero representation. At some point, this behaviour should
+ * become standard.
+ */
+/* #define BN_DEBUG */
+/* #define BN_DEBUG_RAND */
+/* #define BN_STRICT */
+
 #ifdef OPENSSL_SYS_VMS
 #undef BN_LLONG /* experimental, so far... */
 #endif
@@ -238,7 +254,9 @@ extern "C" {
 
 #define BN_FLG_MALLOCED                0x01
 #define BN_FLG_STATIC_DATA     0x02
+#ifndef OPENSSL_NO_DEPRECATED
 #define BN_FLG_FREE            0x8000  /* used for debuging */
+#endif
 #define BN_set_flags(b,n)      ((b)->flags|=(n))
 #define BN_get_flags(b,n)      ((b)->flags&(n))
 
@@ -341,16 +359,30 @@ int BN_GENCB_call(BN_GENCB *cb, int a, int b);
 
 #define BN_num_bytes(a)        ((BN_num_bits(a)+7)/8)
 
-/* Note that BN_abs_is_word does not work reliably for w == 0 */
-#define BN_abs_is_word(a,w) (((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w)))
-#define BN_is_zero(a)       (((a)->top == 0) || BN_abs_is_word(a,0))
+/* Note that BN_abs_is_word didn't work reliably for w == 0 until 0.9.8 */
+#define BN_abs_is_word(a,w) ((((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w))) || \
+                               (((w) == 0) && ((a)->top == 0)))
+#ifdef BN_STRICT
+#define BN_is_zero(a)       ((a)->top == 0)
+#else
+#define BN_is_zero(a)       BN_abs_is_word(a,0)
+#endif
 #define BN_is_one(a)        (BN_abs_is_word((a),1) && !(a)->neg)
-#define BN_is_word(a,w)     ((w) ? BN_abs_is_word((a),(w)) && !(a)->neg : \
-                                   BN_is_zero((a)))
+#define BN_is_word(a,w)     (BN_abs_is_word((a),(w)) && (!(w) || !(a)->neg))
 #define BN_is_odd(a)       (((a)->top > 0) && ((a)->d[0] & 1))
 
 #define BN_one(a)      (BN_set_word((a),1))
+#define BN_zero_ex(a) \
+       do { \
+               BIGNUM *_tmp_bn = (a); \
+               _tmp_bn->top = 0; \
+               _tmp_bn->neg = 0; \
+       } while(0)
+#ifdef OPENSSL_NO_DEPRECATED
+#define BN_zero(a)     BN_zero_ex(a)
+#else
 #define BN_zero(a)     (BN_set_word((a),0))
+#endif
 /* BN_set_sign(BIGNUM *, int) sets the sign of a BIGNUM
  * (0 for a non-negative value, 1 for negative) */
 #define BN_set_sign(a,b) ((a)->neg = (b))
@@ -363,7 +395,9 @@ int BN_GENCB_call(BN_GENCB *cb, int a, int b);
 const BIGNUM *BN_value_one(void);
 char * BN_options(void);
 BN_CTX *BN_CTX_new(void);
+#ifndef OPENSSL_NO_DEPRECATED
 void   BN_CTX_init(BN_CTX *c);
+#endif
 void   BN_CTX_free(BN_CTX *c);
 void   BN_CTX_start(BN_CTX *ctx);
 BIGNUM *BN_CTX_get(BN_CTX *ctx);
@@ -588,7 +622,85 @@ const BIGNUM *BN_get0_nist_prime_521(void);
 BIGNUM *bn_expand2(BIGNUM *a, int words);
 BIGNUM *bn_dup_expand(const BIGNUM *a, int words);
 
-#define bn_fix_top(a) \
+/* Bignum consistency macros
+ * There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
+ * bignum data after direct manipulations on the data. There is also an
+ * "internal" macro, bn_check_top(), for verifying that there are no leading
+ * zeroes. Unfortunately, some auditing is required due to the fact that
+ * bn_fix_top() has become an overabused duct-tape because bignum data is
+ * occasionally passed around in an inconsistent state. So the following
+ * changes have been made to sort this out;
+ * - bn_fix_top()s implementation has been moved to bn_correct_top()
+ * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
+ *   bn_check_top() is as before.
+ * - if BN_DEBUG *is* defined;
+ *   - bn_check_top() tries to pollute unused words even if the bignum 'top' is
+ *     consistent. (ed: only if BN_DEBUG_RAND is defined)
+ *   - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
+ * The idea is to have debug builds flag up inconsistent bignums when they
+ * occur. If that occurs in a bn_fix_top(), we examine the code in question; if
+ * the use of bn_fix_top() was appropriate (ie. it follows directly after code
+ * that manipulates the bignum) it is converted to bn_correct_top(), and if it
+ * was not appropriate, we convert it permanently to bn_check_top() and track
+ * down the cause of the bug. Eventually, no internal code should be using the
+ * bn_fix_top() macro. External applications and libraries should try this with
+ * their own code too, both in terms of building against the openssl headers
+ * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
+ * defined. This not only improves external code, it provides more test
+ * coverage for openssl's own code.
+ */
+
+#ifdef BN_DEBUG
+
+/* We only need assert() when debugging */
+#include <assert.h>
+
+#ifdef BN_DEBUG_RAND
+/* To avoid "make update" cvs wars due to BN_DEBUG, use some tricks */
+#ifndef RAND_pseudo_bytes
+int RAND_pseudo_bytes(unsigned char *buf,int num);
+#define BN_DEBUG_TRIX
+#endif
+#define bn_pollute(a) \
+       do { \
+               const BIGNUM *_bnum1 = (a); \
+               if(_bnum1->top < _bnum1->dmax) { \
+                       unsigned char _tmp_char; \
+                       /* We cast away const without the compiler knowing, any \
+                        * *genuinely* constant variables that aren't mutable \
+                        * wouldn't be constructed with top!=dmax. */ \
+                       BN_ULONG *_not_const; \
+                       memcpy(&_not_const, &_bnum1->d, sizeof(BN_ULONG*)); \
+                       RAND_pseudo_bytes(&_tmp_char, 1); \
+                       memset((unsigned char *)(_not_const + _bnum1->top), _tmp_char, \
+                               (_bnum1->dmax - _bnum1->top) * sizeof(BN_ULONG)); \
+               } \
+       } while(0)
+#ifdef BN_DEBUG_TRIX
+#undef RAND_pseudo_bytes
+#endif
+#else
+#define bn_pollute(a)
+#endif
+#define bn_check_top(a) \
+       do { \
+               const BIGNUM *_bnum2 = (a); \
+               assert((_bnum2->top == 0) || \
+                               (_bnum2->d[_bnum2->top - 1] != 0)); \
+               bn_pollute(_bnum2); \
+       } while(0)
+
+#define bn_fix_top(a)          bn_check_top(a)
+
+#else /* !BN_DEBUG */
+
+#define bn_pollute(a)
+#define bn_check_top(a)
+#define bn_fix_top(a)          bn_correct_top(a)
+
+#endif
+
+#define bn_correct_top(a) \
         { \
         BN_ULONG *ftl; \
        if ((a)->top > 0) \
@@ -596,6 +708,7 @@ BIGNUM *bn_dup_expand(const BIGNUM *a, int words);
                for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \
                if (*(ftl--)) break; \
                } \
+       bn_pollute(a); \
        }
 
 BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);