File libgcrypt-CVE-2024-2236_01.patch of Package libgcrypt.39215

From a611e3a25d61505698e2bb38ec2db38bc6a74820 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Tue, 10 May 2022 15:44:19 +0900
Subject: [PATCH] mpi: Fix for 64-bit for _gcry_mpih_cmp_ui.

* mpi/mpih-const-time.c (_gcry_mpih_cmp_ui): Compare 64-bit
value correctly.

--

Reported-by: Guido Vranken <guidovranken@gmail.com>
GnuPG-bug-id: 5970
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
---
 mpi/mpih-const-time.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Index: libgcrypt-1.9.4/mpi/mpih-const-time.c
===================================================================
--- libgcrypt-1.9.4.orig/mpi/mpih-const-time.c
+++ libgcrypt-1.9.4/mpi/mpih-const-time.c
@@ -22,14 +22,33 @@
 #include <stdlib.h>
 #include "mpi-internal.h"
 #include "g10lib.h"
+#include "const-time.h"
+#include "longlong.h"
 
 #define A_LIMB_1 ((mpi_limb_t)1)
 
-/* These variables are used to generate masks from conditional operation
- * flag parameters.  Use of volatile prevents compiler optimizations from
- * converting AND-masking to conditional branches.  */
-static volatile mpi_limb_t vzero = 0;
-static volatile mpi_limb_t vone = 1;
+
+/*
+ * Return 1 if X > Y and otherwise return 0.
+ */
+static inline mpi_limb_t
+mpih_ct_limb_greater_than (mpi_limb_t x, mpi_limb_t y)
+{
+  mpi_limb_t diff_hi, diff_lo;
+  sub_ddmmss (diff_hi, diff_lo, 0, y, 0, x);
+  return diff_hi >> (BITS_PER_MPI_LIMB - 1);
+}
+
+
+/*
+ * Return 1 if X < Y and otherwise return 0.
+ */
+static inline mpi_limb_t
+mpih_ct_limb_less_than (mpi_limb_t x, mpi_limb_t y)
+{
+  return mpih_ct_limb_greater_than (y, x);
+}
+
 
 /*
  *  W = U when OP_ENABLED=1
@@ -39,9 +58,10 @@ void
 _gcry_mpih_set_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
                      unsigned long op_enable)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(op_enable);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(op_enable);
   mpi_size_t i;
-  mpi_limb_t mask1 = vzero - op_enable;
-  mpi_limb_t mask2 = op_enable - vone;
 
   for (i = 0; i < usize; i++)
     {
@@ -58,21 +78,22 @@ mpi_limb_t
 _gcry_mpih_add_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
                        mpi_size_t usize, unsigned long op_enable)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(op_enable);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(op_enable);
   mpi_size_t i;
   mpi_limb_t cy;
-  mpi_limb_t mask1 = vzero - op_enable;
-  mpi_limb_t mask2 = op_enable - vone;
 
   cy = 0;
   for (i = 0; i < usize; i++)
     {
       mpi_limb_t u = up[i];
       mpi_limb_t x = u + vp[i];
-      mpi_limb_t cy1 = x < u;
+      mpi_limb_t cy1 = mpih_ct_limb_less_than(x, u);
       mpi_limb_t cy2;
 
       x = x + cy;
-      cy2 = x < cy;
+      cy2 = mpih_ct_limb_less_than(x, cy);
       cy = cy1 | cy2;
       wp[i] = (u & mask2) | (x & mask1);
     }
@@ -89,20 +110,21 @@ mpi_limb_t
 _gcry_mpih_sub_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
                        mpi_size_t usize, unsigned long op_enable)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(op_enable);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(op_enable);
   mpi_size_t i;
   mpi_limb_t cy;
-  mpi_limb_t mask1 = vzero - op_enable;
-  mpi_limb_t mask2 = op_enable - vone;
 
   cy = 0;
   for (i = 0; i < usize; i++)
     {
       mpi_limb_t u = up[i];
       mpi_limb_t x = u - vp[i];
-      mpi_limb_t cy1 = x > u;
+      mpi_limb_t cy1 = mpih_ct_limb_greater_than(x, u);
       mpi_limb_t cy2;
 
-      cy2 = x < cy;
+      cy2 = mpih_ct_limb_less_than(x, cy);
       x = x - cy;
       cy = cy1 | cy2;
       wp[i] = (u & mask2) | (x & mask1);
@@ -120,9 +142,10 @@ void
 _gcry_mpih_swap_cond (mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t usize,
                       unsigned long op_enable)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(op_enable);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(op_enable);
   mpi_size_t i;
-  mpi_limb_t mask1 = vzero - op_enable;
-  mpi_limb_t mask2 = op_enable - vone;
 
   for (i = 0; i < usize; i++)
     {
@@ -142,17 +165,18 @@ void
 _gcry_mpih_abs_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
                      unsigned long op_enable)
 {
-  mpi_size_t i;
-  mpi_limb_t mask1 = vzero - op_enable;
-  mpi_limb_t mask2 = op_enable - vone;
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(op_enable);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(op_enable);
   mpi_limb_t cy = op_enable;
+  mpi_size_t i;
 
   for (i = 0; i < usize; i++)
     {
       mpi_limb_t u = up[i];
       mpi_limb_t x = ~u + cy;
 
-      cy = (x < ~u);
+      cy = mpih_ct_limb_less_than(x, ~u);
       wp[i] = (u & mask2) | (x & mask1);
     }
 }
@@ -180,7 +204,7 @@ _gcry_mpih_mod (mpi_ptr_t vp, mpi_size_t
       unsigned int limbno = j / BITS_PER_MPI_LIMB;
       unsigned int bitno = j % BITS_PER_MPI_LIMB;
       mpi_limb_t limb = vp[limbno];
-      unsigned int the_bit = ((limb & (A_LIMB_1 << bitno)) ? 1 : 0);
+      unsigned int the_bit = (limb >> bitno) & 1;
       mpi_limb_t underflow;
       mpi_limb_t overflow;
 
@@ -201,9 +225,16 @@ _gcry_mpih_cmp_ui (mpi_ptr_t up, mpi_siz
   mpi_size_t i;
 
   for (i = 1; i < usize; i++)
-    is_all_zero &= (up[i] == 0);
+    is_all_zero &= mpih_limb_is_zero (up[i]);
 
   if (is_all_zero)
-    return up[0] - v;
+    {
+      if (up[0] < v)
+        return -1;
+      else if (up[0] > v)
+        return 1;
+      else
+        return 0;
+    }
   return 1;
 }
Index: libgcrypt-1.9.4/cipher/rsa-common.c
===================================================================
--- libgcrypt-1.9.4.orig/cipher/rsa-common.c
+++ libgcrypt-1.9.4/cipher/rsa-common.c
@@ -27,6 +27,7 @@
 #include "mpi.h"
 #include "cipher.h"
 #include "pubkey-internal.h"
+#include "const-time.h"
 
 
 /* Turn VALUE into an octet string and store it in an allocated buffer
@@ -161,6 +162,35 @@ _gcry_rsa_pkcs1_encode_for_enc (gcry_mpi
 }
 
 
+/*
+ *                    <--len-->
+ * DST-------v       v-------------SRC
+ *           [.................]
+ *            <---- buflen --->
+ *
+ * Copy the memory area SRC with LEN into another memory area DST.
+ * Conditions met:
+ *         the address SRC > DST
+ *         DST + BUFLEN == SRC + LEN.
+ *
+ * Memory access doesn't depends on LEN, but always done independently,
+ * sliding memory area by 1, 2, 4 ... until done.
+ */
+static void
+memmov_independently (void *dst, const void *src, size_t len, size_t buflen)
+{
+  size_t offset = (size_t)((char *)src - (char *)dst);
+  size_t shift;
+
+  (void)len; /* No dependency.  */
+  for (shift = 1; shift < buflen; shift <<= 1)
+    {
+      ct_memmov_cond (dst, (char *)dst + shift, buflen - shift, (offset&1));
+      offset >>= 1;
+    }
+}
+
+
 /* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
    NBITS is the size of the secret key.  On success the result is
    stored as a newly allocated buffer at R_RESULT and its valid length at
@@ -172,7 +202,9 @@ _gcry_rsa_pkcs1_decode_for_enc (unsigned
   gcry_error_t err;
   unsigned char *frame = NULL;
   size_t nframe = (nbits+7) / 8;
-  size_t n;
+  size_t n, n0;
+  unsigned int failed = 0;
+  unsigned int not_found = 1;
 
   *r_result = NULL;
 
@@ -203,33 +235,31 @@ _gcry_rsa_pkcs1_decode_for_enc (unsigned
   n = 0;
   if (!frame[0])
     n++;
-  if (frame[n++] != 0x02)
-    {
-      xfree (frame);
-      return GPG_ERR_ENCODING_PROBLEM;  /* Wrong block type.  */
-    }
+  failed |= ct_not_equal_byte (frame[n++], 0x02);
 
