mirror of
git://git.gnupg.org/gnupg.git
synced 2024-10-31 20:08:43 +01:00
484 lines
9.9 KiB
C
484 lines
9.9 KiB
C
/* misc.c - miscellaneous functions
|
|
* Copyright (C) 1998, 1999, 2000 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 <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
|
#include <asm/sysinfo.h>
|
|
#include <asm/unistd.h>
|
|
#endif
|
|
#ifdef HAVE_SETRLIMIT
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#endif
|
|
#include <assert.h>
|
|
|
|
#include <gcrypt.h>
|
|
#include "util.h"
|
|
#include "main.h"
|
|
#include "options.h"
|
|
#include "i18n.h"
|
|
|
|
|
|
#define MAX_EXTERN_MPI_BITS 16384
|
|
|
|
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
|
#warning using trap_unaligned
|
|
static int
|
|
setsysinfo(unsigned long op, void *buffer, unsigned long size,
|
|
int *start, void *arg, unsigned long flag)
|
|
{
|
|
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
|
|
}
|
|
|
|
void
|
|
trap_unaligned(void)
|
|
{
|
|
unsigned int buf[2];
|
|
|
|
buf[0] = SSIN_UACPROC;
|
|
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
|
|
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
|
|
}
|
|
#else
|
|
void
|
|
trap_unaligned(void)
|
|
{ /* dummy */
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
disable_core_dumps()
|
|
{
|
|
#ifdef HAVE_DOSISH_SYSTEM
|
|
return 0;
|
|
#else
|
|
#ifdef HAVE_SETRLIMIT
|
|
struct rlimit limit;
|
|
|
|
limit.rlim_cur = 0;
|
|
limit.rlim_max = 0;
|
|
if( !setrlimit( RLIMIT_CORE, &limit ) )
|
|
return 0;
|
|
if( errno != EINVAL && errno != ENOSYS )
|
|
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
|
|
#endif
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
* write an mpi to out.
|
|
*/
|
|
int
|
|
mpi_write( IOBUF out, MPI a )
|
|
{
|
|
char buffer[(MAX_EXTERN_MPI_BITS+7)/8];
|
|
size_t nbytes;
|
|
int rc;
|
|
|
|
nbytes = (MAX_EXTERN_MPI_BITS+7)/8;
|
|
rc = gcry_mpi_print( GCRYMPI_FMT_PGP, buffer, &nbytes, a );
|
|
if( !rc )
|
|
rc = iobuf_write( out, buffer, nbytes );
|
|
|
|
return rc;
|
|
}
|
|
|
|
/****************
|
|
* Writye a MPI to out, but in this case it is an opaque one,
|
|
* s used vor v3 protected keys.
|
|
*/
|
|
int
|
|
mpi_write_opaque( IOBUF out, MPI a )
|
|
{
|
|
size_t nbytes, nbits;
|
|
int rc;
|
|
char *p;
|
|
|
|
assert( gcry_mpi_get_flag( a, GCRYMPI_FLAG_OPAQUE ) );
|
|
p = gcry_mpi_get_opaque( a, &nbits );
|
|
nbytes = (nbits+7) / 8;
|
|
iobuf_put( out, nbits >> 8 );
|
|
iobuf_put( out, nbits );
|
|
rc = iobuf_write( out, p, nbytes );
|
|
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
|
|
mpi_read(IOBUF inp, unsigned int *ret_nread, int secure)
|
|
{
|
|
int c, c1, c2, i;
|
|
unsigned int nbits, nbytes, nread=0;
|
|
MPI a = NULL;
|
|
byte *buf = NULL;
|
|
byte *p;
|
|
|
|
if( (c = c1 = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nbits = c << 8;
|
|
if( (c = c2 = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nbits |= c;
|
|
if( nbits > MAX_EXTERN_MPI_BITS ) {
|
|
log_error("mpi too large (%u bits)\n", nbits);
|
|
goto leave;
|
|
}
|
|
nread = 2;
|
|
nbytes = (nbits+7) / 8;
|
|
buf = secure? gcry_xmalloc_secure( nbytes+2 ) : gcry_xmalloc( nbytes+2 );
|
|
p = buf;
|
|
p[0] = c1;
|
|
p[1] = c2;
|
|
for( i=0 ; i < nbytes; i++ ) {
|
|
p[i+2] = iobuf_get(inp) & 0xff;
|
|
nread++;
|
|
}
|
|
nread += nbytes;
|
|
if( gcry_mpi_scan( &a, GCRYMPI_FMT_PGP, buf, &nread ) )
|
|
a = NULL;
|
|
|
|
leave:
|
|
gcry_free(buf);
|
|
if( nread > *ret_nread )
|
|
log_bug("mpi larger than packet");
|
|
else
|
|
*ret_nread = nread;
|
|
return a;
|
|
}
|
|
|
|
/****************
|
|
* Same as mpi_read but the value is stored as an opaque MPI.
|
|
* This function is used to read encrypted MPI of v3 packets.
|
|
*/
|
|
GCRY_MPI
|
|
mpi_read_opaque(IOBUF inp, unsigned *ret_nread )
|
|
{
|
|
int c, c1, c2, i;
|
|
unsigned nbits, nbytes, nread=0;
|
|
GCRY_MPI a = NULL;
|
|
byte *buf = NULL;
|
|
byte *p;
|
|
|
|
if( (c = c1 = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nbits = c << 8;
|
|
if( (c = c2 = iobuf_get(inp)) == -1 )
|
|
goto leave;
|
|
nbits |= c;
|
|
if( nbits > MAX_EXTERN_MPI_BITS ) {
|
|
log_error("mpi too large (%u bits)\n", nbits);
|
|
goto leave;
|
|
}
|
|
nread = 2;
|
|
nbytes = (nbits+7) / 8;
|
|
buf = gcry_xmalloc( nbytes );
|
|
p = buf;
|
|
for( i=0 ; i < nbytes; i++ ) {
|
|
p[i] = iobuf_get(inp) & 0xff;
|
|
}
|
|
nread += nbytes;
|
|
a = gcry_mpi_set_opaque(NULL, buf, nbits );
|
|
buf = NULL;
|
|
|
|
leave:
|
|
gcry_free(buf);
|
|
if( nread > *ret_nread )
|
|
log_bug("mpi larger than packet");
|
|
else
|
|
*ret_nread = nread;
|
|
return a;
|
|
}
|
|
|
|
|
|
int
|
|
mpi_print( FILE *fp, MPI a, int mode )
|
|
{
|
|
int n=0;
|
|
|
|
if( !a )
|
|
return fprintf(fp, "[MPI_NULL]");
|
|
if( !mode ) {
|
|
unsigned int n1;
|
|
n1 = gcry_mpi_get_nbits(a);
|
|
n += fprintf(fp, "[%u bits]", n1);
|
|
}
|
|
else {
|
|
int rc;
|
|
char *buffer;
|
|
|
|
rc = gcry_mpi_aprint( GCRYMPI_FMT_HEX, (void **)&buffer, NULL, a );
|
|
assert( !rc );
|
|
fputs( buffer, fp );
|
|
n += strlen(buffer);
|
|
gcry_free( buffer );
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
|
|
u16
|
|
checksum_u16( unsigned n )
|
|
{
|
|
u16 a;
|
|
|
|
a = (n >> 8) & 0xff;
|
|
a += n & 0xff;
|
|
return a;
|
|
}
|
|
|
|
u16
|
|
checksum( byte *p, unsigned n )
|
|
{
|
|
u16 a;
|
|
|
|
for(a=0; n; n-- )
|
|
a += *p++;
|
|
return a;
|
|
}
|
|
|
|
u16
|
|
checksum_mpi( MPI a )
|
|
{
|
|
int rc;
|
|
u16 csum;
|
|
byte *buffer;
|
|
size_t nbytes;
|
|
|
|
rc = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, &nbytes, a );
|
|
assert( !rc );
|
|
/* fixme: for numbers not in the suecre memory we
|
|
* should use a stack based buffer and only allocate
|
|
* a larger one when the mpi_print return an error
|
|
*/
|
|
buffer = gcry_is_secure(a)? gcry_xmalloc_secure(nbytes) : gcry_xmalloc(nbytes);
|
|
rc = gcry_mpi_print( GCRYMPI_FMT_PGP, buffer, &nbytes, a );
|
|
assert( !rc );
|
|
csum = checksum( buffer, nbytes );
|
|
gcry_free( buffer );
|
|
return csum;
|
|
}
|
|
|
|
|
|
u32
|
|
buffer_to_u32( const byte *buffer )
|
|
{
|
|
unsigned long a;
|
|
a = *buffer << 24;
|
|
a |= buffer[1] << 16;
|
|
a |= buffer[2] << 8;
|
|
a |= buffer[3];
|
|
return a;
|
|
}
|
|
|
|
|
|
static void
|
|
no_exp_algo(void)
|
|
{
|
|
static int did_note = 0;
|
|
|
|
if( !did_note ) {
|
|
did_note = 1;
|
|
log_info(_("Experimental algorithms should not be used!\n"));
|
|
}
|
|
}
|
|
|
|
void
|
|
print_pubkey_algo_note( int algo )
|
|
{
|
|
if( algo >= 100 && algo <= 110 )
|
|
no_exp_algo();
|
|
}
|
|
|
|
void
|
|
print_cipher_algo_note( int algo )
|
|
{
|
|
if( algo >= 100 && algo <= 110 )
|
|
no_exp_algo();
|
|
else if( algo == GCRY_CIPHER_3DES
|
|
|| algo == GCRY_CIPHER_CAST5
|
|
|| algo == GCRY_CIPHER_BLOWFISH
|
|
|| algo == GCRY_CIPHER_RIJNDAEL
|
|
|| algo == GCRY_CIPHER_TWOFISH
|
|
)
|
|
;
|
|
else {
|
|
static int did_note = 0;
|
|
|
|
if( !did_note ) {
|
|
did_note = 1;
|
|
log_info(_("this cipher algorithm is depreciated; "
|
|
"please use a more standard one!\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
print_digest_algo_note( int algo )
|
|
{
|
|
if( algo >= 100 && algo <= 110 )
|
|
no_exp_algo();
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
* Wrapper around the libgcrypt function with addional checks on
|
|
* openPGP contraints for the algo ID.
|
|
*/
|
|
int
|
|
openpgp_cipher_test_algo( int algo )
|
|
{
|
|
if( algo < 0 || algo > 110 )
|
|
return GCRYERR_INV_CIPHER_ALGO;
|
|
return gcry_cipher_test_algo(algo);
|
|
}
|
|
|
|
int
|
|
openpgp_pk_test_algo( int algo, unsigned int usage_flags )
|
|
{
|
|
size_t n = usage_flags;
|
|
|
|
if( algo < 0 || algo > 110 )
|
|
return GCRYERR_INV_PK_ALGO;
|
|
return gcry_pk_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, &n );
|
|
}
|
|
|
|
int
|
|
openpgp_pk_algo_usage ( int algo )
|
|
{
|
|
int usage = 0;
|
|
|
|
/* some are hardwired */
|
|
switch ( algo ) {
|
|
case GCRY_PK_RSA:
|
|
usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
|
|
break;
|
|
case GCRY_PK_RSA_E:
|
|
usage = GCRY_PK_USAGE_ENCR;
|
|
break;
|
|
case GCRY_PK_RSA_S:
|
|
usage = GCRY_PK_USAGE_SIGN;
|
|
break;
|
|
case GCRY_PK_ELG_E:
|
|
usage = GCRY_PK_USAGE_ENCR;
|
|
break;
|
|
case GCRY_PK_DSA:
|
|
usage = GCRY_PK_USAGE_SIGN;
|
|
break;
|
|
case GCRY_PK_ELG:
|
|
usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
|
|
break;
|
|
default:
|
|
usage = gcry_pk_algo_info ( algo, GCRYCTL_GET_ALGO_USAGE,
|
|
NULL, NULL);
|
|
}
|
|
return usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
openpgp_md_test_algo( int algo )
|
|
{
|
|
if( algo < 0 || algo > 110 )
|
|
return GCRYERR_INV_MD_ALGO;
|
|
return gcry_md_test_algo(algo);
|
|
}
|
|
|
|
|
|
int
|
|
pubkey_get_npkey( int algo )
|
|
{
|
|
int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, 0 );
|
|
return n > 0? n : 0;
|
|
}
|
|
|
|
int
|
|
pubkey_get_nskey( int algo )
|
|
{
|
|
int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, 0 );
|
|
return n > 0? n : 0;
|
|
}
|
|
|
|
int
|
|
pubkey_get_nsig( int algo )
|
|
{
|
|
int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, 0 );
|
|
return n > 0? n : 0;
|
|
}
|
|
|
|
int
|
|
pubkey_get_nenc( int algo )
|
|
{
|
|
int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, 0 );
|
|
return n > 0? n : 0;
|
|
}
|
|
|
|
|
|
unsigned int
|
|
pubkey_nbits( int algo, MPI *key )
|
|
{
|
|
int rc, nbits;
|
|
GCRY_SEXP sexp;
|
|
|
|
if( algo == GCRY_PK_DSA ) {
|
|
rc = gcry_sexp_build ( &sexp, NULL,
|
|
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
|
|
key[0], key[1], key[2], key[3] );
|
|
}
|
|
else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
|
|
rc = gcry_sexp_build ( &sexp, NULL,
|
|
"(public-key(elg(p%m)(g%m)(y%m)))",
|
|
key[0], key[1], key[2] );
|
|
}
|
|
else if( algo == GCRY_PK_RSA ) {
|
|
rc = gcry_sexp_build ( &sexp, NULL,
|
|
"(public-key(rsa(n%m)(e%m)))",
|
|
key[0], key[1] );
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
if ( rc )
|
|
BUG ();
|
|
|
|
nbits = gcry_pk_get_nbits( sexp );
|
|
gcry_sexp_release( sexp );
|
|
return nbits;
|
|
}
|
|
|