/* misc.c - miscellaneous functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
* 2008, 2009, 2010 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 3 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, see .
*/
#include
#include
#include
#include
#include
#include
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include
#include
#endif
#ifdef HAVE_SETRLIMIT
#include
#include
#include
#endif
#ifdef ENABLE_SELINUX_HACKS
#include
#endif
#ifdef HAVE_W32_SYSTEM
#include
#include
#include
#include
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE 0x8000
#endif
#endif /*HAVE_W32_SYSTEM*/
#include "gpg.h"
#ifdef HAVE_W32_SYSTEM
# include "status.h"
#endif /*HAVE_W32_SYSTEM*/
#include "util.h"
#include "main.h"
#include "photoid.h"
#include "options.h"
#include "call-agent.h"
#include "i18n.h"
#include
static int
string_count_chr (const char *string, int c)
{
int count;
for (count=0; *string; string++ )
if ( *string == c )
count++;
return count;
}
#ifdef ENABLE_SELINUX_HACKS
/* A object and a global variable to keep track of files marked as
secured. */
struct secured_file_item
{
struct secured_file_item *next;
ino_t ino;
dev_t dev;
};
static struct secured_file_item *secured_files;
#endif /*ENABLE_SELINUX_HACKS*/
/* For the sake of SELinux we want to restrict access through gpg to
certain files we keep under our own control. This function
registers such a file and is_secured_file may then be used to
check whether a file has ben registered as secured. */
void
register_secured_file (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
/* Note that we stop immediatley if something goes wrong here. */
if (stat (fname, &buf))
log_fatal (_("fstat of '%s' failed in %s: %s\n"), fname,
"register_secured_file", strerror (errno));
/* log_debug ("registering '%s' i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return; /* Already registered. */
}
sf = xmalloc (sizeof *sf);
sf->ino = buf.st_ino;
sf->dev = buf.st_dev;
sf->next = secured_files;
secured_files = sf;
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
}
/* Remove a file registered as secure. */
void
unregister_secured_file (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf, *sfprev;
if (stat (fname, &buf))
{
log_error (_("fstat of '%s' failed in %s: %s\n"), fname,
"unregister_secured_file", strerror (errno));
return;
}
/* log_debug ("unregistering '%s' i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sfprev=NULL,sf=secured_files; sf; sfprev=sf, sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
{
if (sfprev)
sfprev->next = sf->next;
else
secured_files = sf->next;
xfree (sf);
return;
}
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
}
/* Return true if FD is corresponds to a secured file. Using -1 for
FS is allowed and will return false. */
int
is_secured_file (int fd)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
if (fd == -1)
return 0; /* No file descriptor so it can't be secured either. */
/* Note that we print out a error here and claim that a file is
secure if something went wrong. */
if (fstat (fd, &buf))
{
log_error (_("fstat(%d) failed in %s: %s\n"), fd,
"is_secured_file", strerror (errno));
return 1;
}
/* log_debug ("is_secured_file (%d) i=%lu.%lu\n", fd, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return 1; /* Yes. */
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fd;
#endif /*!ENABLE_SELINUX_HACKS*/
return 0; /* No. */
}
/* Return true if FNAME is corresponds to a secured file. Using NULL,
"" or "-" for FS is allowed and will return false. This function is
used before creating a file, thus it won't fail if the file does
not exist. */
int
is_secured_filename (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
if (iobuf_is_pipe_filename (fname) || !*fname)
return 0;
/* Note that we print out a error here and claim that a file is
secure if something went wrong. */
if (stat (fname, &buf))
{
if (errno == ENOENT || errno == EPERM || errno == EACCES)
return 0;
log_error (_("fstat of '%s' failed in %s: %s\n"), fname,
"is_secured_filename", strerror (errno));
return 1;
}
/* log_debug ("is_secured_filename (%s) i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return 1; /* Yes. */
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
return 0; /* No. */
}
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 (gcry_mpi_t a)
{
u16 csum;
byte *buffer;
size_t nbytes;
if ( gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, a) )
BUG ();
/* Fixme: For numbers not in secure memory we should use a stack
* based buffer and only allocate a larger one if mpi_print returns
* an error. */
buffer = (gcry_is_secure(a)?
gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes));
if ( gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, NULL, a) )
BUG ();
csum = checksum (buffer, nbytes);
xfree (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;
}
void
print_pubkey_algo_note( int algo )
{
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
log_info (_("WARNING: using experimental public key algorithm %s\n"),
openpgp_cipher_algo_name (algo));
}
}
else if (algo == 20)
{
log_info (_("WARNING: Elgamal sign+encrypt keys are deprecated\n"));
}
}
void
print_cipher_algo_note( int algo )
{
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
log_info (_("WARNING: using experimental cipher algorithm %s\n"),
openpgp_cipher_algo_name (algo));
}
}
}
void
print_digest_algo_note( int algo )
{
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
log_info (_("WARNING: using experimental digest algorithm %s\n"),
gcry_md_algo_name (algo));
}
}
else if(algo==DIGEST_ALGO_MD5)
log_info (_("WARNING: digest algorithm %s is deprecated\n"),
gcry_md_algo_name (algo));
}
/* Map OpenPGP algo numbers to those used by Libgcrypt. We need to do
this for algorithms we implemented in Libgcrypt after they become
part of OpenPGP. */
int
map_cipher_openpgp_to_gcry (int algo)
{
switch (algo)
{
case CIPHER_ALGO_CAMELLIA128: return 310;
case CIPHER_ALGO_CAMELLIA192: return 311;
case CIPHER_ALGO_CAMELLIA256: return 312;
default: return algo;
}
}
/* The inverse fucntion of above. */
static int
map_cipher_gcry_to_openpgp (int algo)
{
switch (algo)
{
case 310: return CIPHER_ALGO_CAMELLIA128;
case 311: return CIPHER_ALGO_CAMELLIA192;
case 312: return CIPHER_ALGO_CAMELLIA256;
default: return algo;
}
}
/* Map OpenPGP public key algorithm numbers to those used by
Libgcrypt. */
int
map_pk_openpgp_to_gcry (int algo)
{
switch (algo)
{
case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA;
case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH;
default: return algo;
}
}
/* Map Gcrypt public key algorithm numbers to those used by
OpenPGP. */
int
map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
{
switch (algo)
{
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
default: return algo < 110 ? algo : 0;
}
}
/* Return the block length of an OpenPGP cipher algorithm. */
int
openpgp_cipher_blocklen (int algo)
{
/* We use the numbers from OpenPGP to be sure that we get the right
block length. This is so that the packet parsing code works even
for unknown algorithms (for which we assume 8 due to tradition).
NOTE: If you change the the returned blocklen above 16, check
the callers because they may use a fixed size buffer of that
size. */
switch (algo)
{
case 7: case 8: case 9: /* AES */
case 10: /* Twofish */
case 11: case 12: case 13: /* Camellia */
return 16;
default:
return 8;
}
}
/****************
* Wrapper around the libgcrypt function with additonal checks on
* the OpenPGP contraints for the algo ID.
*/
int
openpgp_cipher_test_algo( int algo )
{
/* (5 and 6 are marked reserved by rfc4880.) */
if ( algo < 0 || algo > 110 || algo == 5 || algo == 6 )
return gpg_error (GPG_ERR_CIPHER_ALGO);
return gcry_cipher_test_algo (map_cipher_openpgp_to_gcry (algo));
}
/* Map the OpenPGP cipher algorithm whose ID is contained in ALGORITHM to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_cipher_algo_name (int algo)
{
return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
}
int
openpgp_pk_test_algo( int algo )
{
/* Dont't allow type 20 keys unless in rfc2440 mode. */
if (!RFC2440 && algo == 20)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo));
}
int
openpgp_pk_test_algo2( int algo, unsigned int use )
{
size_t use_buf = use;
/* Dont't allow type 20 keys unless in rfc2440 mode. */
if (!RFC2440 && algo == 20)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo),
GCRYCTL_TEST_ALGO, NULL, &use_buf);
}
int
openpgp_pk_algo_usage ( int algo )
{
int use = 0;
/* They are hardwired in gpg 1.0. */
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
if (RFC2440)
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
case PUBKEY_ALGO_ECDSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
default:
break;
}
return use;
}
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_pk_algo_name (int algo)
{
return gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo));
}
int
openpgp_md_test_algo( int algo )
{
/* Note: If the list of actual supported OpenPGP algorithms changes,
make sure that our hard coded values at
print_status_begin_signing() gets updated. */
/* 4, 5, 6, 7 are defined by rfc2440 but will be removed from the
next revision of the standard. */
if (algo < 0 || algo > 110 || (algo >= 4 && algo <= 7))
return gpg_error (GPG_ERR_DIGEST_ALGO);
return gcry_md_test_algo (algo);
}
/* Map the OpenPGP digest algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_md_algo_name (int algo)
{
if (algo < 0 || algo > 110)
return "?";
return gcry_md_algo_name (algo);
}
static unsigned long
get_signature_count (PKT_public_key *pk)
{
#ifdef ENABLE_CARD_SUPPORT
struct agent_card_info_s info;
(void)pk;
if (!agent_scd_getattr ("SIG-COUNTER",&info))
return info.sig_counter;
else
return 0;
#else
(void)pk;
return 0;
#endif
}
/* Expand %-strings. Returns a string which must be xfreed. Returns
NULL if the string cannot be expanded (too large). */
char *
pct_expando(const char *string,struct expando_args *args)
{
const char *ch=string;
int idx=0,maxlen=0,done=0;
u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
char *ret=NULL;
if(args->pk)
keyid_from_pk(args->pk,pk_keyid);
if(args->pksk)
keyid_from_pk (args->pksk, sk_keyid);
/* This is used so that %k works in photoid command strings in
--list-secret-keys (which of course has a sk, but no pk). */
if(!args->pk && args->pksk)
keyid_from_pk (args->pksk, pk_keyid);
while(*ch!='\0')
{
if(!done)
{
/* 8192 is way bigger than we'll need here */
if(maxlen>=8192)
goto fail;
maxlen+=1024;
ret=xrealloc(ret,maxlen);
}
done=0;
if(*ch=='%')
{
switch(*(ch+1))
{
case 's': /* short key id */
if(idx+8pksk));
idx+=strlen(&ret[idx]);
done=1;
}
break;
case 'p': /* primary pk fingerprint of a sk */
case 'f': /* pk fingerprint */
case 'g': /* sk fingerprint */
{
byte array[MAX_FINGERPRINT_LEN];
size_t len;
int i;
if((*(ch+1))=='p' && args->pksk)
{
if(args->pksk->flags.primary)
fingerprint_from_pk (args->pksk, array, &len);
else if (args->pksk->main_keyid[0]
|| args->pksk->main_keyid[1])
{
/* FIXME: Document teh code and check whether
it is still needed. */
PKT_public_key *pk=
xmalloc_clear(sizeof(PKT_public_key));
if (!get_pubkey_fast (pk,args->pksk->main_keyid))
fingerprint_from_pk (pk, array, &len);
else
memset (array, 0, (len=MAX_FINGERPRINT_LEN));
free_public_key (pk);
}
else
memset(array,0,(len=MAX_FINGERPRINT_LEN));
}
else if((*(ch+1))=='f' && args->pk)
fingerprint_from_pk (args->pk, array, &len);
else if((*(ch+1))=='g' && args->pksk)
fingerprint_from_pk (args->pksk, array, &len);
else
memset(array,0,(len=MAX_FINGERPRINT_LEN));
if(idx+(len*2)validity_info && idx+1validity_info;
ret[idx]='\0';
done=1;
}
break;
/* The text string types */
case 't':
case 'T':
case 'V':
{
const char *str=NULL;
switch(*(ch+1))
{
case 't': /* e.g. "jpg" */
str=image_type_to_string(args->imagetype,0);
break;
case 'T': /* e.g. "image/jpeg" */
str=image_type_to_string(args->imagetype,2);
break;
case 'V': /* e.g. "full", "expired", etc. */
str=args->validity_string;
break;
}
if(str && idx+strlen(str)='A' && file[0]<='Z')
|| (file[0]>='a' && file[0]<='z'))
&& file[1]==':')
#else
|| file[0]=='/'
#endif
)
return access(file,mode);
else
{
/* At least as large as, but most often larger than we need. */
char *buffer=xmalloc(strlen(envpath)+1+strlen(file)+1);
char *split,*item,*path=xstrdup(envpath);
split=path;
while((item=strsep(&split,PATHSEP_S)))
{
strcpy(buffer,item);
strcat(buffer,"/");
strcat(buffer,file);
ret=access(buffer,mode);
if(ret==0)
break;
}
xfree(path);
xfree(buffer);
}
return ret;
}
/* Return the number of public key parameters as used by OpenPGP. */
int
pubkey_get_npkey (int algo)
{
size_t n;
/* ECC is special. */
if (algo == PUBKEY_ALGO_ECDSA)
return 2;
else if (algo == PUBKEY_ALGO_ECDH)
return 3;
/* All other algorithms match those of Libgcrypt. */
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (is_RSA (algo))
algo = GCRY_PK_RSA;
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
n = 0;
return n;
}
/* Return the number of secret key parameters as used by OpenPGP. */
int
pubkey_get_nskey (int algo)
{
size_t n;
/* ECC is special. */
if (algo == PUBKEY_ALGO_ECDSA)
return 3;
else if (algo == PUBKEY_ALGO_ECDH)
return 4;
/* All other algorithms match those of Libgcrypt. */
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (is_RSA (algo))
algo = GCRY_PK_RSA;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
n = 0;
return n;
}
/* Temporary helper. */
int
pubkey_get_nsig (int algo)
{
size_t n;
/* ECC is special. */
if (algo == PUBKEY_ALGO_ECDSA)
return 2;
else if (algo == PUBKEY_ALGO_ECDH)
return 0;
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (is_RSA (algo))
algo = GCRY_PK_RSA;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
n = 0;
return n;
}
/* Temporary helper. */
int
pubkey_get_nenc (int algo)
{
size_t n;
/* ECC is special. */
if (algo == PUBKEY_ALGO_ECDSA)
return 0;
else if (algo == PUBKEY_ALGO_ECDH)
return 2;
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (is_RSA (algo))
algo = GCRY_PK_RSA;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
n = 0;
return n;
}
/* Temporary helper. */
unsigned int
pubkey_nbits( int algo, gcry_mpi_t *key )
{
int rc, nbits;
gcry_sexp_t sexp;
if( algo == PUBKEY_ALGO_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 == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E ) {
rc = gcry_sexp_build ( &sexp, NULL,
"(public-key(elg(p%m)(g%m)(y%m)))",
key[0], key[1], key[2] );
}
else if( is_RSA (algo) ) {
rc = gcry_sexp_build ( &sexp, NULL,
"(public-key(rsa(n%m)(e%m)))",
key[0], key[1] );
}
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
char *curve = openpgp_oid_to_str (key[0]);
if (!curve)
rc = gpg_error_from_syserror ();
else
{
rc = gcry_sexp_build (&sexp, NULL,
"(public-key(ecc(curve%s)(q%m)))",
curve, key[1]);
xfree (curve);
}
}
else
return 0;
if ( rc )
BUG ();
nbits = gcry_pk_get_nbits( sexp );
gcry_sexp_release( sexp );
return nbits;
}
int
mpi_print (estream_t fp, gcry_mpi_t a, int mode)
{
int n=0;
if (!a)
return es_fprintf (fp, "[MPI_NULL]");
if (!mode)
{
unsigned int n1;
n1 = gcry_mpi_get_nbits(a);
n += es_fprintf (fp, "[%u bits]", n1);
}
else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
unsigned int nbits;
unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
if (!p)
n += es_fprintf (fp, "[invalid opaque value]");
else
{
nbits = (nbits + 7)/8;
for (; nbits; nbits--, p++)
n += es_fprintf (fp, "%02X", *p);
}
}
else
{
unsigned char *buffer;
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a))
BUG ();
es_fputs (buffer, fp);
n += strlen (buffer);
gcry_free (buffer);
}
return n;
}
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point,
i.e. 04 */
unsigned int
ecdsa_qbits_from_Q (unsigned int qbits)
{
if ((qbits%8) > 3)
{
log_error (_("ECDSA public key is expected to be in SEC encoding "
"multiple of 8 bits\n"));
return 0;
}
qbits -= qbits%8;
qbits /= 2;
return qbits;
}