-  /* Skip the non-zero random bytes and the terminating zero byte.  */
-  for (; n < nframe && frame[n] != 0x00; n++)
-    ;
-  if (n+1 >= nframe)
+  /* Find the terminating zero byte.  */
+  n0 = n;
+  for (; n < nframe; n++)
     {
-      xfree (frame);
-      return GPG_ERR_ENCODING_PROBLEM; /* No zero byte.  */
+      not_found &= ct_not_equal_byte (frame[n], 0x00);
+      n0 += not_found;
     }
-  n++; /* Skip the zero byte.  */
+
+  failed |= not_found;
+  n0 += ct_is_zero (not_found); /* Skip the zero byte.  */
 
   /* To avoid an extra allocation we reuse the frame buffer.  The only
      caller of this function will anyway free the result soon.  */
-  memmove (frame, frame + n, nframe - n);
+  memmov_independently (frame, frame + n0, nframe - n0, nframe);
+
   *r_result = frame;
-  *r_resultlen = nframe - n;
+  *r_resultlen = nframe - n0;
 
   if (DBG_CIPHER)
     log_printhex ("value extracted from PKCS#1 block type 2 encoded data",
                   *r_result, *r_resultlen);
 
-  return 0;
+  return (0U - failed) & GPG_ERR_ENCODING_PROBLEM;
 }
 
 
