mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-23 10:29:58 +01:00
ec0cc1f135
corrupt) MPI, make sure the number of bytes we read is valid so we can skip the rest of the bad packet (in hopes the whole stream isn't invalid).
448 lines
10 KiB
C
448 lines
10 KiB
C
/* mpicoder.c - Coder for the external representation of MPIs
|
|
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of GnuPG.
|
|
*
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GnuPG 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include "mpi.h"
|
|
#include "mpi-internal.h"
|
|
#include "iobuf.h"
|
|
#include "memory.h"
|
|
#include "util.h"
|
|
|
|
#ifdef M_DEBUG
|
|
#undef mpi_read
|
|
#endif
|
|
|
|
#define MAX_EXTERN_MPI_BITS 16384
|
|
|
|
/****************
|
|
* write an mpi to out.
|
|
*/
|
|
int
|
|
mpi_write( IOBUF out, MPI a )
|
|
{
|
|
int rc;
|
|
unsigned nbits = mpi_get_nbits(a);
|
|
byte *p, *buf;
|
|
unsigned n;
|
|
|
|
if( nbits > MAX_EXTERN_MPI_BITS )
|
|
log_bug("mpi_encode: mpi too large (%u bits)\n", nbits);
|
|
|
|
iobuf_put(out, (nbits >>8) );
|
|
iobuf_put(out, (nbits) );
|
|
|
|
p = buf = mpi_get_buffer( a, &n, NULL );
|
|
rc = iobuf_write( out, p, n );
|
|
m_free(buf);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************
|
|
* Read an external representation of an mpi and return the MPI
|
|
* The external format is a 16 bit unsigned value stored in network byte order,
|
|
* giving the number of bits for the following integer. The integer is stored
|
|
* with MSB first (left padded with zeroes to align on a byte boundary).
|
|
*/
|
|
MPI
|
|
#ifdef M_DEBUG
|
|
mpi_debug_read(IOBUF inp, unsigned *ret_nread, int secure, const char *info)
|
|
#else
|
|
mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
|
|
#endif
|
|
{
|
|
int c, i, j;
|
|
unsigned nbits, nbytes, nlimbs, nread=0;
|
|
mpi_limb_t a;
|
|
MPI val = MPI_NULL;
|
|
|
|
if( (c = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nread++;
|
|
nbits = c << 8;
|
|
if( (c = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nread++;
|
|
nbits |= c;
|
|
if( nbits > MAX_EXTERN_MPI_BITS ) {
|
|
log_error("mpi too large (%u bits)\n", nbits);
|
|
goto leave;
|
|
}
|
|
|
|
nbytes = (nbits+7) / 8;
|
|
nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
|
|
#ifdef M_DEBUG
|
|
val = secure? mpi_debug_alloc_secure( nlimbs, info )
|
|
: mpi_debug_alloc( nlimbs, info );
|
|
#else
|
|
val = secure? mpi_alloc_secure( nlimbs )
|
|
: mpi_alloc( nlimbs );
|
|
#endif
|
|
i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
|
|
i %= BYTES_PER_MPI_LIMB;
|
|
val->nbits = nbits;
|
|
j= val->nlimbs = nlimbs;
|
|
val->sign = 0;
|
|
for( ; j > 0; j-- ) {
|
|
a = 0;
|
|
for(; i < BYTES_PER_MPI_LIMB; i++ ) {
|
|
a <<= 8;
|
|
a |= iobuf_get(inp) & 0xff; nread++;
|
|
}
|
|
i = 0;
|
|
val->d[j-1] = a;
|
|
}
|
|
|
|
leave:
|
|
if( nread > *ret_nread )
|
|
log_bug("mpi crosses packet border\n");
|
|
else
|
|
*ret_nread = nread;
|
|
return val;
|
|
}
|
|
|
|
|
|
MPI
|
|
mpi_read_from_buffer(byte *buffer, unsigned *ret_nread, int secure)
|
|
{
|
|
int i, j;
|
|
unsigned nbits, nbytes, nlimbs, nread=0;
|
|
mpi_limb_t a;
|
|
MPI val = MPI_NULL;
|
|
|
|
if( *ret_nread < 2 )
|
|
goto leave;
|
|
nbits = buffer[0] << 8 | buffer[1];
|
|
if( nbits > MAX_EXTERN_MPI_BITS ) {
|
|
log_error("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;
|
|
val->nbits = nbits;
|
|
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_bug("mpi larger than buffer\n");
|
|
a <<= 8;
|
|
a |= *buffer++;
|
|
}
|
|
i = 0;
|
|
val->d[j-1] = a;
|
|
}
|
|
|
|
leave:
|
|
*ret_nread = nread;
|
|
return val;
|
|
}
|
|
|
|
|
|
/****************
|
|
* Make an mpi from a character string.
|
|
*/
|
|
int
|
|
mpi_fromstr(MPI val, const char *str)
|
|
{
|
|
int hexmode=0, sign=0, prepend_zero=0, i, j, c, c1, c2;
|
|
unsigned nbits, nbytes, nlimbs;
|
|
mpi_limb_t a;
|
|
|
|
if( *str == '-' ) {
|
|
sign = 1;
|
|
str++;
|
|
}
|
|
if( *str == '0' && str[1] == 'x' )
|
|
hexmode = 1;
|
|
else
|
|
return 1; /* other bases are not yet supported */
|
|
str += 2;
|
|
|
|
nbits = strlen(str)*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++;
|
|
assert(c1);
|
|
c2 = *str++;
|
|
assert(c2);
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
a <<= 8;
|
|
a |= c;
|
|
}
|
|
i = 0;
|
|
val->d[j-1] = a;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/****************
|
|
* print an MPI to the given stream and return the number of characters
|
|
* printed.
|
|
*/
|
|
int
|
|
mpi_print( FILE *fp, MPI a, int mode )
|
|
{
|
|
int i, n=0;
|
|
|
|
if( a == MPI_NULL )
|
|
return fprintf(fp, "[MPI_NULL]");
|
|
if( !mode ) {
|
|
unsigned int n1;
|
|
|
|
n1 = mpi_get_nbits(a);
|
|
n += fprintf(fp, "[%u bits]", n1);
|
|
}
|
|
else {
|
|
if( a->sign )
|
|
putc('-', fp);
|
|
#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"
|
|
#else
|
|
#error please define the format here
|
|
#endif
|
|
for(i=a->nlimbs; i > 0 ; i-- ) {
|
|
n += fprintf(fp, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]);
|
|
#undef X
|
|
}
|
|
if( !a->nlimbs )
|
|
putc('0', fp );
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
void
|
|
g10_log_mpidump( const char *text, MPI a )
|
|
{
|
|
FILE *fp = log_stream();
|
|
|
|
g10_log_print_prefix(text);
|
|
mpi_print(fp, a, 1 );
|
|
fputc('\n', fp);
|
|
}
|
|
|
|
/****************
|
|
* Special function to get the low 8 bytes from an mpi.
|
|
* This can be used as a keyid; KEYID is an 2 element array.
|
|
* Return the low 4 bytes.
|
|
*/
|
|
u32
|
|
mpi_get_keyid( MPI a, u32 *keyid )
|
|
{
|
|
#if BYTES_PER_MPI_LIMB == 4
|
|
if( keyid ) {
|
|
keyid[0] = a->nlimbs >= 2? a->d[1] : 0;
|
|
keyid[1] = a->nlimbs >= 1? a->d[0] : 0;
|
|
}
|
|
return a->nlimbs >= 1? a->d[0] : 0;
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
|
if( keyid ) {
|
|
keyid[0] = a->nlimbs? (u32)(a->d[0] >> 32) : 0;
|
|
keyid[1] = a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0;
|
|
}
|
|
return a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0;
|
|
#else
|
|
#error Make this function work with other LIMB sizes
|
|
#endif
|
|
}
|
|
|
|
|
|
/****************
|
|
* Return an m_alloced buffer with the MPI (msb first).
|
|
* NBYTES receives the length of this buffer. Caller must free the
|
|
* return string (This function does return a 0 byte 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.
|
|
*/
|
|
static byte *
|
|
do_get_buffer( MPI a, unsigned *nbytes, int *sign, int force_secure )
|
|
{
|
|
byte *p, *buffer;
|
|
mpi_limb_t alimb;
|
|
int i;
|
|
unsigned int n;
|
|
|
|
if( sign )
|
|
*sign = a->sign;
|
|
*nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
|
|
if (!n)
|
|
n++; /* avoid zero length allocation */
|
|
p = buffer = force_secure || mpi_is_secure(a) ? m_alloc_secure(n)
|
|
: m_alloc(n);
|
|
|
|
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
|
|
}
|
|
|
|
/* 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 )
|
|
;
|
|
if( p != buffer )
|
|
memmove(buffer,p, *nbytes);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
byte *
|
|
mpi_get_buffer( MPI a, unsigned *nbytes, int *sign )
|
|
{
|
|
return do_get_buffer( a, nbytes, sign, 0 );
|
|
}
|
|
|
|
byte *
|
|
mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign )
|
|
{
|
|
return do_get_buffer( a, nbytes, sign, 1 );
|
|
}
|
|
|
|
/****************
|
|
* Use BUFFER to update MPI.
|
|
*/
|
|
void
|
|
mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign )
|
|
{
|
|
const byte *p;
|
|
mpi_limb_t alimb;
|
|
int nlimbs;
|
|
int i;
|
|
|
|
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 = (mpi_limb_t)*p-- ;
|
|
alimb |= (mpi_limb_t)*p-- << 8 ;
|
|
alimb |= (mpi_limb_t)*p-- << 16 ;
|
|
alimb |= (mpi_limb_t)*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 |= (mpi_limb_t)*p-- << 8 ;
|
|
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 16 ;
|
|
if( p >= buffer ) alimb |= (mpi_limb_t)*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;
|
|
assert( i == nlimbs );
|
|
}
|