summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/mpi/mpicoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgcrypt-1.8.7/mpi/mpicoder.c')
-rw-r--r--libotr/libgcrypt-1.8.7/mpi/mpicoder.c958
1 files changed, 958 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/mpi/mpicoder.c b/libotr/libgcrypt-1.8.7/mpi/mpicoder.c
new file mode 100644
index 0000000..a133421
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/mpi/mpicoder.c
@@ -0,0 +1,958 @@
+/* mpicoder.c  -  Coder for the external representation of MPIs
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ *               2008 Free Software Foundation, Inc.
+ * Copyright (C) 2013, 2014 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+#include "g10lib.h"
+
+/* The maximum length we support in the functions converting an
+ * external representation to an MPI.  This limit is used to catch
+ * programming errors and to avoid DoS due to insane long allocations.
+ * The 16 MiB limit is actually ridiculous large but some of those PQC
+ * algorithms use quite large keys and they might end up using MPIs
+ * for that.  */
+#define MAX_EXTERN_SCAN_BYTES (16*1024*1024)
+
+/* The maximum length (in bits) we support for OpenPGP MPIs.  Note
+ * that OpenPGP's MPI format uses only two bytes and thus would be
+ * limited to 64k anyway.  Note that this limit matches that used by
+ * GnuPG.  */
+#define MAX_EXTERN_MPI_BITS 16384
+
+
+/* Helper used to scan PGP style MPIs.  Returns NULL on failure. */
+static gcry_mpi_t
+mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread,
+                      int secure)
+{
+  int i, j;
+  unsigned int nbits, nbytes, nlimbs, nread=0;
+  mpi_limb_t a;
+  gcry_mpi_t val = MPI_NULL;
+
+  if ( *ret_nread < 2 )
+    goto leave;
+  nbits = buffer[0] << 8 | buffer[1];
+  if ( nbits > MAX_EXTERN_MPI_BITS )
+    {
+/*       log_debug ("mpi too large (%u bits)\n", nbits); */
+      goto leave;
+    }
+  buffer += 2;
+  nread = 2;
+
+  nbytes = (nbits+7) / 8;
+  nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+  val = secure? mpi_alloc_secure (nlimbs) : mpi_alloc (nlimbs);
+  i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+  i %= BYTES_PER_MPI_LIMB;
+  j= val->nlimbs = nlimbs;
+  val->sign = 0;
+  for ( ; j > 0; j-- )
+    {
+      a = 0;
+      for (; i < BYTES_PER_MPI_LIMB; i++ )
+        {
+          if ( ++nread > *ret_nread )
+            {
+/*               log_debug ("mpi larger than buffer"); */
+              mpi_free (val);
+              val = NULL;
+              goto leave;
+            }
+          a <<= 8;
+          a |= *buffer++;
+	}
+      i = 0;
+      val->d[j-1] = a;
+    }
+
+ leave:
+  *ret_nread = nread;
+  return val;
+}
+
+
+/****************
+ * Fill the mpi VAL from the hex string in STR.
+ */
+static int
+mpi_fromstr (gcry_mpi_t val, const char *str)
+{
+  int sign = 0;
+  int prepend_zero = 0;
+  int i, j, c, c1, c2;
+  unsigned int nbits, nbytes, nlimbs;
+  mpi_limb_t a;
+
+  if ( *str == '-' )
+    {
+      sign = 1;
+      str++;
+    }
+
+  /* Skip optional hex prefix.  */
+  if ( *str == '0' && str[1] == 'x' )
+    str += 2;
+
+  nbits = strlen (str);
+  if (nbits > MAX_EXTERN_SCAN_BYTES)
+    {
+      mpi_clear (val);
+      return 1;  /* Error.  */
+    }
+  nbits *= 4;
+  if ((nbits % 8))
+    prepend_zero = 1;
+
+  nbytes = (nbits+7) / 8;
+  nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+
+  if ( val->alloced < nlimbs )
+    mpi_resize (val, nlimbs);
+
+  i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB);
+  i %= BYTES_PER_MPI_LIMB;
+  j = val->nlimbs = nlimbs;
+  val->sign = sign;
+  for (; j > 0; j--)
+    {
+      a = 0;
+      for (; i < BYTES_PER_MPI_LIMB; i++)
+        {
+          if (prepend_zero)
+            {
+              c1 = '0';
+              prepend_zero = 0;
+	    }
+          else
+            c1 = *str++;
+
+          if (!c1)
+            {
+              mpi_clear (val);
+              return 1;  /* Error.  */
+	    }
+          c2 = *str++;
+          if (!c2)
+            {
+              mpi_clear (val);
+              return 1;  /* Error.  */
+	    }
+          if ( c1 >= '0' && c1 <= '9' )
+            c = c1 - '0';
+          else if ( c1 >= 'a' && c1 <= 'f' )
+            c = c1 - 'a' + 10;
+          else if ( c1 >= 'A' && c1 <= 'F' )
+            c = c1 - 'A' + 10;
+          else
+            {
+              mpi_clear (val);
+              return 1;  /* Error.  */
+	    }
+          c <<= 4;
+          if ( c2 >= '0' && c2 <= '9' )
+            c |= c2 - '0';
+          else if( c2 >= 'a' && c2 <= 'f' )
+            c |= c2 - 'a' + 10;
+          else if( c2 >= 'A' && c2 <= 'F' )
+            c |= c2 - 'A' + 10;
+          else
+            {
+              mpi_clear(val);
+              return 1;  /* Error. */
+	    }
+          a <<= 8;
+          a |= c;
+	}
+      i = 0;
+      val->d[j-1] = a;
+    }
+
+  return 0;  /* Okay.  */
+}
+
+
+/* Return an allocated buffer with the MPI (msb first).  NBYTES
+   receives the length of this buffer.  If FILL_LE is not 0, the
+   returned value is stored as little endian and right padded with
+   zeroes so that the returned buffer has at least FILL_LE bytes.
+
+   If EXTRAALLOC > 0 the returned buffer has these number of bytes
+   extra allocated at the end; if EXTRAALLOC < 0 the returned buffer
+   has the absolute value of EXTRAALLOC allocated at the begin of the
+   buffer (the are not initialized) and the MPI is stored right after
+   this.  This feature is useful to allow the caller to prefix the
+   returned value.  EXTRAALLOC is _not_ included in the value stored
+   at NBYTES.
+
+   Caller must free the return string.  This function returns an
+   allocated buffer with NBYTES set to zero if the value of A is zero.
+   If sign is not NULL, it will be set to the sign of the A.  On error
+   NULL is returned and ERRNO set appropriately.  */
+static unsigned char *
+do_get_buffer (gcry_mpi_t a, unsigned int fill_le, int extraalloc,
+               unsigned int *nbytes, int *sign, int force_secure)
+{
+  unsigned char *p, *buffer, *retbuffer;
+  unsigned int length, tmp;
+  mpi_limb_t alimb;
+  int i;
+  size_t n, n2;
+
+  if (sign)
+    *sign = a->sign;
+
+  *nbytes = a->nlimbs * BYTES_PER_MPI_LIMB;
+  n = *nbytes? *nbytes:1; /* Allocate at least one byte.  */
+  if (n < fill_le)
+    n = fill_le;
+  if (extraalloc < 0)
+    n2 = n + -extraalloc;
+  else
+    n2 = n + extraalloc;
+
+  retbuffer = (force_secure || mpi_is_secure(a))? xtrymalloc_secure (n2)
+                                                : xtrymalloc (n2);
+  if (!retbuffer)
+    return NULL;
+  if (extraalloc < 0)
+    buffer = retbuffer + -extraalloc;
+  else
+    buffer = retbuffer;
+  p = buffer;
+
+  for (i=a->nlimbs-1; i >= 0; i--)
+    {
+      alimb = a->d[i];
+#if BYTES_PER_MPI_LIMB == 4
+      *p++ = alimb >> 24;
+      *p++ = alimb >> 16;
+      *p++ = alimb >>  8;
+      *p++ = alimb	  ;
+#elif BYTES_PER_MPI_LIMB == 8
+      *p++ = alimb >> 56;
+      *p++ = alimb >> 48;
+      *p++ = alimb >> 40;
+      *p++ = alimb >> 32;
+      *p++ = alimb >> 24;
+      *p++ = alimb >> 16;
+      *p++ = alimb >>  8;
+      *p++ = alimb	  ;
+#else
+#     error please implement for this limb size.
+#endif
+    }
+
+  if (fill_le)
+    {
+      length = *nbytes;
+      /* Reverse buffer and pad with zeroes.  */
+      for (i=0; i < length/2; i++)
+        {
+          tmp = buffer[i];
+          buffer[i] = buffer[length-1-i];
+          buffer[length-1-i] = tmp;
+        }
+      /* Pad with zeroes.  */
+      for (p = buffer + length; length < fill_le; length++)
+        *p++ = 0;
+      *nbytes = length;
+
+      return retbuffer;
+    }
+
+  /* This is sub-optimal but we need to do the shift operation because
+     the caller has to free the returned buffer.  */
+  for (p=buffer; *nbytes && !*p; p++, --*nbytes)
+    ;
+  if (p != buffer)
+    memmove (buffer, p, *nbytes);
+  return retbuffer;
+}
+
+
+byte *
+_gcry_mpi_get_buffer (gcry_mpi_t a, unsigned int fill_le,
+                      unsigned int *r_nbytes, int *sign)
+{
+  if (mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    {
+      unsigned int nbits;
+      byte *p = _gcry_mpi_get_opaque_copy (a, &nbits);
+
+      if (r_nbytes)
+        *r_nbytes = (nbits+7)/8;
+
+      return p;
+    }
+  else
+    return do_get_buffer (a, fill_le, 0, r_nbytes, sign, 0);
+}
+
+byte *
+_gcry_mpi_get_buffer_extra (gcry_mpi_t a, unsigned int fill_le, int extraalloc,
+                            unsigned int *r_nbytes, int *sign)
+{
+  return do_get_buffer (a, fill_le, extraalloc, r_nbytes, sign, 0);
+}
+
+byte *
+_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned int fill_le,
+                             unsigned int *r_nbytes, int *sign)
+{
+  return do_get_buffer (a, fill_le, 0, r_nbytes, sign, 1);
+}
+
+
+/*
+ * Use the NBYTES at BUFFER_ARG to update A.  Set the sign of a to
+ * SIGN.
+ */
+void
+_gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
+                      unsigned int nbytes, int sign)
+{
+  const unsigned char *buffer = (const unsigned char*)buffer_arg;
+  const unsigned char *p;
+  mpi_limb_t alimb;
+  int nlimbs;
+  int i;
+
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
+  nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+  RESIZE_IF_NEEDED(a, nlimbs);
+  a->sign = sign;
+
+  for (i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; )
+    {
+#if BYTES_PER_MPI_LIMB == 4
+      alimb  = *p--	    ;
+      alimb |= *p-- <<  8 ;
+      alimb |= *p-- << 16 ;
+      alimb |= *p-- << 24 ;
+#elif BYTES_PER_MPI_LIMB == 8
+      alimb  = (mpi_limb_t)*p--	;
+      alimb |= (mpi_limb_t)*p-- <<  8 ;
+      alimb |= (mpi_limb_t)*p-- << 16 ;
+      alimb |= (mpi_limb_t)*p-- << 24 ;
+      alimb |= (mpi_limb_t)*p-- << 32 ;
+      alimb |= (mpi_limb_t)*p-- << 40 ;
+      alimb |= (mpi_limb_t)*p-- << 48 ;
+      alimb |= (mpi_limb_t)*p-- << 56 ;
+#else
+#       error please implement for this limb size.
+#endif
+      a->d[i++] = alimb;
+    }
+  if ( p >= buffer )
+    {
+#if BYTES_PER_MPI_LIMB == 4
+      alimb  = *p--;
+      if (p >= buffer)
+        alimb |= *p-- <<  8;
+      if (p >= buffer)
+        alimb |= *p-- << 16;
+      if (p >= buffer)
+        alimb |= *p-- << 24;
+#elif BYTES_PER_MPI_LIMB == 8
+      alimb  = (mpi_limb_t)*p--;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 8;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 16;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 24;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 32;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 40;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 48;
+      if (p >= buffer)
+        alimb |= (mpi_limb_t)*p-- << 56;
+#else
+#     error please implement for this limb size.
+#endif
+      a->d[i++] = alimb;
+    }
+  a->nlimbs = i;
+  gcry_assert (i == nlimbs);
+}
+
+
+static void
+onecompl (gcry_mpi_t a)
+{
+  mpi_ptr_t ap;
+  mpi_size_t n;
+  unsigned int i;
+  unsigned int nbits;
+
+  if (!a || mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
+  nbits = mpi_get_nbits (a);
+
+  mpi_normalize (a);
+  ap = a->d;
+  n = a->nlimbs;
+
+  for( i = 0; i < n; i++ )
+    ap[i] ^= (mpi_limb_t)(-1);
+
+  a->sign = 0;
+  mpi_clear_highbit (a, nbits-1);
+}
+
+
+/* Perform a two's complement operation on buffer P of size N bytes.  */
+static void
+twocompl (unsigned char *p, unsigned int n)
+{
+  int i;
+
+  for (i=n-1; i >= 0 && !p[i]; i--)
+    ;
+  if (i >= 0)
+    {
+      if ((p[i] & 0x01))
+        p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff);
+      else if ((p[i] & 0x02))
+        p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe);
+      else if ((p[i] & 0x04))
+        p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc);
+      else if ((p[i] & 0x08))
+        p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8);
+      else if ((p[i] & 0x10))
+        p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0);
+      else if ((p[i] & 0x20))
+        p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0);
+      else if ((p[i] & 0x40))
+        p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0);
+      else
+        p[i] = 0x80;
+
+      for (i--; i >= 0; i--)
+        p[i] ^= 0xff;
+    }
+}
+
+
+/* Convert the external representation of an integer stored in BUFFER
+ * with a length of BUFLEN into a newly create MPI returned in
+ * RET_MPI.  If NSCANNED is not NULL, it will receive the number of
+ * bytes actually scanned after a successful operation.  */
+gcry_err_code_t
+_gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
+                const void *buffer_arg, size_t buflen, size_t *nscanned)
+{
+  const unsigned char *buffer = (const unsigned char*)buffer_arg;
+  struct gcry_mpi *a = NULL;
+  unsigned int len;
+  int secure = (buffer && _gcry_is_secure (buffer));
+
+  if (buflen > MAX_EXTERN_SCAN_BYTES)
+    {
+      if (nscanned)
+        *nscanned = 0;
+      return GPG_ERR_INV_OBJ;
+    }
+
+  if (format == GCRYMPI_FMT_SSH)
+    len = 0;
+  else
+    len = buflen;
+
+  if (format == GCRYMPI_FMT_STD)
+    {
+      const unsigned char *s = buffer;
+
+      a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
+                                    /BYTES_PER_MPI_LIMB)
+                : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+      if (len)
+        {
+          _gcry_mpi_set_buffer (a, s, len, 0);
+          a->sign = !!(*s & 0x80);
+          if (a->sign)
+            {
+              onecompl (a);
+              mpi_add_ui (a, a, 1);
+              a->sign = 1;
+	    }
+	}
+      if (ret_mpi)
+        {
+          mpi_normalize ( a );
+          *ret_mpi = a;
+	}
+      else
+        mpi_free(a);
+      if (nscanned)
+        *nscanned = len;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_USG)
+    {
+      a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
+                                    /BYTES_PER_MPI_LIMB)
+                : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+
+      if (len)
+        _gcry_mpi_set_buffer (a, buffer, len, 0);
+      if (ret_mpi)
+        {
+          mpi_normalize ( a );
+          *ret_mpi = a;
+	}
+      else
+        mpi_free(a);
+      if (nscanned)
+        *nscanned = len;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_PGP)
+    {
+      a = mpi_read_from_buffer (buffer, &len, secure);
+      if (nscanned)
+        *nscanned = len;
+      if (ret_mpi && a)
+        {
+          mpi_normalize (a);
+          *ret_mpi = a;
+	}
+      else if (a)
+        {
+          mpi_free(a);
+          a = NULL;
+        }
+      return a? 0 : GPG_ERR_INV_OBJ;
+    }
+  else if (format == GCRYMPI_FMT_SSH)
+    {
+      const unsigned char *s = buffer;
+      size_t n;
+
+      /* This test is not strictly necessary and an assert (!len)
+         would be sufficient.  We keep this test in case we later
+         allow the BUFLEN argument to act as a sanitiy check.  Same
+         below. */
+      if (len && len < 4)
+        return GPG_ERR_TOO_SHORT;
+
+      n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
+      s += 4;
+      if (len)
+        len -= 4;
+      if (len && n > len)
+        return GPG_ERR_TOO_LARGE;
+
+      a = secure? mpi_alloc_secure ((n+BYTES_PER_MPI_LIMB-1)
+                                    /BYTES_PER_MPI_LIMB)
+                : mpi_alloc ((n+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+      if (n)
+        {
+          _gcry_mpi_set_buffer( a, s, n, 0 );
+          a->sign = !!(*s & 0x80);
+          if (a->sign)
+            {
+              onecompl (a);
+              mpi_add_ui (a, a, 1);
+              a->sign = 1;
+	    }
+	}
+      if (nscanned)
+        *nscanned = n+4;
+      if (ret_mpi)
+        {
+          mpi_normalize ( a );
+          *ret_mpi = a;
+        }
+      else
+        mpi_free(a);
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_HEX)
+    {
+      /* We can only handle C strings for now.  */
+      if (buflen)
+        return GPG_ERR_INV_ARG;
+
+      a = secure? mpi_alloc_secure (0) : mpi_alloc(0);
+      if (mpi_fromstr (a, (const char *)buffer))
+        {
+          mpi_free (a);
+          return GPG_ERR_INV_OBJ;
+        }
+      if (ret_mpi)
+        {
+          mpi_normalize ( a );
+          *ret_mpi = a;
+	}
+      else
+        mpi_free(a);
+      if (nscanned)
+        *nscanned = strlen ((const char*)buffer);
+      return 0;
+    }
+  else
+    return GPG_ERR_INV_ARG;
+}
+
+
+/* Convert the big integer A into the external representation
+   described by FORMAT and store it in the provided BUFFER which has
+   been allocated by the user with a size of BUFLEN bytes.  NWRITTEN
+   receives the actual length of the external representation unless it
+   has been passed as NULL.  BUFFER may be NULL to query the required
+   length.  */
+gcry_err_code_t
+_gcry_mpi_print (enum gcry_mpi_format format,
+                 unsigned char *buffer, size_t buflen,
+                 size_t *nwritten, struct gcry_mpi *a)
+{
+  unsigned int nbits = mpi_get_nbits (a);
+  size_t len;
+  size_t dummy_nwritten;
+  int negative;
+
+  if (!nwritten)
+    nwritten = &dummy_nwritten;
+
+  /* Libgcrypt does no always care to set clear the sign if the value
+     is 0.  For printing this is a bit of a surprise, in particular
+     because if some of the formats don't support negative numbers but
+     should be able to print a zero.  Thus we need this extra test
+     for a negative number.  */
+  if (a->sign && _gcry_mpi_cmp_ui (a, 0))
+    negative = 1;
+  else
+    negative = 0;
+
+  len = buflen;
+  *nwritten = 0;
+  if (format == GCRYMPI_FMT_STD)
+    {
+      unsigned char *tmp;
+      int extra = 0;
+      unsigned int n;
+
+      tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+      if (!tmp)
+        return gpg_err_code_from_syserror ();
+
+      if (negative)
+        {
+          twocompl (tmp, n);
+          if (!(*tmp & 0x80))
+            {
+              /* Need to extend the sign.  */
+              n++;
+              extra = 2;
+            }
+        }
+      else if (n && (*tmp & 0x80))
+        {
+          /* Positive but the high bit of the returned buffer is set.
+             Thus we need to print an extra leading 0x00 so that the
+             output is interpreted as a positive number.  */
+          n++;
+          extra = 1;
+	}
+
+      if (buffer && n > len)
+        {
+          /* The provided buffer is too short. */
+          xfree (tmp);
+          return GPG_ERR_TOO_SHORT;
+	}
+      if (buffer)
+        {
+          unsigned char *s = buffer;
+
+          if (extra == 1)
+            *s++ = 0;
+          else if (extra)
+            *s++ = 0xff;
+          memcpy (s, tmp, n-!!extra);
+	}
+      xfree (tmp);
+      *nwritten = n;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_USG)
+    {
+      unsigned int n = (nbits + 7)/8;
+
+      /* Note:  We ignore the sign for this format.  */
+      /* FIXME: for performance reasons we should put this into
+	 mpi_aprint because we can then use the buffer directly.  */
+
+      if (buffer && n > len)
+        return GPG_ERR_TOO_SHORT;
+      if (buffer)
+        {
+          unsigned char *tmp;
+
+          tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+          if (!tmp)
+            return gpg_err_code_from_syserror ();
+          memcpy (buffer, tmp, n);
+          xfree (tmp);
+	}
+      *nwritten = n;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_PGP)
+    {
+      unsigned int n = (nbits + 7)/8;
+
+      /* The PGP format can only handle unsigned integers.  */
+      if (negative)
+        return GPG_ERR_INV_ARG;
+
+      if (buffer && n+2 > len)
+        return GPG_ERR_TOO_SHORT;
+
+      if (buffer)
+        {
+          unsigned char *tmp;
+          unsigned char *s = buffer;
+
+          s[0] = nbits >> 8;
+          s[1] = nbits;
+
+          tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+          if (!tmp)
+            return gpg_err_code_from_syserror ();
+          memcpy (s+2, tmp, n);
+          xfree (tmp);
+	}
+      *nwritten = n+2;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_SSH)
+    {
+      unsigned char *tmp;
+      int extra = 0;
+      unsigned int n;
+
+      tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+      if (!tmp)
+        return gpg_err_code_from_syserror ();
+
+      if (negative)
+        {
+          twocompl (tmp, n);
+          if (!(*tmp & 0x80))
+            {
+              /* Need to extend the sign.  */
+              n++;
+              extra = 2;
+            }
+        }
+      else if (n && (*tmp & 0x80))
+        {
+          n++;
+          extra=1;
+	}
+
+      if (buffer && n+4 > len)
+        {
+          xfree(tmp);
+          return GPG_ERR_TOO_SHORT;
+	}
+
+      if (buffer)
+        {
+          unsigned char *s = buffer;
+
+          *s++ = n >> 24;
+          *s++ = n >> 16;
+          *s++ = n >> 8;
+          *s++ = n;
+          if (extra == 1)
+            *s++ = 0;
+          else if (extra)
+            *s++ = 0xff;
+          memcpy (s, tmp, n-!!extra);
+	}
+      xfree (tmp);
+      *nwritten = 4+n;
+      return 0;
+    }
+  else if (format == GCRYMPI_FMT_HEX)
+    {
+      unsigned char *tmp;
+      int i;
+      int extra = 0;
+      unsigned int n = 0;
+
+      tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+      if (!tmp)
+        return gpg_err_code_from_syserror ();
+      if (!n || (*tmp & 0x80))
+        extra = 2;
+
+      if (buffer && 2*n + extra + negative + 1 > len)
+        {
+          xfree(tmp);
+          return GPG_ERR_TOO_SHORT;
+	}
+      if (buffer)
+        {
+          unsigned char *s = buffer;
+
+          if (negative)
+            *s++ = '-';
+          if (extra)
+            {
+              *s++ = '0';
+              *s++ = '0';
+	    }
+
+          for (i=0; i < n; i++)
+            {
+              unsigned int c = tmp[i];
+
+              *s++ = (c >> 4) < 10? '0'+(c>>4) : 'A'+(c>>4)-10 ;
+              c &= 15;
+              *s++ = c < 10? '0'+c : 'A'+c-10 ;
+	    }
+          *s++ = 0;
+          *nwritten = s - buffer;
+	}
+      else
+        {
+          *nwritten = 2*n + extra + negative + 1;
+	}
+      xfree (tmp);
+      return 0;
+    }
+  else
+    return GPG_ERR_INV_ARG;
+}
+
+
+/*
+ * Like gcry_mpi_print but this function allocates the buffer itself.
+ * The caller has to supply the address of a pointer.  NWRITTEN may be
+ * NULL.
+ */
+gcry_err_code_t
+_gcry_mpi_aprint (enum gcry_mpi_format format,
+                  unsigned char **buffer, size_t *nwritten,
+                  struct gcry_mpi *a)
+{
+  size_t n;
+  gcry_err_code_t rc;
+
+  *buffer = NULL;
+  rc = _gcry_mpi_print (format, NULL, 0, &n, a);
+  if (rc)
+    return rc;
+
+  *buffer = mpi_is_secure(a) ? xtrymalloc_secure (n?n:1) : xtrymalloc (n?n:1);
+  if (!*buffer)
+    return gpg_err_code_from_syserror ();
+  /* If the returned buffer will have a length of 0, we nevertheless
+     allocated 1 byte (malloc needs it anyway) and store a 0.  */
+  if (!n)
+    **buffer = 0;
+  rc = _gcry_mpi_print( format, *buffer, n, &n, a );
+  if (rc)
+    {
+      xfree (*buffer);
+      *buffer = NULL;
+    }
+  else if (nwritten)
+    *nwritten = n;
+  return rc;
+}
+
+
+/* Turn VALUE into an octet string and store it in an allocated buffer
+   at R_FRAME or - if R_RAME is NULL - copy it into the caller
+   provided buffer SPACE; either SPACE or R_FRAME may be used.  If
+   SPACE if not NULL, the caller must provide a buffer of at least
+   NBYTES.  If the resulting octet string is shorter than NBYTES pad
+   it to the left with zeroes.  If VALUE does not fit into NBYTES
+   return an error code.  */
+gpg_err_code_t
+_gcry_mpi_to_octet_string (unsigned char **r_frame, void *space,
+                           gcry_mpi_t value, size_t nbytes)
+{
+  gpg_err_code_t rc;
+  size_t nframe, noff, n;
+  unsigned char *frame;
+
+  if (!r_frame == !space)
+    return GPG_ERR_INV_ARG;  /* Only one may be used.  */
+
+  if (r_frame)
+    *r_frame = NULL;
+
+  rc = _gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nframe, value);
+  if (rc)
+    return rc;
+  if (nframe > nbytes)
+    return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES.  */
+
+  noff = (nframe < nbytes)? nbytes - nframe : 0;
+  n = nframe + noff;
+  if (space)
+    frame = space;
+  else
+    {
+      frame = mpi_is_secure (value)? xtrymalloc_secure (n) : xtrymalloc (n);
+      if (!frame)
+        {
+          rc = gpg_err_code_from_syserror ();
+          return rc;
+        }
+    }
+  if (noff)
+    memset (frame, 0, noff);
+  nframe += noff;
+  rc = _gcry_mpi_print (GCRYMPI_FMT_USG, frame+noff, nframe-noff, NULL, value);
+  if (rc)
+    {
+      xfree (frame);
+      return rc;
+    }
+
+  if (r_frame)
+    *r_frame = frame;
+  return 0;
+}