@@ -616,7 +646,8 @@ _gcry_rsa_oaep_decode (unsigned char **r
   size_t db_len;               /* Length of DB and masked_db.  */
   size_t nkey = (nbits+7)/8;   /* Length of the key in bytes.  */
   int failed = 0;              /* Error indicator.  */
-  size_t n;
+  size_t n, n1;
+  unsigned int not_found = 1;
 
   *r_result = NULL;
 
@@ -688,51 +719,43 @@ _gcry_rsa_oaep_decode (unsigned char **r
   db_len      = nframe - 1 - hlen;
 
   /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen).  */
-  if (mgf1 (seed, hlen, masked_db, db_len, algo))
-    failed = 1;
+  failed |= (mgf1 (seed, hlen, masked_db, db_len, algo) != 0);
   for (n = 0; n < hlen; n++)
     seed[n] ^= masked_seed[n];
 
   /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len).  */
-  if (mgf1 (db, db_len, seed, hlen, algo))
-    failed = 1;
+  failed |= (mgf1 (db, db_len, seed, hlen, algo) != 0);
   for (n = 0; n < db_len; n++)
     db[n] ^= masked_db[n];
 
   /* Step 3g: Check lhash, an possible empty padding string terminated
      by 0x01 and the first byte of EM being 0.  */
