BN_copy now propagates BN_FLG_CONSTTIME
[openssl.git] / crypto / bn / bn_lib.c
index ccdefb354f4f7a7be8d66b256df258b1b3c7e714..f0a3bf1e3d452a4f8e47c1098656a988a2f0020a 100644 (file)
@@ -170,7 +170,7 @@ int BN_num_bits(const BIGNUM *a)
 
 static void bn_free_d(BIGNUM *a)
 {
-    if (BN_get_flags(a,BN_FLG_SECURE))
+    if (BN_get_flags(a, BN_FLG_SECURE))
         OPENSSL_secure_free(a->d);
     else
         OPENSSL_free(a->d);
@@ -245,9 +245,7 @@ BIGNUM *BN_new(void)
 /* The caller MUST check that words > b->dmax before calling this */
 static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
 {
-    BN_ULONG *A, *a = NULL;
-    const BN_ULONG *B;
-    int i;
+    BN_ULONG *a = NULL;
 
     bn_check_top(b);
 
@@ -259,57 +257,20 @@ static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
         BNerr(BN_F_BN_EXPAND_INTERNAL, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
         return (NULL);
     }
-    if (BN_get_flags(b,BN_FLG_SECURE))
-        a = A = OPENSSL_secure_zalloc(words * sizeof(*a));
+    if (BN_get_flags(b, BN_FLG_SECURE))
+        a = OPENSSL_secure_zalloc(words * sizeof(*a));
     else
-        a = A = OPENSSL_zalloc(words * sizeof(*a));
-    if (A == NULL) {
+        a = OPENSSL_zalloc(words * sizeof(*a));
+    if (a == NULL) {
         BNerr(BN_F_BN_EXPAND_INTERNAL, ERR_R_MALLOC_FAILURE);
         return (NULL);
     }
 
-#if 1
-    B = b->d;
-    /* Check if the previous number needs to be copied */
-    if (B != NULL) {
-        for (i = b->top >> 2; i > 0; i--, A += 4, B += 4) {
-            /*
-             * The fact that the loop is unrolled
-             * 4-wise is a tribute to Intel. It's
-             * the one that doesn't have enough
-             * registers to accommodate more data.
-             * I'd unroll it 8-wise otherwise:-)
-             *
-             *              <appro@fy.chalmers.se>
-             */
-            BN_ULONG a0, a1, a2, a3;
-            a0 = B[0];
-            a1 = B[1];
-            a2 = B[2];
-            a3 = B[3];
-            A[0] = a0;
-            A[1] = a1;
-            A[2] = a2;
-            A[3] = a3;
-        }
-        switch (b->top & 3) {
-        case 3:
-            A[2] = B[2];
-        case 2:
-            A[1] = B[1];
-        case 1:
-            A[0] = B[0];
-        case 0:
-            /* Without the "case 0" some old optimizers got this wrong. */
-            ;
-        }
-    }
-#else
-    memset(A, 0, sizeof(*A) * words);
-    memcpy(A, b->d, sizeof(b->d[0]) * b->top);
-#endif
+    assert(b->top <= words);
+    if (b->top > 0)
+        memcpy(a, b->d, sizeof(*a) * b->top);
 
-    return (a);
+    return a;
 }
 
 /*
@@ -361,49 +322,23 @@ BIGNUM *BN_dup(const BIGNUM *a)
 
 BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
 {
-    int i;
-    BN_ULONG *A;
-    const BN_ULONG *B;
-
     bn_check_top(b);
 
     if (a == b)
-        return (a);
+        return a;
     if (bn_wexpand(a, b->top) == NULL)
-        return (NULL);
+        return NULL;
 
-#if 1
-    A = a->d;
-    B = b->d;
-    for (i = b->top >> 2; i > 0; i--, A += 4, B += 4) {
-        BN_ULONG a0, a1, a2, a3;
-        a0 = B[0];
-        a1 = B[1];
-        a2 = B[2];
-        a3 = B[3];
-        A[0] = a0;
-        A[1] = a1;
-        A[2] = a2;
-        A[3] = a3;
-    }
-    /* ultrix cc workaround, see comments in bn_expand_internal */
-    switch (b->top & 3) {
-    case 3:
-        A[2] = B[2];
-    case 2:
-        A[1] = B[1];
-    case 1:
-        A[0] = B[0];
-    case 0:;
-    }
-#else
-    memcpy(a->d, b->d, sizeof(b->d[0]) * b->top);
-#endif
+    if (b->top > 0)
+        memcpy(a->d, b->d, sizeof(b->d[0]) * b->top);
+
+    if (BN_get_flags(b, BN_FLG_CONSTTIME) != 0)
+        BN_set_flags(a, BN_FLG_CONSTTIME);
 
     a->top = b->top;
     a->neg = b->neg;
     bn_check_top(a);
-    return (a);
+    return a;
 }
 
 void BN_swap(BIGNUM *a, BIGNUM *b)
@@ -445,7 +380,7 @@ void BN_clear(BIGNUM *a)
 {
     bn_check_top(a);
     if (a->d != NULL)
-        memset(a->d, 0, sizeof(*a->d) * a->dmax);
+        OPENSSL_cleanse(a->d, sizeof(*a->d) * a->dmax);
     a->top = 0;
     a->neg = 0;
 }
@@ -565,9 +500,9 @@ BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret)
     if (ret == NULL)
         return (NULL);
     bn_check_top(ret);
-    s += len - 1;
+    s += len;
     /* Skip trailing zeroes. */
-    for ( ; len > 0 && *s == 0; s--, len--)
+    for ( ; len > 0 && s[-1] == 0; s--, len--)
         continue;
     n = len;
     if (n == 0) {
@@ -584,7 +519,8 @@ BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret)
     ret->neg = 0;
     l = 0;
     while (n--) {
-        l = (l << 8L) | *(s--);
+        s--;
+        l = (l << 8L) | *s;
         if (m-- == 0) {
             ret->d[--i] = l;
             l = 0;
@@ -610,10 +546,11 @@ int BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen)
     /* Add trailing zeroes if necessary */
     if (tolen > i)
         memset(to + i, 0, tolen - i);
-    to += i - 1;
+    to += i;
     while (i--) {
         l = a->d[i / BN_BYTES];
-        *(to--) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
+        to--;
+        *to = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
     }
     return tolen;
 }
@@ -1029,5 +966,7 @@ void bn_correct_top(BIGNUM *a)
         }
         a->top = tmp_top;
     }
+    if (a->top == 0)
+        a->neg = 0;
     bn_pollute(a);
 }