diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/mpi/mpicoder.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/mpi/mpicoder.c | 511 |
1 files changed, 339 insertions, 172 deletions
diff --git a/plugins/MirOTR/Libgcrypt/mpi/mpicoder.c b/plugins/MirOTR/Libgcrypt/mpi/mpicoder.c index 8f0c76f144..896dda14cc 100644 --- a/plugins/MirOTR/Libgcrypt/mpi/mpicoder.c +++ b/plugins/MirOTR/Libgcrypt/mpi/mpicoder.c @@ -1,6 +1,7 @@ /* 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. * @@ -37,7 +38,7 @@ mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread, 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]; @@ -46,11 +47,6 @@ mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread, /* log_debug ("mpi too large (%u bits)\n", nbits); */ goto leave; } - else if( !nbits ) - { -/* log_debug ("an mpi of size 0 is not allowed\n"); */ - goto leave; - } buffer += 2; nread = 2; @@ -64,7 +60,7 @@ mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread, for ( ; j > 0; j-- ) { a = 0; - for (; i < BYTES_PER_MPI_LIMB; i++ ) + for (; i < BYTES_PER_MPI_LIMB; i++ ) { if ( ++nread > *ret_nread ) { @@ -79,7 +75,7 @@ mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread, i = 0; val->d[j-1] = a; } - + leave: *ret_nread = nread; return val; @@ -164,7 +160,7 @@ mpi_fromstr (gcry_mpi_t val, const char *str) c |= c2 - 'a' + 10; else if( c2 >= 'A' && c2 <= 'F' ) c |= c2 - 'A' + 10; - else + else { mpi_clear(val); return 1; /* Error. */ @@ -175,81 +171,59 @@ mpi_fromstr (gcry_mpi_t val, const char *str) i = 0; val->d[j-1] = a; } - - return 0; /* Okay. */ -} - -/* Dump the value of A in a format suitable for debugging to - Libgcrypt's logging stream. Note that one leading space but no - trailing space or linefeed will be printed. It is okay to pass - NULL for A. */ -void -gcry_mpi_dump (const gcry_mpi_t a) -{ - int i; - - log_printf (" "); - if (!a) - log_printf ("[MPI_NULL]"); - else - { - if (a->sign) - log_printf ( "-"); -#if BYTES_PER_MPI_LIMB == 2 -# define X "4" -#elif BYTES_PER_MPI_LIMB == 4 -# define X "8" -#elif BYTES_PER_MPI_LIMB == 8 -# define X "16" -#elif BYTES_PER_MPI_LIMB == 16 -# define X "32" -#else -# error please define the format here -#endif - for (i=a->nlimbs; i > 0 ; i-- ) - { - log_printf (i != a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]); - } -#undef X - if (!a->nlimbs) - log_printf ("0"); - } -} - -/* Convience function used internally. */ -void -_gcry_log_mpidump (const char *text, gcry_mpi_t a) -{ - log_printf ("%s:", text); - gcry_mpi_dump (a); - log_printf ("\n"); + return 0; /* Okay. */ } /* Return an allocated buffer with the MPI (msb first). NBYTES - receives the length of this buffer. 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. */ + 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 *nbytes, int *sign, int force_secure) +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; + unsigned char *p, *buffer, *retbuffer; + unsigned int length, tmp; mpi_limb_t alimb; int i; - size_t n; - + 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. */ - p = buffer = (force_secure || mpi_is_secure(a))? gcry_malloc_secure (n) - : gcry_malloc (n); - if (!buffer) + 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--) { @@ -273,26 +247,53 @@ do_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign, int force_secure) #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; !*p && *nbytes; p++, --*nbytes) + for (p=buffer; *nbytes && !*p; p++, --*nbytes) ; if (p != buffer) - memmove (buffer,p, *nbytes); - return buffer; + memmove (buffer, p, *nbytes); + return retbuffer; } byte * -_gcry_mpi_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign) +_gcry_mpi_get_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, 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, nbytes, sign, 0); + return do_get_buffer (a, fill_le, extraalloc, r_nbytes, sign, 0); } byte * -_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned *nbytes, int *sign) +_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned int fill_le, + unsigned int *r_nbytes, int *sign) { - return do_get_buffer (a, nbytes, sign, 1); + return do_get_buffer (a, fill_le, 0, r_nbytes, sign, 1); } @@ -309,12 +310,18 @@ _gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg, 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; ) + + for (i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; ) { #if BYTES_PER_MPI_LIMB == 4 alimb = *p-- ; @@ -371,24 +378,83 @@ _gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg, } +static void +onecompl (gcry_mpi_t a) +{ + mpi_ptr_t ap; + mpi_size_t n; + unsigned int i; + unsigned int nbits = mpi_get_nbits (a); + + if (mpi_is_immutable (a)) + { + mpi_immutable_failed (); + return; + } + + 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 NBYTES is not NULL, it will receive the number of bytes actually scanned after a successful operation. */ -gcry_error_t -gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, - const void *buffer_arg, size_t buflen, size_t *nscanned) +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)); + int secure = (buffer && _gcry_is_secure (buffer)); if (format == GCRYMPI_FMT_SSH) len = 0; else len = buflen; - + if (format == GCRYMPI_FMT_STD) { const unsigned char *s = buffer; @@ -397,16 +463,15 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, /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) { - /* FIXME: we have to convert from 2compl to magnitude format */ - mpi_free (a); - return gcry_error (GPG_ERR_INTERNAL); + onecompl (a); + mpi_add_ui (a, a, 1); + a->sign = 1; } - else - _gcry_mpi_set_buffer (a, s, len, 0); } if (ret_mpi) { @@ -415,6 +480,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, } else mpi_free(a); + if (nscanned) + *nscanned = len; return 0; } else if (format == GCRYMPI_FMT_USG) @@ -432,6 +499,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, } else mpi_free(a); + if (nscanned) + *nscanned = len; return 0; } else if (format == GCRYMPI_FMT_PGP) @@ -449,37 +518,40 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, mpi_free(a); a = NULL; } - return a? 0 : gcry_error (GPG_ERR_INV_OBJ); + 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 gcry_error (GPG_ERR_TOO_SHORT); + return GPG_ERR_TOO_SHORT; n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); - s += 4; + s += 4; if (len) len -= 4; if (len && n > len) - return gcry_error (GPG_ERR_TOO_LARGE); + 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) { - /* FIXME: we have to convert from 2compl to magnitude format */ - mpi_free(a); - return gcry_error (GPG_ERR_INTERNAL); + onecompl (a); + mpi_add_ui (a, a, 1); + a->sign = 1; } - else - _gcry_mpi_set_buffer( a, s, n, 0 ); } if (nscanned) *nscanned = n+4; @@ -496,25 +568,27 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, { /* We can only handle C strings for now. */ if (buflen) - return gcry_error (GPG_ERR_INV_ARG); + 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 gcry_error (GPG_ERR_INV_OBJ); + return GPG_ERR_INV_OBJ; } - if (ret_mpi) + if (ret_mpi) { mpi_normalize ( a ); *ret_mpi = a; } else mpi_free(a); + if (nscanned) + *nscanned = strlen ((const char*)buffer); return 0; } else - return gcry_error (GPG_ERR_INV_ARG); + return GPG_ERR_INV_ARG; } @@ -524,53 +598,77 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, 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_error_t -gcry_mpi_print (enum gcry_mpi_format format, - unsigned char *buffer, size_t buflen, - size_t *nwritten, struct gcry_mpi *a) +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) + if (format == GCRYMPI_FMT_STD) { unsigned char *tmp; int extra = 0; unsigned int n; - - if (a->sign) - return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ - tmp = _gcry_mpi_get_buffer (a, &n, NULL); + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); if (!tmp) - return gpg_error_from_syserror (); - if (n && (*tmp & 0x80)) + 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; + extra = 1; } - + if (buffer && n > len) { /* The provided buffer is too short. */ - gcry_free (tmp); - return gcry_error (GPG_ERR_TOO_SHORT); + xfree (tmp); + return GPG_ERR_TOO_SHORT; } if (buffer) { unsigned char *s = buffer; - if (extra) + if (extra == 1) *s++ = 0; - memcpy (s, tmp, n-extra); + else if (extra) + *s++ = 0xff; + memcpy (s, tmp, n-!!extra); } - gcry_free(tmp); + xfree (tmp); *nwritten = n; return 0; } @@ -581,17 +679,18 @@ gcry_mpi_print (enum gcry_mpi_format format, /* 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 gcry_error (GPG_ERR_TOO_SHORT); + return GPG_ERR_TOO_SHORT; if (buffer) { unsigned char *tmp; - tmp = _gcry_mpi_get_buffer (a, &n, NULL); + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); if (!tmp) - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); memcpy (buffer, tmp, n); - gcry_free (tmp); + xfree (tmp); } *nwritten = n; return 0; @@ -599,13 +698,13 @@ gcry_mpi_print (enum gcry_mpi_format format, else if (format == GCRYMPI_FMT_PGP) { unsigned int n = (nbits + 7)/8; - + /* The PGP format can only handle unsigned integers. */ - if( a->sign ) - return gcry_error (GPG_ERR_INV_ARG); + if (negative) + return GPG_ERR_INV_ARG; if (buffer && n+2 > len) - return gcry_error (GPG_ERR_TOO_SHORT); + return GPG_ERR_TOO_SHORT; if (buffer) { @@ -614,12 +713,12 @@ gcry_mpi_print (enum gcry_mpi_format format, s[0] = nbits >> 8; s[1] = nbits; - - tmp = _gcry_mpi_get_buffer (a, &n, NULL); + + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); if (!tmp) - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); memcpy (s+2, tmp, n); - gcry_free (tmp); + xfree (tmp); } *nwritten = n+2; return 0; @@ -629,14 +728,22 @@ gcry_mpi_print (enum gcry_mpi_format format, unsigned char *tmp; int extra = 0; unsigned int n; - - if (a->sign) - return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ - - tmp = _gcry_mpi_get_buffer (a, &n, NULL); + + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); if (!tmp) - return gpg_error_from_syserror (); - if (n && (*tmp & 0x80)) + 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; @@ -644,24 +751,25 @@ gcry_mpi_print (enum gcry_mpi_format format, if (buffer && n+4 > len) { - gcry_free(tmp); - return gcry_error (GPG_ERR_TOO_SHORT); + 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) + if (extra == 1) *s++ = 0; - - memcpy (s, tmp, n-extra); + else if (extra) + *s++ = 0xff; + memcpy (s, tmp, n-!!extra); } - gcry_free (tmp); + xfree (tmp); *nwritten = 4+n; return 0; } @@ -671,30 +779,30 @@ gcry_mpi_print (enum gcry_mpi_format format, int i; int extra = 0; unsigned int n = 0; - - tmp = _gcry_mpi_get_buffer (a, &n, NULL); + + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); if (!tmp) - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); if (!n || (*tmp & 0x80)) extra = 2; - if (buffer && 2*n + extra + !!a->sign + 1 > len) + if (buffer && 2*n + extra + negative + 1 > len) { - gcry_free(tmp); - return gcry_error (GPG_ERR_TOO_SHORT); + xfree(tmp); + return GPG_ERR_TOO_SHORT; } if (buffer) { unsigned char *s = buffer; - if (a->sign) + if (negative) *s++ = '-'; if (extra) { *s++ = '0'; *s++ = '0'; } - + for (i=0; i < n; i++) { unsigned int c = tmp[i]; @@ -706,15 +814,15 @@ gcry_mpi_print (enum gcry_mpi_format format, *s++ = 0; *nwritten = s - buffer; } - else + else { - *nwritten = 2*n + extra + !!a->sign + 1; + *nwritten = 2*n + extra + negative + 1; } - gcry_free (tmp); + xfree (tmp); return 0; } else - return gcry_error (GPG_ERR_INV_ARG); + return GPG_ERR_INV_ARG; } @@ -723,26 +831,30 @@ gcry_mpi_print (enum gcry_mpi_format format, * The caller has to supply the address of a pointer. NWRITTEN may be * NULL. */ -gcry_error_t -gcry_mpi_aprint (enum gcry_mpi_format format, - unsigned char **buffer, size_t *nwritten, - struct gcry_mpi *a) +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_error_t rc; - + gcry_err_code_t rc; + *buffer = NULL; - rc = gcry_mpi_print (format, NULL, 0, &n, a); + rc = _gcry_mpi_print (format, NULL, 0, &n, a); if (rc) return rc; - *buffer = mpi_is_secure(a) ? gcry_malloc_secure (n) : gcry_malloc (n); + *buffer = mpi_is_secure(a) ? xtrymalloc_secure (n?n:1) : xtrymalloc (n?n:1); if (!*buffer) - return gpg_error_from_syserror (); - rc = gcry_mpi_print( format, *buffer, n, &n, a ); + 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) { - gcry_free(*buffer); + xfree (*buffer); *buffer = NULL; } else if (nwritten) @@ -750,3 +862,58 @@ gcry_mpi_aprint (enum gcry_mpi_format format, 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; +} |