-  if (memcmp (lhash, db, hlen))
-    failed = 1;
-  for (n = hlen; n < db_len; n++)
-    if (db[n] == 0x01)
-      break;
-  if (n == db_len)
-    failed = 1;
-  if (frame[0])
-    failed = 1;
+  failed |= ct_not_memequal (lhash, db, hlen);
+  for (n = n1 = hlen; n < db_len; n++)
+    {
+      not_found &= ct_not_equal_byte (db[n], 0x01);
+      n1 += not_found;
+    }
+  failed |= not_found;
+  failed |= ct_not_equal_byte (frame[0], 0x00);
 
   xfree (lhash);
   xfree (frame);
-  if (failed)
-    {
-      xfree (seed);
-      return GPG_ERR_ENCODING_PROBLEM;
-    }
 
   /* Step 4: Output M.  */
   /* To avoid an extra allocation we reuse the seed buffer.  The only
      caller of this function will anyway free the result soon.  */
-  n++;
-  memmove (seed, db + n, db_len - n);
+  n1 += !not_found;
+  memmov_independently (seed, db + n1, db_len - n1, nframe - 1);
   *r_result = seed;
-  *r_resultlen = db_len - n;
+  *r_resultlen = db_len - n1;
   seed = NULL;
 
   if (DBG_CIPHER)
     log_printhex ("value extracted from OAEP encoded data",
                   *r_result, *r_resultlen);
 
-  return 0;
+  return (0U - failed) & GPG_ERR_ENCODING_PROBLEM;
 }
 
 
Index: libgcrypt-1.9.4/cipher/rsa.c
===================================================================
--- libgcrypt-1.9.4.orig/cipher/rsa.c
+++ libgcrypt-1.9.4/cipher/rsa.c
@@ -33,6 +33,7 @@
 #include "mpi.h"
 #include "cipher.h"
 #include "pubkey-internal.h"
+#include "const-time.h"
 
 
 typedef struct
@@ -1434,7 +1435,7 @@ static gcry_err_code_t
 rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 
 {
-  gpg_err_code_t rc;
+  gpg_err_code_t rc, rc_sexp;
   struct pk_encoding_ctx ctx;
   gcry_sexp_t l1 = NULL;
   gcry_mpi_t data = NULL;
@@ -1443,6 +1444,8 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
   unsigned char *unpad = NULL;
   size_t unpadlen = 0;
   unsigned int nbits = rsa_get_nbits (keyparms);
+  gcry_sexp_t result = NULL;
+  gcry_sexp_t dummy = NULL;
 
   rc = rsa_check_keysize (nbits);
   if (rc)
@@ -1511,8 +1514,12 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
       rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain);
       mpi_free (plain);
       plain = NULL;
-      if (!rc)
-        rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+      rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+      *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+      dummy = sexp_null_cond (result, ct_is_zero (rc));
+      sexp_release (dummy);
+      rc = ct_ulong_select (rc_sexp, rc,
+			    ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
       break;
 
     case PUBKEY_ENC_OAEP:
@@ -1521,8 +1528,12 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
                                   plain, ctx.label, ctx.labellen);
       mpi_free (plain);
       plain = NULL;
-      if (!rc)
-        rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+      rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+      *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+      dummy = sexp_null_cond (result, ct_is_zero (rc));
+      sexp_release (dummy);
+      rc = ct_ulong_select (rc_sexp, rc,
+			    ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
       break;
 
     default:
Index: libgcrypt-1.9.4/src/Makefile.am
===================================================================
--- libgcrypt-1.9.4.orig/src/Makefile.am
+++ libgcrypt-1.9.4/src/Makefile.am
@@ -64,6 +64,7 @@ libgcrypt_la_SOURCES = \
 	stdmem.c stdmem.h secmem.c secmem.h \
 	mpi.h missing-string.c fips.c \
 	hmac256.c hmac256.h context.c context.h \
+	const-time.h const-time.c \
 	ec-context.h
 
 EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c hwf-ppc.c hwf-s390x.c
Index: libgcrypt-1.9.4/src/const-time.c
===================================================================
--- /dev/null
+++ libgcrypt-1.9.4/src/const-time.c
@@ -0,0 +1,78 @@
+/* const-time.c  -  Constant-time functions
+ *      Copyright (C) 2023  g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "g10lib.h"
+#include "const-time.h"
+
+/*
+ * Compare byte arrays of length LEN, return 1 if it's not same,
+ * 0, otherwise.
+ */
+unsigned int
+_gcry_ct_not_memequal (const void *b1, const void *b2, size_t len)
+{
+  const byte *a = b1;
+  const byte *b = b2;
+  int ab, ba;
+  size_t i;
+
+  /* Constant-time compare. */
+  for (i = 0, ab = 0, ba = 0; i < len; i++)
+    {
+      /* If a[i] != b[i], either ab or ba will be negative. */
+      ab |= a[i] - b[i];
+      ba |= b[i] - a[i];
+    }
+
+  /* 'ab | ba' is negative when buffers are not equal, extract sign bit.  */
+  return ((unsigned int)(ab | ba) >> (sizeof(unsigned int) * 8 - 1)) & 1;
+}
+
+/*
+ * Compare byte arrays of length LEN, return 0 if it's not same,
+ * 1, otherwise.
+ */
+unsigned int
+_gcry_ct_memequal (const void *b1, const void *b2, size_t len)
+{
+  return _gcry_ct_not_memequal (b1, b2, len) ^ 1;
+}
+
+/*
+ * Copy LEN bytes from memory area SRC to memory area DST, when
+ * OP_ENABLED=1.  When DST <= SRC, the memory areas may overlap.  When
+ * DST > SRC, the memory areas must not overlap.
+ */
+void
+_gcry_ct_memmov_cond (void *dst, const void *src, size_t len,
+		      unsigned long op_enable)
+{
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  unsigned char mask1 = ct_ulong_gen_mask(op_enable);
+  unsigned char mask2 = ct_ulong_gen_inv_mask(op_enable);
+  unsigned char *b_dst = dst;
+  const unsigned char *b_src = src;
+  size_t i;
+
+  for (i = 0; i < len; i++)
+    b_dst[i] = (b_dst[i] & mask2) | (b_src[i] & mask1);
+}
Index: libgcrypt-1.9.4/src/const-time.h
===================================================================
--- /dev/null
+++ libgcrypt-1.9.4/src/const-time.h
@@ -0,0 +1,167 @@
+/* const-time.h  -  Constant-time functions
+ *      Copyright (C) 2023  g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GCRY_CONST_TIME_H
+#define GCRY_CONST_TIME_H
+
+#include "types.h"
+
+
+#define ct_not_memequal _gcry_ct_not_memequal
+#define ct_memequal _gcry_ct_memequal
+#define ct_memmov_cond _gcry_ct_memmov_cond
+
+
+#ifndef HAVE_GCC_ASM_VOLATILE_MEMORY
+extern volatile unsigned int _gcry_ct_vzero;
+extern volatile unsigned int _gcry_ct_vone;
+#endif
+
+
+/*
+ * Return 0 if A is 0 and return 1 otherwise.
+ */
+static inline unsigned int
+ct_is_not_zero (unsigned int a)
+{
+  /* Sign bit set if A != 0. */
+  a = a | (-a);
+
+  return a >> (sizeof(unsigned int) * 8 - 1);
+}
+
+/*
+ * Return 1 if A is 0 and return 0 otherwise.
+ */
+static inline unsigned int
+ct_is_zero (unsigned int a)
+{
+  /* Sign bit set if A == 0. */
+  a = ~a & ~(-a);
+
+  return a >> (sizeof(unsigned int) * 8 - 1);
+}
+
+/*
+ * Return 1 if it's not same, 0 if same.
+ */
+static inline unsigned int
+ct_not_equal_byte (unsigned char b0, unsigned char b1)
+{
+  unsigned int diff;
+
+  diff = b0;
+  diff ^= b1;
+
+  return (0U - diff) >> (sizeof (unsigned int)*8 - 1);
+}
+
+/* Compare byte-arrays of length LEN, return 1 if it's not same, 0
+   otherwise.  We use pointer of void *, so that it can be used with
+   any structure.  */
+unsigned int _gcry_ct_not_memequal (const void *b1, const void *b2, size_t len);
+
+/* Compare byte-arrays of length LEN, return 0 if it's not same, 1
+   otherwise.  We use pointer of void *, so that it can be used with
+   any structure.  */
+unsigned int _gcry_ct_memequal (const void *b1, const void *b2, size_t len);
+
+/*
+ * Return all bits set if A is 1 and return 0 otherwise.
+ */
+#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
+#  define DEFINE_CT_TYPE_GEN_MASK(name, type) \
+     static inline type \
+     ct_##name##_gen_mask (unsigned long op_enable) \
+     { \
+       type mask = -(type)op_enable; \
+       asm volatile ("\n" : "+r" (mask) :: "memory"); \
+       return mask; \
+     }
+#else
+#  define DEFINE_CT_TYPE_GEN_MASK(name, type) \
+     static inline type \
+     ct_##name##_gen_mask (unsigned long op_enable) \
+     { \
+       type mask = (type)_gcry_ct_vzero - (type)op_enable; \
+       return mask; \
+     }
+#endif
+DEFINE_CT_TYPE_GEN_MASK(uintptr, uintptr_t)
+DEFINE_CT_TYPE_GEN_MASK(ulong, unsigned long)
+
+/*
+ * Return all bits set if A is 0 and return 1 otherwise.
+ */
+#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
+#  define DEFINE_CT_TYPE_GEN_INV_MASK(name, type) \
+     static inline type \
+     ct_##name##_gen_inv_mask (unsigned long op_enable) \
+     { \
+       type mask = (type)op_enable - (type)1; \
+       asm volatile ("\n" : "+r" (mask) :: "memory"); \
+       return mask; \
+     }
+#else
+#  define DEFINE_CT_TYPE_GEN_INV_MASK(name, type) \
+     static inline type \
+     ct_##name##_gen_inv_mask (unsigned long op_enable) \
+     { \
+       type mask = (type)op_enable - (type)_gcry_ct_vone; \
+       return mask; \
+     }
+#endif
+DEFINE_CT_TYPE_GEN_INV_MASK(uintptr, uintptr_t)
+DEFINE_CT_TYPE_GEN_INV_MASK(ulong, unsigned long)
+
+/*
+ *  Return A when OP_ENABLED=1
+ *  otherwise, return B
+ */
+#define DEFINE_CT_TYPE_SELECT_FUNC(name, type) \
+  static inline type \
+  ct_##name##_select (type a, type b, unsigned long op_enable) \
+  { \
+    type mask_b = ct_##name##_gen_inv_mask(op_enable); \
+    type mask_a = ct_##name##_gen_mask(op_enable); \
+    return (mask_a & a) | (mask_b & b); \
+  }
+DEFINE_CT_TYPE_SELECT_FUNC(uintptr, uintptr_t)
+DEFINE_CT_TYPE_SELECT_FUNC(ulong, unsigned long)
+
+/*
+ *  Return NULL when OP_ENABLED=1
+ *  otherwise, return W
+ */
+static inline gcry_sexp_t
+sexp_null_cond (gcry_sexp_t w, unsigned long op_enable)
+{
+  uintptr_t o = ct_uintptr_select((uintptr_t)NULL, (uintptr_t)w, op_enable);
+  return (gcry_sexp_t)(void *)o;
+}
+
+/*
+ * Copy LEN bytes from memory area SRC to memory area DST, when
+ * OP_ENABLED=1.  When DST <= SRC, the memory areas may overlap.  When
+ * DST > SRC, the memory areas must not overlap.
+ */
+void _gcry_ct_memmov_cond (void *dst, const void *src, size_t len,
+			   unsigned long op_enable);
+
+#endif /*GCRY_CONST_TIME_H*/
Index: libgcrypt-1.9.4/cipher/elgamal.c
===================================================================
--- libgcrypt-1.9.4.orig/cipher/elgamal.c
+++ libgcrypt-1.9.4/cipher/elgamal.c
@@ -31,6 +31,7 @@
 #include "mpi.h"
 #include "cipher.h"
 #include "pubkey-internal.h"
+#include "const-time.h"
 
 
 /* Blinding is used to mitigate side-channel attacks.  You may undef
@@ -872,7 +873,7 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_s
 static gcry_err_code_t
 elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-  gpg_err_code_t rc;
+  gpg_err_code_t rc, rc_sexp;
   struct pk_encoding_ctx ctx;
   gcry_sexp_t l1 = NULL;
   gcry_mpi_t data_a = NULL;
@@ -881,6 +882,8 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_
   gcry_mpi_t plain = NULL;
   unsigned char *unpad = NULL;
   size_t unpadlen = 0;
+  gcry_sexp_t result = NULL;
+  gcry_sexp_t dummy = NULL;
 
   _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
                                    elg_get_nbits (keyparms));
@@ -928,18 +931,28 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_
     {
     case PUBKEY_ENC_PKCS1:
       rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
-      mpi_free (plain); plain = NULL;
-      if (!rc)
-        rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+      mpi_free (plain);
+      plain = NULL;
+      rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+      *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+      dummy = sexp_null_cond (result, ct_is_zero (rc));
+      sexp_release (dummy);
+      rc = ct_ulong_select (rc_sexp, rc,
+			    ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
       break;
 
     case PUBKEY_ENC_OAEP:
       rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
                                   ctx.nbits, ctx.hash_algo, plain,
                                   ctx.label, ctx.labellen);
-      mpi_free (plain); plain = NULL;
-      if (!rc)
-        rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+      mpi_free (plain);
+      plain = NULL;
+      rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+      *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+      dummy = sexp_null_cond (result, ct_is_zero (rc));
+      sexp_release (dummy);
+      rc = ct_ulong_select (rc_sexp, rc,
+			    ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
       break;
 
     default:
Index: libgcrypt-1.9.4/cipher/bufhelp.h
===================================================================
--- libgcrypt-1.9.4.orig/cipher/bufhelp.h
+++ libgcrypt-1.9.4/cipher/bufhelp.h
@@ -22,6 +22,7 @@
 
 #include "g10lib.h"
 #include "bithelp.h"
+#include "const-time.h"
 
 
 #undef BUFHELP_UNALIGNED_ACCESS
@@ -362,23 +363,9 @@ buf_xor_n_copy(void *_dst_xor, void *_sr
 /* Constant-time compare of two buffers.  Returns 1 if buffers are equal,
    and 0 if buffers differ.  */
 static inline int
-buf_eq_const(const void *_a, const void *_b, size_t len)
+buf_eq_const(const void *a, const void *b, size_t len)
 {
-  const byte *a = _a;
-  const byte *b = _b;
-  int ab, ba;
-  size_t i;
-
-  /* Constant-time compare. */
-  for (i = 0, ab = 0, ba = 0; i < len; i++)
-    {
-      /* If a[i] != b[i], either ab or ba will be negative. */
-      ab |= a[i] - b[i];
-      ba |= b[i] - a[i];
-    }
-
-  /* 'ab | ba' is negative when buffers are not equal. */
-  return (ab | ba) >= 0;
+  return ct_memequal (a, b, len);
 }
 
 
Index: libgcrypt-1.9.4/mpi/mpiutil.c
===================================================================
--- libgcrypt-1.9.4.orig/mpi/mpiutil.c
+++ libgcrypt-1.9.4/mpi/mpiutil.c
@@ -27,6 +27,7 @@
 #include "g10lib.h"
 #include "mpi-internal.h"
 #include "mod-source-info.h"
+#include "const-time.h"
 
 
 #if SIZEOF_UNSIGNED_INT == 2
@@ -46,12 +47,6 @@
 /* Constants allocated right away at startup.  */
 static gcry_mpi_t constants[MPI_NUMBER_OF_CONSTANTS];
 
-/* These variables are used to generate masks from conditional operation
- * flag parameters.  Use of volatile prevents compiler optimizations from
- * converting AND-masking to conditional branches.  */
-static volatile mpi_limb_t vzero = 0;
-static volatile mpi_limb_t vone = 1;
-
 
 const char *
 _gcry_mpi_get_hw_config (void)
@@ -517,10 +512,11 @@ _gcry_mpi_set (gcry_mpi_t w, gcry_mpi_t
 gcry_mpi_t
 _gcry_mpi_set_cond (gcry_mpi_t w, const gcry_mpi_t u, unsigned long set)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(set);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(set);
   mpi_size_t i;
   mpi_size_t nlimbs = u->alloced;
-  mpi_limb_t mask1 = vzero - set;
-  mpi_limb_t mask2 = set - vone;
   mpi_limb_t xu;
   mpi_limb_t xw;
   mpi_limb_t *uu = u->d;
@@ -618,10 +614,11 @@ _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t
 void
 _gcry_mpi_swap_cond (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap)
 {
+  /* Note: dual mask with AND/OR used for EM leakage mitigation */
+  mpi_limb_t mask1 = ct_limb_gen_mask(swap);
+  mpi_limb_t mask2 = ct_limb_gen_inv_mask(swap);
   mpi_size_t i;
   mpi_size_t nlimbs;
-  mpi_limb_t mask1 = vzero - swap;
-  mpi_limb_t mask2 = swap - vone;
   mpi_limb_t *ua = a->d;
   mpi_limb_t *ub = b->d;
   mpi_limb_t xa;
Index: libgcrypt-1.9.4/mpi/mpi-internal.h
===================================================================
--- libgcrypt-1.9.4.orig/mpi/mpi-internal.h
+++ libgcrypt-1.9.4/mpi/mpi-internal.h
@@ -50,6 +50,7 @@
 #endif /*BITS_PER_MPI_LIMB*/
 
 #include "mpi.h"
+#include "const-time.h"
 
 /* If KARATSUBA_THRESHOLD is not already defined, define it to a
  * value which is good on most machines.  */
@@ -262,6 +263,18 @@ mpi_limb_t _gcry_mpih_rshift( mpi_ptr_t
 #define mpih_abs_cond(w,u,s,o) _gcry_mpih_abs_cond ((w),(u),(s),(o))
 #define mpih_mod(v,vs,u,us) _gcry_mpih_mod ((v),(vs),(u),(us))
 
+DEFINE_CT_TYPE_GEN_MASK(limb, mpi_limb_t)
+DEFINE_CT_TYPE_GEN_INV_MASK(limb, mpi_limb_t)
+
+static inline int
+mpih_limb_is_zero (mpi_limb_t a)
+{
+  /* Sign bit set if A == 0. */
+  a = ~a & ~(-a);
+
+  return a >> (BITS_PER_MPI_LIMB - 1);
+}
+
 void _gcry_mpih_set_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
                           unsigned long op_enable);
 mpi_limb_t _gcry_mpih_add_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
openSUSE Build Service is sponsored by