edit-key is now complete

This commit is contained in:
Werner Koch 1998-07-29 19:35:05 +00:00
parent 1a80de41a5
commit 5ae562b41d
48 changed files with 2044 additions and 984 deletions

View File

@ -6,3 +6,7 @@ Werner Koch. Designed and implemented gnupg.
TRANSLATIONS Marco d'Itri 1997-02-22
Disclaim
Twofish Matthew Skala ????????????

25
NEWS
View File

@ -1,12 +1,37 @@
Noteworthy changes in version 0.3.3
-----------------------------------
* The format of the trust database has changed; you must delete
the old one, so gnupg can create a new one.
IMPORTANT: Use version 0.3.[12] to save your assigned ownertrusts
("gpgm --list-ownertrust >saved-trust"); then build this new version
and restore the ownertrust with this new version
("gpgm --import-ownertrust saved-trust").
* The command --edit-key now provides a commandline driven menu
which can be used vor vaious tasks. --sign-key is only an
an alias to --edit-key and maybe removed in future: use the
command "sign" of this new menu - you can select which user ids
you want to sign.
* Alternate user ids can now be created an signed.
* Removed options --gen-prime and --gen-random.
* Removed option --add-key; use --edit-key instead.
* Removed option --change-passphrase; use --edit-key instead.
* Signatures are now checked even if the output file could not
be created. Command "--verify" tries to find the detached data.
* gpg now disables core dumps.
* We have added the Twofish as an experimental cipher algorithm.
Many thanks to Matthew Skala for doing this work.
Twofish is the AES submission from Schneier et al.; see
"www.counterpane.com/twofish.html" for more information.
Noteworthy changes in version 0.3.2
-----------------------------------

3
README
View File

@ -135,6 +135,9 @@
Creates a signature of file, but writes the output to the file "out".
If you use the option "--rfc1991", gnupg tries to me more compatible
to RFC1991 (pgp 2.x).
Encrypt
-------

3
THANKS
View File

@ -5,6 +5,7 @@ errors.
Anand Kumria wildfire@progsoc.uts.edu.au
Brian Warner warner@lothar.com
Caskey L. Dickson caskey@technocage.com
Charles Levert charles@comm.polymtl.ca
Christian von Roques roques@pond.sub.org
Daniel Eisenbud eisenbud@cs.swarthmore.edu
@ -25,8 +26,10 @@ Martin Schulte schulte@thp.uni-koeln.de
Matthew Skala mskala@ansuz.sooke.bc.ca
Max Valianskiy maxcom@maxcom.ml.org
Nicolas Graner Nicolas.Graner@cri.u-psud.fr
Oskari Jääskeläinen f33003a@cc.hut.fi
Peter Gutmann pgut001@cs.auckland.ac.nz
Ralph Gillen gillen@theochem.uni-duesseldorf.de
Steffen Ullrich ccrlphr@xensei.com
Thomas Roessler roessler@guug.de
Tom Spindler dogcow@home.merit.edu
Tom Zerucha tzeruch@ceddec.com

16
TODO
View File

@ -2,6 +2,16 @@
can also hold the localid and extend the localid to hold information
of the subkey number because two subkeys may have the same keyid.
* Fix Oscaris problems with the trustdb.
* add test cases for invalid data (scrambled armor or other random data)
* fix the expire stuff for v4 packets.
* check whether it is valid to pack the signature stuff (onepass, data,
sig) into a compressed packet - or should we only compress the data?
what does pgp 5 do, what does OpenPGP say=
* invalid packets (Marco)
* add some sanity checks to read_keyblock, so that we are sure that
@ -9,9 +19,7 @@
* what about the CR,LF in cleartext singatures?
* add option --restore-ownertrust
* always put key signatures before the first subkey.
* add option --import-ownertrust
* add a way to delete subkeys (in edit-keys?)
@ -33,8 +41,6 @@
* add checking of armor trailers
* remove all "Fixmes"
* add an option to create a new user id.
* add an option to re-create a public key from a secret key. Think about
a backup system of only the secret part of the secret key.

View File

@ -61,10 +61,10 @@ chdir () {
set -e
pgmname=$(basename $0)
pgmname=`basename $0`
#trap cleanup SIGHUP SIGINT SIGQUIT
[ -z $srcdir ] && fatal "not called from make"
[ -z "$srcdir" ] && fatal "not called from make"
cat <<EOF >./options
no-greeting

View File

@ -1,3 +1,10 @@
Mon Jul 27 10:30:22 1998 Werner Koch (wk@(none))
* cipher.c : Support for other blocksizes
(cipher_get_blocksize): New.
* twofish.c: New.
* Makefile.am: Add twofish module.
Mon Jul 13 21:30:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (read_pool): Simple alloc if secure_alloc is not set.

View File

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
gnupg_extensions = tiger
gnupg_extensions = tiger twofish
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl
@ -42,9 +42,13 @@ libcipher_a_SOURCES = cipher.c \
smallprime.c
EXTRA_tiger_SOURCES = tiger.c
EXTRA_twofish_SOURCES = twofish.c
tiger: tiger.c
$(COMPILE) -shared -fPIC -o tiger tiger.c
$(COMPILE) -shared -fPIC -o tiger tiger.c
twofish: twofish.c
$(COMPILE) -shared -fPIC -o twofish twofish.c
install-exec-hook:
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \

View File

@ -34,12 +34,13 @@
#include "dynload.h"
#define STD_BLOCKSIZE 8
#define MAX_BLOCKSIZE 16
#define TABLE_SIZE 10
struct cipher_table_s {
const char *name;
int algo;
size_t blocksize;
size_t keylen;
size_t contextsize; /* allocate this amount of context */
void (*setkey)( void *c, byte *key, unsigned keylen );
@ -53,8 +54,9 @@ static struct cipher_table_s cipher_table[TABLE_SIZE];
struct cipher_handle_s {
int algo;
int mode;
byte iv[STD_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[STD_BLOCKSIZE];
size_t blocksize;
byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[MAX_BLOCKSIZE];
int unused; /* in IV */
void (*setkey)( void *c, byte *key, unsigned keylen );
void (*encrypt)( void *c, byte *outbuf, byte *inbuf );
@ -80,44 +82,44 @@ setup_cipher_table()
{
int i;
size_t blocksize;
i = 0;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&blocksize,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_CAST5;
cipher_table[i].name = cast5_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&blocksize,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH160;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&blocksize,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_DUMMY;
cipher_table[i].name = "DUMMY";
cipher_table[i].blocksize = 8;
cipher_table[i].keylen = 128;
cipher_table[i].contextsize = 0;
cipher_table[i].setkey = dummy_setkey;
@ -141,7 +143,6 @@ load_cipher_modules()
void *context = NULL;
struct cipher_table_s *ct;
int ct_idx;
size_t blocksize;
int i;
const char *name;
int any = 0;
@ -164,9 +165,9 @@ load_cipher_modules()
BUG(); /* table already full */
/* now load all extensions */
while( (name = enum_gnupgext_ciphers( &context, &ct->algo,
&ct->keylen, &blocksize, &ct->contextsize,
&ct->keylen, &ct->blocksize, &ct->contextsize,
&ct->setkey, &ct->encrypt, &ct->decrypt)) ) {
if( blocksize != STD_BLOCKSIZE ) {
if( ct->blocksize != 8 && ct->blocksize != 16 ) {
log_info("skipping cipher %d: unsupported blocksize\n", ct->algo);
continue;
}
@ -271,6 +272,26 @@ cipher_get_keylen( int algo )
return 0;
}
unsigned
cipher_get_blocksize( int algo )
{
int i;
unsigned len = 0;
do {
for(i=0; cipher_table[i].name; i++ ) {
if( cipher_table[i].algo == algo ) {
len = cipher_table[i].blocksize;
if( !len )
log_bug("cipher %d w/o blocksize\n", algo );
return len;
}
}
} while( load_cipher_modules() );
log_bug("cipher %d not found\n", algo );
return 0;
}
/****************
* Open a cipher handle for use with algorithm ALGO, in mode MODE
@ -299,6 +320,7 @@ cipher_open( int algo, int mode, int secure )
+ cipher_table[i].contextsize )
: m_alloc_clear( sizeof *hd + cipher_table[i].contextsize );
hd->algo = algo;
hd->blocksize = cipher_table[i].blocksize;
hd->setkey = cipher_table[i].setkey;
hd->encrypt = cipher_table[i].encrypt;
hd->decrypt = cipher_table[i].decrypt;
@ -336,9 +358,9 @@ void
cipher_setiv( CIPHER_HANDLE c, const byte *iv )
{
if( iv )
memcpy( c->iv, iv, STD_BLOCKSIZE );
memcpy( c->iv, iv, c->blocksize );
else
memset( c->iv, 0, STD_BLOCKSIZE );
memset( c->iv, 0, c->blocksize );
c->unused = 0;
}
@ -351,8 +373,8 @@ do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
for(n=0; n < nblocks; n++ ) {
(*c->encrypt)( &c->context, outbuf, inbuf );
inbuf += STD_BLOCKSIZE;;
outbuf += STD_BLOCKSIZE;
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
@ -363,8 +385,8 @@ do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
for(n=0; n < nblocks; n++ ) {
(*c->decrypt)( &c->context, outbuf, inbuf );
inbuf += STD_BLOCKSIZE;;
outbuf += STD_BLOCKSIZE;
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
@ -373,11 +395,12 @@ static void
do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv+STD_BLOCKSIZE - c->unused; nbytes; nbytes--, c->unused-- )
for(ivp=c->iv+c->blocksize - c->unused; nbytes; nbytes--, c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
return;
}
@ -385,26 +408,26 @@ do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
for(ivp=c->iv+STD_BLOCKSIZE - c->unused; c->unused; c->unused-- )
for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
}
/* now we can process complete blocks */
while( nbytes >= STD_BLOCKSIZE ) {
while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < STD_BLOCKSIZE; i++ )
for(ivp=c->iv,i=0; i < blocksize; i++ )
*outbuf++ = (*ivp++ ^= *inbuf++);
nbytes -= STD_BLOCKSIZE;
nbytes -= blocksize;
}
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
c->unused = STD_BLOCKSIZE;
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- )
@ -417,11 +440,12 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
ulong temp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv+STD_BLOCKSIZE - c->unused; nbytes; nbytes--,c->unused--){
for(ivp=c->iv+blocksize - c->unused; nbytes; nbytes--,c->unused--){
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
@ -432,7 +456,7 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
for(ivp=c->iv+STD_BLOCKSIZE - c->unused; c->unused; c->unused-- ) {
for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
@ -440,70 +464,24 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
}
/* now we can process complete blocks */
#ifdef BIG_ENDIAN_HOST
/* This does only make sense for big endian hosts, due to ... ivp = temp*/
if( !((ulong)inbuf % SIZEOF_UNSIGNED_LONG) ) {
while( nbytes >= STD_BLOCKSIZE ) {
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
(*c->encrypt)( &c->context, c->iv, c->iv );
ivp = c->iv;
/* XOR the input with the IV and store input into IV */
#if SIZEOF_UNSIGNED_LONG == STD_BLOCKSIZE
temp = *(ulong*)inbuf;
*(ulong*)outbuf = *(ulong*)c->iv ^ temp;
*(ulong*)ivp = temp;
#elif (2*SIZEOF_UNSIGNED_LONG) == STD_BLOCKSIZE
temp = ((ulong*)inbuf)[0];
((ulong*)outbuf)[0] = ((ulong*)c->iv)[0] ^ temp;
((ulong*)ivp)[0] = temp;
temp = ((ulong*)inbuf)[1];
((ulong*)outbuf)[1] = ((ulong*)c->iv)[1] ^ temp;
((ulong*)ivp)[1] = temp;
#elif (4*SIZEOF_UNSIGNED_LONG) == STD_BLOCKSIZE
temp = ((ulong*)inbuf)[0];
((ulong*)outbuf)[0] = ((ulong*)c->iv)[0] ^ temp;
((ulong*)ivp)[0] = temp;
temp = ((ulong*)inbuf)[1];
((ulong*)outbuf)[1] = ((ulong*)c->iv)[1] ^ temp;
((ulong*)ivp)[1] = temp;
temp = ((ulong*)inbuf)[2];
((ulong*)outbuf)[2] = ((ulong*)c->iv)[2] ^ temp;
((ulong*)ivp)[2] = temp;
temp = ((ulong*)inbuf)[3];
((ulong*)outbuf)[3] = ((ulong*)c->iv)[3] ^ temp;
((ulong*)ivp)[3] = temp;
#else
#error Please disable the align test.
#endif
nbytes -= STD_BLOCKSIZE;
inbuf += STD_BLOCKSIZE;
outbuf += STD_BLOCKSIZE;
while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < blocksize; i++ ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
nbytes -= blocksize;
}
else { /* non aligned version */
#endif /* BIG_ENDIAN_HOST */
while( nbytes >= STD_BLOCKSIZE ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
(*c->encrypt)( &c->context, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < STD_BLOCKSIZE; i++ ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
nbytes -= STD_BLOCKSIZE;
}
#ifdef BIG_ENDIAN_HOST
}
#endif
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
c->unused = STD_BLOCKSIZE;
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- ) {
@ -576,8 +554,8 @@ void
cipher_sync( CIPHER_HANDLE c )
{
if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) {
memmove(c->iv + c->unused, c->iv, STD_BLOCKSIZE - c->unused );
memcpy(c->iv, c->lastiv + STD_BLOCKSIZE - c->unused, c->unused);
memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused );
memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused);
c->unused = 0;
}
}

View File

@ -939,7 +939,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
void *ret;
int i = *sequence;
/*log_info("gnupgext_enum_func in rsa+idea called what=%d i=%d: ", what, i);*/
do {
if( i >= DIM(func_table) || i < 0 ) {
/*fprintf(stderr, "failed\n");*/

View File

@ -56,23 +56,18 @@ Record type 1:
--------------
Version information for this TrustDB. This is always the first
record of the DB and the only one with type 1.
1 byte value 2
1 byte value 1
3 bytes 'gpg' magic value
1 byte Version of the TrustDB
3 byte reserved
1 u32 locked by (pid) 0 = not locked.
1 u32 locked flags
1 u32 timestamp of trustdb creation
1 u32 timestamp of last modification
1 u32 timestamp of last validation
(Used to keep track of the time, when this TrustDB was checked
against the pubring)
1 u32 reserved
1 byte marginals needed
1 byte completes needed
1 byte max. cert depth
If any of this 3 values are changed, all cache records
must be invalidated.
9 bytes reserved
1 u32 record number of keyhashtable
12 bytes reserved
Record type 2: (directory record)
@ -183,9 +178,9 @@ Record type 9: (cache record)
Record Type 10 (hash table)
--------------
Due to the fact that we use the keyid to lookup keys, we can
Due to the fact that we use fingerprints to lookup keys, we can
implement quick access by some simple hash methods, and avoid
the overhead of gdbm. A property of keyids is that they can be
the overhead of gdbm. A property of fingerprints is that they can be
used directly as hash values. (They can be considered as strong
random numbers.)
What we use is a dynamic multilevel architecture, which combines
@ -194,11 +189,11 @@ Record Type 10 (hash table)
This record is a hashtable of 256 entries; a special property
is that all these records are stored consecutively to make one
big table. The hash value is simple the 1st, 2nd, ... byte of
the keyid (depending on the indirection level).
the fingerprint (depending on the indirection level).
1 byte value 10
1 byte reserved
n u32 recnum; n depends on th record length:
n u32 recnum; n depends on the record length:
n = (reclen-2)/4 which yields 9 for the current record length
of 40 bytes.
@ -206,18 +201,15 @@ Record Type 10 (hash table)
m = (256+n-1) / n
which is 29 for a record length of 40.
To look up a key we use its lsb to get the recnum from this
hashtable and look up the addressed record:
- If this record is another hashtable, we use 2nd lsb
To look up a key we use the first byte of the fingerprint to get
the recnum from this hashtable and look up the addressed record:
- If this record is another hashtable, we use 2nd byte
to index this hast table and so on.
- if this record is a hashlist, we walk thru the
reclist records until we found one whose hash field
matches the MSB of our keyid, and lookup this record
- if this record is a dir record, we compare the
keyid and if this is correct, we get the keyrecod and compare
the fingerprint to decide whether it is the requested key;
if this is not the correct dir record, we look at the next
dir record which is linked by the link field.
- if this record is a hashlist, we walk all entries
until we found one a matching one.
- if this record is a key record, we compare the
fingerprint and to decide whether it is the requested key;
Record type 11 (hash list)
--------------
@ -226,11 +218,10 @@ Record type 11 (hash list)
1 byte value 11
1 byte reserved
1 u32 next next hash list record
n times n = (reclen-6)/5
1 byte hash
n times n = (reclen-5)/5
1 u32 recnum
For the current record length of 40, n is 6
For the current record length of 40, n is 7

View File

@ -5,6 +5,7 @@ gpg - GNU Privacy Guard
=head1 SYNOPSIS
B<gpg> [--homedir name] [--options file] [options] command [args]
B<gpgm> [--homedir name] [--options file] [options] command [args]
=head1 DESCRIPTION
@ -98,23 +99,46 @@ B<--gen-key>
Generate a new key pair. This command can only be
used interactive.
B<--add-key> I<name>
Add a subkey to an already existing key. This
command is similiar to B<--gen-key> but a primary
key must already exit.
B<--sign-key> I<name>
Make a signature on key of user I<name>.
This looks for the key, displays the key and checks
all existing signatures of this key. If the key is
not yet signed by the default user (or the users given
with B<-u>), the program displays the information of
the key again, together with its fingerprint and
asks whether it should be signed. This question
is repeated for all users specified with B<-u>.
The key is then signed and the keyring which
contains the key is updated.
B<--edit-key> I<name>
Present a menu which enables you to do all key
related tasks:
B<sign>
Make a signature on key of user I<name>.
If the key is not yet signed by the default
user (or the users given with B<-u>), the
program displays the information of the key
again, together with its fingerprint and
asks whether it should be signed. This
question is repeated for all users specified
with B<-u>.
B<adduid>
Create an alternate user id.
B<deluid>
Delete an user id.
B<addkey>
Add a subkey to this key.
B<delkey>
Remove a subkey.
B<passwd>
Change the passphrase of the secret key.
B<check>
Check signatures
B<uid> I<n>
Toggle selection of user id with index I<n>.
Use 0 to deselect all.
B<key> I<n>
Toggle selection of subkey with index I<n>.
Use 0 to deselect all.
B<check>
Check all selected user ids.
B<toggle>
Toggle between public and secret key listing.
B<save>
Save all changes to the key rings and quit.
B<quit>
Quit the program without updating the
key rings.
B<--delete-key>
Remove key from the public keyring
@ -122,12 +146,6 @@ B<--delete-key>
B<--delete-secret-key>
Remove key from the secret and public keyring
B<--edit-key>
Edit/remove a key signature.
B<--change-passphrase>
Change the passphrase of your secret keyring
B<--gen-revoke>
Generate a revocation certificate.
@ -142,10 +160,15 @@ B<--export> [I<names>]
B<--import>
import/merge keys
B<--list-ownertrust>
B<--export-ownertrust>
List the assigned ownertrust values in ascii format for
backup purposes [B<gpgm> only].
B<--import-ownertrust> [I<filename>]
Update the trustdb with the ownertrust values stored in
I<filename> (or stdin if not given); existing values will be
overwritten. [B<gpgm> only].
=head1 OPTIONS
Long options can be put in an options file (default F<~/.gnupg/options>);

View File

@ -1,3 +1,26 @@
Wed Jul 29 12:53:03 1998 Werner Koch (wk@(none))
* free-packet.c (copy_signature): New.
* keygen.c (generate_subkeypair): rewritten
* g10.c (aKeyadd): Removed option --add-key
Mon Jul 27 10:37:28 1998 Werner Koch (wk@(none))
* seckey-cert.c (do_check): Additional check on cipher blocksize.
(protect_secret_key): Ditto.
* encr-data.c: Support for other blocksizes.
* cipher.c (write_header): Ditto.
Fri Jul 24 16:47:59 1998 Werner Koch (wk@(none))
* kbnode.c (insert_kbnode): Changed semantics and all callers.
* keyedit.c : More or less a complete rewrite
Wed Jul 22 17:10:04 1998 Werner Koch (wk@(none))
* build-packet.c (write_sign_packet_header): New.
Tue Jul 21 14:37:09 1998 Werner Koch (wk@(none))
* import.c (import_one): Now creates a trustdb record.

View File

@ -48,7 +48,6 @@ common_source = \
status.c \
status.h \
sign.c \
keyedit.c \
plaintext.c \
encr-data.c \
encode.c \
@ -61,6 +60,7 @@ gpg_SOURCES = g10.c \
$(common_source) \
verify.c \
decrypt.c \
keyedit.c \
keygen.c

View File

@ -57,3 +57,9 @@ compress-sigs
# Normally, compressing of signatures does not make sense; so this
# is disabled for detached signatures unless this option is used.
emulate-pgp-sign-bug
# PGP 2.x can only cope with 2 byte length headers of the
# signature packets, this option forces.

View File

@ -51,6 +51,7 @@ static int calc_header_length( u32 len );
static int write_16(IOBUF inp, u16 a);
static int write_32(IOBUF inp, u32 a);
static int write_header( IOBUF out, int ctb, u32 len );
static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
static int write_version( IOBUF out, int ctb );
@ -669,7 +670,10 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
for(i=0; i < n; i++ )
mpi_write(a, sig->data[i] );
write_header(out, ctb, iobuf_get_temp_length(a) );
if( is_RSA(sig->pubkey_algo) && sig->version < 4 )
write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) );
else
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
rc = G10ERR_WRITE_FILE;
@ -747,6 +751,18 @@ write_header( IOBUF out, int ctb, u32 len )
return write_header2( out, ctb, len, 0, 1 );
}
static int
write_sign_packet_header( IOBUF out, int ctb, u32 len )
{
/* work around a bug in the pgp read function for signature packets,
* which are not correctly coded and silently assume at some
* point 2 byte length headers.*/
iobuf_put(out, 0x89 );
iobuf_put(out, len >> 8 );
return iobuf_put(out, len ) == -1 ? -1:0;
}
/****************
* if HDRLEN is > 0, try to build a header of this length.
* we need this, so that we can hash packets without reading them again.

View File

@ -42,7 +42,8 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
{
PACKET pkt;
PKT_encrypted ed;
byte temp[10];
byte temp[18];
unsigned blocksize;
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
@ -52,15 +53,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n");
randomize_buffer( temp, 8, 1 );
temp[8] = temp[6];
temp[9] = temp[7];
blocksize = cipher_get_blocksize( cfx->dek->algo );
if( blocksize < 8 || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
randomize_buffer( temp, blocksize, 1 );
temp[blocksize] = temp[blocksize-2];
temp[blocksize+1] = temp[blocksize-1];
cfx->cipher_hd = cipher_open( cfx->dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
cipher_setiv( cfx->cipher_hd, NULL );
cipher_encrypt( cfx->cipher_hd, temp, temp, 10);
cipher_encrypt( cfx->cipher_hd, temp, temp, blocksize+2);
cipher_sync( cfx->cipher_hd );
iobuf_write(a, temp, 10);
iobuf_write(a, temp, blocksize+2);
cfx->header=1;
}

View File

@ -49,7 +49,8 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
decode_filter_ctx_t dfx;
byte *p;
int rc, c, i;
byte temp[16];
byte temp[32];
unsigned blocksize;
if( opt.verbose ) {
const char *s = cipher_algo_to_string( dek->algo );
@ -60,7 +61,10 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
}
if( (rc=check_cipher_algo(dek->algo)) )
return rc;
if( ed->len && ed->len < 10 )
blocksize = cipher_get_blocksize(dek->algo);
if( !blocksize || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
if( ed->len && ed->len < (blocksize+2) )
log_bug("Nanu\n"); /* oops: found a bug */
dfx.cipher_hd = cipher_open( dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
@ -70,20 +74,20 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
if( ed->len ) {
iobuf_set_limit( ed->buf, ed->len );
for(i=0; i < 10 && ed->len; i++, ed->len-- )
for(i=0; i < (blocksize+2) && ed->len; i++, ed->len-- )
temp[i] = iobuf_get(ed->buf);
}
else {
for(i=0; i < 10; i++ )
for(i=0; i < (blocksize+2); i++ )
if( (c=iobuf_get(ed->buf)) == -1 )
break;
else
temp[i] = c;
}
cipher_decrypt( dfx.cipher_hd, temp, temp, 10);
cipher_decrypt( dfx.cipher_hd, temp, temp, blocksize+2);
cipher_sync( dfx.cipher_hd );
p = temp;
if( p[6] != p[8] || p[7] != p[9] ) {
if( p[blocksize-2] != p[blocksize] || p[blocksize-1] != p[blocksize+1] ) {
cipher_close(dfx.cipher_hd);
return G10ERR_BAD_KEY;
}

View File

@ -55,7 +55,7 @@ void
free_seckey_enc( PKT_signature *sig )
{
int n, i;
n = pubkey_get_nenc( sig->pubkey_algo );
n = pubkey_get_nsig( sig->pubkey_algo );
if( !n ) {
m_free(sig->data[0]);
sig->data[0] = NULL;
@ -107,6 +107,20 @@ cp_fake_data( MPI a )
return d;
}
static void *
cp_data_block( byte *s )
{
byte *d;
u16 len;
if( !s )
return NULL;
len = (s[0] << 8) | s[1];
d = m_alloc( len+2 );
memcpy(d, s, len+2);
return d;
}
PKT_public_key *
copy_public_key( PKT_public_key *d, PKT_public_key *s )
@ -126,6 +140,39 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s )
return d;
}
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
int n, i;
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nsig( s->pubkey_algo );
if( !n )
d->data[0] = cp_fake_data(s->data[0]);
else {
for(i=0; i < n; i++ )
d->data[i] = mpi_copy( s->data[i] );
}
d->hashed_data = cp_data_block(s->hashed_data);
d->unhashed_data = cp_data_block(s->unhashed_data);
return d;
}
PKT_user_id *
copy_user_id( PKT_user_id *d, PKT_user_id *s )
{
if( !d )
d = m_alloc(sizeof *d + s->len - 1 );
memcpy( d, s, sizeof *d + s->len - 1 );
return d;
}
void
release_secret_key_parts( PKT_secret_key *sk )
{

View File

@ -68,11 +68,8 @@ static ARGPARSE_OPTS opts[] = {
{ 558, "list-secret-keys", 256, N_("list secret keys")},
#ifdef IS_G10
{ 503, "gen-key", 256, N_("generate a new key pair")},
{ 554, "add-key", 256, N_("add a subkey to a key pair")},
{ 506, "sign-key" ,256, N_("make a signature on a key in the keyring")},
{ 505, "delete-key",256, N_("remove key from the public keyring")},
{ 524, "edit-key" ,256, N_("edit a key signature")},
{ 525, "change-passphrase", 256, N_("change the passphrase of your secret keyring")},
{ 524, "edit-key" ,256, N_("sign or edit a key")},
{ 542, "gen-revoke",256, N_("generate a revocation certificate")},
#endif
{ 537, "export" , 256, N_("export keys") },
@ -81,7 +78,8 @@ static ARGPARSE_OPTS opts[] = {
{ 530, "import", 256 , N_("import/merge keys")},
{ 521, "list-packets",256,N_("list only the sequence of packets")},
#ifdef IS_G10MAINT
{ 564, "list-ownertrust", 256, N_("list the ownertrust values")},
{ 564, "export-ownertrust", 256, N_("export the ownertrust values")},
{ 525, "import-ownertrust", 256 , N_("import ownertrust values")},
{ 567, "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
{ 546, "dearmor", 256, N_("De-Armor a file or stdin") },
{ 547, "enarmor", 256, N_("En-Armor a file or stdin") },
@ -153,6 +151,7 @@ static ARGPARSE_OPTS opts[] = {
{ 504, "delete-secret-key",0, "@" },
{ 524, "edit-sig" ,0, "@"}, /* alias for edit-key */
{ 523, "passphrase-fd",1, "@" },
{ 506, "sign-key" ,256, "@" }, /* alias for edit-key */
#endif
{ 532, "quick-random", 0, "@"},
{ 526, "no-verbose", 0, "@"},
@ -173,18 +172,18 @@ static ARGPARSE_OPTS opts[] = {
{ 566, "compress-sigs",0, "@"},
{ 559, "always-trust", 0, "@"},
{ 562, "emulate-checksum-bug", 0, "@"},
/*554 is unused */
{0} };
enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
aSignKey, aClearsign, aListPackets, aEditKey, aDeleteKey, aDeleteSecretKey,
aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys,
aListSigs, aKeyadd, aListSecretKeys,
aExport, aExportSecret,
aKMode, aKModeC, aImport, aVerify, aDecrypt, aListKeys,
aListSigs, aListSecretKeys, aExport, aExportSecret,
aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, aPrintMDs,
aCheckTrustDB, aListTrustDB, aListTrustPath, aListOwnerTrust,
aCheckTrustDB, aListTrustDB, aListTrustPath,
aExportOwnerTrust, aImportOwnerTrust,
aDeArmor, aEnArmor, aGenRandom,
aTest };
@ -521,7 +520,6 @@ main( int argc, char **argv )
case 507: set_cmd( &cmd, aStore); break;
case 523: set_passphrase_fd( pargs.r.ret_int ); break;
case 524: set_cmd( &cmd, aEditKey); break;
case 525: set_cmd( &cmd, aChangePass); break;
case 527: def_cipher_string = m_strdup(pargs.r.ret_str); break;
case 529: def_digest_string = m_strdup(pargs.r.ret_str); break;
case 539: set_cmd( &cmd, aClearsign); break;
@ -548,7 +546,8 @@ main( int argc, char **argv )
case 546: set_cmd( &cmd, aDeArmor); break;
case 547: set_cmd( &cmd, aEnArmor); break;
case 555: set_cmd( &cmd, aPrintMD); break;
case 564: set_cmd( &cmd, aListOwnerTrust); break;
case 564: set_cmd( &cmd, aExportOwnerTrust); break;
case 525: set_cmd( &cmd, aImportOwnerTrust); break;
#endif /* IS_G10MAINT */
case 'o': opt.outfile = pargs.r.ret_str; break;
@ -564,7 +563,7 @@ main( int argc, char **argv )
case 510: opt.debug |= pargs.r.ret_ulong; break;
case 511: opt.debug = ~0; break;
case 512: set_status_fd( pargs.r.ret_int ); break;
case 515: opt.fingerprint = 1; break;
case 515: opt.fingerprint++; break;
case 517: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case 518:
/* config files may not be nested (silently ignore them) */
@ -595,17 +594,17 @@ main( int argc, char **argv )
case 551: set_cmd( &cmd, aListKeys); break;
case 552: set_cmd( &cmd, aListSigs); break;
case 553: opt.skip_verify=1; break;
case 554: set_cmd( &cmd, aKeyadd); break;
case 556: opt.def_compress_algo = pargs.r.ret_int; break;
case 557: opt.compress_keys = 1; break;
case 558: set_cmd( &cmd, aListSecretKeys); break;
case 559: opt.always_trust = 1; break;
case 560: register_cipher_extension(pargs.r.ret_str); break;
case 561: opt.rfc1991 = 1; break;
case 562: opt.emulate_bugs |= 1; break;
case 561: opt.rfc1991 = 1; opt.no_comment = 1; break;
case 562: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
case 563: set_cmd( &cmd, aExportSecret); break;
case 565: opt.do_not_export_rsa = 1; break;
case 566: opt.compress_sigs = 1; break;
case 554:
default : errors++; pargs.err = configfp? 1:2; break;
}
}
@ -722,7 +721,7 @@ main( int argc, char **argv )
if( opt.with_colons ) /* need this to list the trust */
rc = init_trustdb(1, trustdb_name );
break;
case aListOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
case aExportOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
default: rc = init_trustdb(1, trustdb_name ); break;
}
@ -808,19 +807,10 @@ main( int argc, char **argv )
case aSignKey: /* sign the key given as argument */
if( argc != 1 )
wrong_args(_("--sign-key username"));
/* note: fname is the user id! */
if( (rc = sign_key(fname, locusr)) )
log_error("%s: sign key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
case aEditKey: /* Edit a key signature */
if( argc != 1 )
wrong_args(_("--edit-key username"));
/* note: fname is the user id! */
if( (rc = edit_keysigs(fname)) )
log_error("%s: edit signature failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
keyedit_menu(fname, locusr );
break;
case aDeleteSecretKey:
@ -834,14 +824,6 @@ main( int argc, char **argv )
log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
case aChangePass: /* Change the passphrase */
if( argc > 1 ) /* no arg: use default, 1 arg use this one */
wrong_args(_("--change-passphrase [username]"));
/* note: fname is the user id! */
if( (rc = change_passphrase(fname)) )
log_error("%s: change passphrase failed: %s\n", print_fname_stdin(fname),
g10_errstr(rc) );
break;
#endif /* IS_G10 */
case aCheckKeys:
@ -880,11 +862,6 @@ main( int argc, char **argv )
wrong_args("--gen-key");
generate_keypair();
break;
case aKeyadd: /* add a subkey (interactive) */
if( argc != 1 )
wrong_args("--add-key userid");
generate_subkeypair(*argv);
break;
#endif
case aImport:
@ -1049,10 +1026,16 @@ main( int argc, char **argv )
list_trust_path( atoi(*argv), argv[1] );
break;
case aListOwnerTrust:
case aExportOwnerTrust:
if( argc )
wrong_args("--list-ownertrust");
list_ownertrust();
wrong_args("--export-ownertrust");
export_ownertrust();
break;
case aImportOwnerTrust:
if( argc > 1 )
wrong_args("--import-ownertrust [file]");
import_ownertrust( argc? *argv:NULL );
break;
#endif /* IS_G10MAINT */

View File

@ -851,7 +851,7 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
* We add a clone to the original keyblock, because this
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_USER_ID );
insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1;
n->flag |= 1;
++*n_sigs;

View File

@ -94,7 +94,8 @@ add_kbnode( KBNODE root, KBNODE node )
}
/****************
* Insert NODE into the list after root but before a packet with type PKTTYPE
* Insert NODE into the list after root but before a packet which is not of
* type PKTTYPE
* (only if PKTTYPE != 0)
*/
void
@ -108,7 +109,7 @@ insert_kbnode( KBNODE root, KBNODE node, int pkttype )
KBNODE n1;
for(n1=root; n1->next; n1 = n1->next)
if( pkttype == n1->next->pkt->pkttype ) {
if( pkttype != n1->next->pkt->pkttype ) {
node->next = n1->next;
n1->next = node;
return;

View File

@ -133,6 +133,8 @@ unsigned nbits_from_sk( PKT_secret_key *sk );
const char *datestr_from_pk( PKT_public_key *pk );
const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig );
const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sk( PKT_secret_key *sk );
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
@ -149,6 +151,7 @@ KBNODE find_kbnode( KBNODE node, int pkttype );
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
/*-- ringedit.c --*/
int add_keyblock_resource( const char *filename, int force, int secret );

File diff suppressed because it is too large Load Diff

View File

@ -74,8 +74,8 @@ add_key_expire( PKT_signature *sig, void *opaque )
* Add preference to the self signature packet.
* This is only called for packets with version > 3.
*/
static int
add_prefs( PKT_signature *sig, void *opaque )
int
keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{
byte buf[8];
@ -134,7 +134,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
/* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
add_prefs, sk );
keygen_add_std_prefs, sk );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
@ -444,25 +444,18 @@ ask_keysize( int algo )
else if( nbits > 2048 ) {
tty_printf(_("Keysizes larger than 2048 are not suggested because "
"computations take REALLY long!\n"));
answer = tty_get(_("Are you sure that you want this keysize? "));
tty_kill_prompt();
if( answer_is_yes(answer) ) {
m_free(answer);
if( tty_get_answer_is_yes(_(
"Are you sure that you want this keysize? ")) ) {
tty_printf(_("Okay, but keep in mind that your monitor "
"and keyboard radiation is also very vulnerable "
"to attacks!\n"));
break;
}
m_free(answer);
}
else if( nbits > 1536 ) {
answer = tty_get(_("Do you really need such a large keysize? "));
tty_kill_prompt();
if( answer_is_yes(answer) ) {
m_free(answer);
if( tty_get_answer_is_yes(_(
"Do you really need such a large keysize? ")) )
break;
}
m_free(answer);
}
else
break;
@ -524,10 +517,7 @@ ask_valid_days()
add_days_to_timestamp( make_timestamp(), valid_days )));
}
m_free(answer);
answer = tty_get(_("Is this correct (y/n)? "));
tty_kill_prompt();
if( answer_is_yes(answer) )
if( tty_get_answer_is_yes(_("Is this correct (y/n)? ")) )
break;
}
m_free(answer);
@ -549,12 +539,13 @@ has_invalid_email_chars( const char *s )
static char *
ask_user_id()
ask_user_id( int mode )
{
char *answer;
char *aname, *acomment, *amail, *uid;
tty_printf( _("\n"
if( !mode )
tty_printf( _("\n"
"You need a User-ID to identify your key; the software constructs the user id\n"
"from Real Name, Comment and Email Address in this form:\n"
" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
@ -630,28 +621,37 @@ ask_user_id()
tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid);
/* fixme: add a warning if this user-id already exists */
for(;;) {
answer = tty_get(_("Edit (N)ame, (C)omment, (E)mail or (O)kay? "));
char *ansstr = N_("NnCcEeOoQq");
answer = tty_get(_(
"Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "));
tty_kill_prompt();
if( strlen(answer) > 1 )
;
else if( *answer == 'N' || *answer == 'n' ) {
else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
m_free(aname); aname = NULL;
break;
}
else if( *answer == 'C' || *answer == 'c' ) {
else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
m_free(acomment); acomment = NULL;
break;
}
else if( *answer == 'E' || *answer == 'e' ) {
else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
m_free(amail); amail = NULL;
break;
}
else if( *answer == 'O' || *answer == 'o' ) {
else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL;
break;
}
else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL;
m_free(uid); uid = NULL;
break;
}
m_free(answer);
}
m_free(answer);
@ -685,7 +685,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
tty_printf(_(
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
"using this program with the option \"--change-passphrase\".\n\n"));
"using this program with the option \"--edit-key\".\n\n"));
break;
}
else
@ -728,6 +728,27 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
}
/****************
* Generate a new user id packet, or return NULL if cancelled
*/
PKT_user_id *
generate_user_id()
{
PKT_user_id *uid;
char *p;
size_t n;
p = ask_user_id( 1 );
if( !p )
return NULL;
n = strlen(p);
uid = m_alloc( sizeof *uid + n - 1 );
uid->len = n;
strcpy(uid->name, p);
return uid;
}
/****************
* Generate a keypair
*/
@ -762,7 +783,11 @@ generate_keypair()
}
nbits = ask_keysize( algo );
ndays = ask_valid_days();
uid = ask_user_id();
uid = ask_user_id(0);
if( !uid ) {
log_error(_("Key generation cancelled.\n"));
return;
}
dek = ask_passphrase( &s2k );
@ -879,88 +904,29 @@ generate_keypair()
/****************
* add a new subkey to an existing key.
* Returns true if a new key has been generated and put into the keyblocks.
*/
void
generate_subkeypair( const char *username )
int
generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
{
int rc=0;
KBPOS pub_kbpos, sec_kbpos;
KBNODE pub_keyblock = NULL;
KBNODE sec_keyblock = NULL;
int okay=0, rc=0;
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
u32 keyid[2];
int v4, algo, ndays;
unsigned nbits;
char *passphrase = NULL;
DEK *dek = NULL;
STRING2KEY *s2k = NULL;
if( opt.batch || opt.answer_yes || opt.answer_no ) {
log_error(_("Key generation can only be used in interactive mode\n"));
return;
}
/* search the userid */
rc = find_secret_keyblock_byname( &sec_kbpos, username );
if( rc ) {
log_error("user '%s' not found\n", username );
goto leave;
}
rc = read_keyblock( &sec_kbpos, &sec_keyblock );
if( rc ) {
log_error("error reading the secret key: %s\n", g10_errstr(rc) );
goto leave;
}
/* and the public key */
rc = find_keyblock_byname( &pub_kbpos, username );
if( rc ) {
log_error("user '%s' not found in public ring\n", username );
goto leave;
}
rc = read_keyblock( &pub_kbpos, &pub_keyblock );
if( rc ) {
log_error("error reading the public key: %s\n", g10_errstr(rc) );
goto leave;
}
/* break out the primary key */
/* break out the primary secret key */
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
if( !node ) {
log_error("Oops; secret key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave;
}
/* make a copy of the sk to keep the protected one in the keyblock */
sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
keyid_from_sk( sk, keyid );
/* display primary and all secondary keys */
tty_printf("sec %4u%c/%08lX %s ",
nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
keyid[1], datestr_from_sk(sk) );
{
size_t n;
char *p = get_user_id( keyid, &n );
tty_print_string( p, n );
m_free(p);
tty_printf("\n");
}
for(node=sec_keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
PKT_secret_key *subsk = node->pkt->pkt.secret_key;
keyid_from_sk( subsk, keyid );
tty_printf("sub %4u%c/%08lX %s\n",
nbits_from_sk( subsk ),
pubkey_letter( subsk->pubkey_algo ),
keyid[1], datestr_from_sk(subsk) );
}
}
tty_printf("\n");
/* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) {
case -1:
@ -984,6 +950,8 @@ generate_subkeypair( const char *username )
assert(algo);
nbits = ask_keysize( algo );
ndays = ask_valid_days();
if( !tty_get_answer_is_yes( _("Really create? ") ) )
goto leave;
if( passphrase ) {
s2k = m_alloc_secure( sizeof *s2k );
@ -999,31 +967,18 @@ generate_subkeypair( const char *username )
rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
if( !rc )
rc = write_keybinding(sec_keyblock, pub_keyblock, sk);
/* write back */
if( !rc ) {
rc = update_keyblock( &pub_kbpos, pub_keyblock );
if( rc )
log_error("update_public_keyblock failed\n" );
}
if( !rc ) {
rc = update_keyblock( &sec_kbpos, sec_keyblock );
if( rc )
log_error("update_secret_keyblock failed\n" );
}
if( !rc )
tty_printf(_("public and secret subkey created.\n") );
okay = 1;
leave:
if( rc )
tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
m_free( passphrase );
m_free( dek );
m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk);
release_kbnode( sec_keyblock );
release_kbnode( pub_keyblock );
set_next_passphrase( NULL );
return okay;
}

View File

@ -296,6 +296,37 @@ datestr_from_sig( PKT_signature *sig )
}
const char *
expirestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
struct tm *tp;
time_t atime;
if( !pk->valid_days )
return "never ";
atime = add_days_to_timestamp( pk->timestamp, pk->valid_days );
tp = gmtime( &atime );
sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
return buffer;
}
const char *
expirestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
struct tm *tp;
time_t atime;
if( !sk->valid_days )
return "never ";
atime = add_days_to_timestamp( sk->timestamp, sk->valid_days );
tp = gmtime( &atime );
sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
return buffer;
}
/**************** .
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free

View File

@ -202,6 +202,8 @@ list_one( const char *name, int secret )
any = 1;
}
keyid_from_pk( pk2, keyid2 );
if( opt.with_colons ) {
printf("sub:%c:%u:%d:%08lX%08lX:%s:%u:",
@ -224,6 +226,8 @@ list_one( const char *name, int secret )
pubkey_letter( pk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_pk( pk2 ) );
if( opt.fingerprint > 1 )
fingerprint( pk2, NULL );
}
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
u32 keyid2[2];
@ -251,6 +255,9 @@ list_one( const char *name, int secret )
pubkey_letter( sk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_sk( sk2 ) );
if( opt.fingerprint > 1 )
fingerprint( NULL, sk2 );
}
else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;

View File

@ -72,14 +72,13 @@ int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
/*-- keyedit.c --*/
int sign_key( const char *username, STRLIST locusr );
int edit_keysigs( const char *username );
int delete_key( const char *username, int secure );
int change_passphrase( const char *username );
void keyedit_menu( const char *username, STRLIST locusr );
/*-- keygen.c --*/
void generate_keypair(void);
void generate_subkeypair(const char *userid);
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
/*-- openfile.c --*/
int overwrite_filep( const char *fname );

View File

@ -520,6 +520,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( pk, NULL );
}
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@ -583,6 +585,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( NULL, sk );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;

View File

@ -98,7 +98,7 @@ checksum_u16( unsigned n )
u16 a;
a = (n >> 8) & 0xff;
if( opt.emulate_bugs & 1 ) {
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
a |= n & 0xff;
log_debug("csum_u16 emulated for n=%u\n", n);
}
@ -142,7 +142,7 @@ checksum_mpi( MPI a )
* this stored value if it is still available.
*/
if( opt.emulate_bugs & 1 )
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM )
nbits = 0;
else
nbits = mpi_get_nbit_info(a);

View File

@ -50,10 +50,12 @@ struct {
int compress_sigs;
int always_trust;
int rfc1991;
unsigned emulate_bugs; /* bug emulation flags */
unsigned emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
} opt;
#define EMUBUG_GPGCHKSUM 1
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */

View File

@ -258,7 +258,9 @@ void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
int cmp_public_keys( PKT_public_key *d, PKT_public_key *s );
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
@ -298,4 +300,7 @@ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id(void);
#endif /*G10_PACKET_H*/

View File

@ -349,7 +349,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
}
leave:
if( rc == -1 && iobuf_error(inp) )
if( !rc && iobuf_error(inp) )
rc = G10ERR_INV_KEYRING;
return rc;
}
@ -434,7 +434,8 @@ skip_rest( IOBUF inp, unsigned long pktlen )
}
else {
for( ; pktlen; pktlen-- )
iobuf_get(inp);
if( iobuf_get(inp) == -1 )
break;
}
}
@ -1048,6 +1049,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
rc = G10ERR_INVALID_PACKET;
goto leave;
}
/* fixme: Add support for other blocksizes */
for(i=0; i < 8 && pktlen; i++, pktlen-- )
temp[i] = iobuf_get_noeof(inp);
if( list_mode ) {

View File

@ -53,6 +53,8 @@ do_check( PKT_secret_key *sk )
BUG();
if( check_cipher_algo( sk->protect.algo ) )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
if( cipher_get_blocksize( sk->protect.algo ) != 8 )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
keyid_from_sk( sk, keyid );
dek = passphrase_to_dek( keyid, sk->protect.algo,
&sk->protect.s2k, 0 );
@ -76,7 +78,7 @@ do_check( PKT_secret_key *sk )
csum += checksum_mpi( sk->skey[i] );
m_free( buffer );
}
if( opt.emulate_bugs & 1 ) {
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
csum = sk->csum;
}
cipher_close( cipher_hd );
@ -180,6 +182,8 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
if( check_cipher_algo( sk->protect.algo ) )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else if( cipher_get_blocksize( sk->protect.algo ) != 8 )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else {
cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1 );

View File

@ -650,4 +650,112 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
}
/****************
* Create a signature packet for the given public key certificate
* and the user id and return it in ret_sig. User signature class SIGCLASS
* user-id is not used (and may be NULL if sigclass is 0x20)
* If digest_algo is 0 the function selects an appropriate one.
*/
int
make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_secret_key *sk,
int sigclass, int digest_algo,
int (*mksubpkt)(PKT_signature *, void *), void *opaque
)
{
PKT_signature *sig;
int rc=0;
MD_HANDLE md;
assert( (sigclass >= 0x10 && sigclass <= 0x13)
|| sigclass == 0x20 || sigclass == 0x18 );
if( !digest_algo ) {
switch( sk->pubkey_algo ) {
case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break;
case PUBKEY_ALGO_RSA_S:
case PUBKEY_ALGO_RSA: digest_algo = DIGEST_ALGO_MD5; break;
default: digest_algo = DIGEST_ALGO_RMD160; break;
}
}
md = md_open( digest_algo, 0 );
/* hash the public key certificate and the user id */
hash_public_key( md, pk );
if( sigclass == 0x18 ) { /* subkey binding */
hash_public_key( md, subpk );
}
else if( sigclass != 0x20 ) {
if( sk->version >=4 ) {
byte buf[5];
buf[0] = 0xb4; /* indicates a userid packet */
buf[1] = uid->len >> 24; /* always use 4 length bytes */
buf[2] = uid->len >> 16;
buf[3] = uid->len >> 8;
buf[4] = uid->len;
md_write( md, buf, 5 );
}
md_write( md, uid->name, uid->len );
}
/* and make the signature packet */
sig = m_alloc_clear( sizeof *sig );
sig->version = sk->version;
keyid_from_sk( sk, sig->keyid );
sig->pubkey_algo = sk->pubkey_algo;
sig->digest_algo = digest_algo;
sig->timestamp = make_timestamp();
sig->sig_class = sigclass;
if( sig->version >= 4 )
build_sig_subpkt_from_sig( sig );
if( sig->version >= 4 && mksubpkt )
rc = (*mksubpkt)( sig, opaque );
if( !rc ) {
if( sig->version >= 4 )
md_putc( md, sig->version );
md_putc( md, sig->sig_class );
if( sig->version < 4 ) {
u32 a = sig->timestamp;
md_putc( md, (a >> 24) & 0xff );
md_putc( md, (a >> 16) & 0xff );
md_putc( md, (a >> 8) & 0xff );
md_putc( md, a & 0xff );
}
else {
byte buf[6];
size_t n;
md_putc( md, sig->pubkey_algo );
md_putc( md, sig->digest_algo );
if( sig->hashed_data ) {
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
md_write( md, sig->hashed_data, n+2 );
n += 6;
}
else
n = 6;
/* add some magic */
buf[0] = sig->version;
buf[1] = 0xff;
buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
buf[3] = n >> 16;
buf[4] = n >> 8;
buf[5] = n;
md_write( md, buf, 6 );
}
md_final(md);
rc = complete_sig( sig, sk, md );
}
md_close( md );
if( rc )
free_seckey_enc( sig );
else
*ret_sig = sig;
return rc;
}

View File

@ -45,46 +45,8 @@ static char *db_name;
static int db_fd = -1;
static void create_db( const char *fname );
static void open_db(void);
/**************************************************
************** read and write helpers ************
**************************************************/
static void
fwrite_8(FILE *fp, byte a)
{
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
}
static void
fwrite_32( FILE*fp, ulong a)
{
putc( (a>>24) & 0xff, fp );
putc( (a>>16) & 0xff, fp );
putc( (a>> 8) & 0xff, fp );
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
}
static void
fwrite_zeros( FILE *fp, size_t n)
{
while( n-- )
if( putc( 0, fp ) == EOF )
log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
}
/**************************************************
************** read and write stuff **************
**************************************************/
int
tdbio_set_dbname( const char *new_dbname, int create )
@ -101,7 +63,11 @@ tdbio_set_dbname( const char *new_dbname, int create )
return G10ERR_TRUSTDB;
}
if( create ) {
FILE *fp;
TRUSTREC rec;
int rc;
char *p = strrchr( fname, '/' );
assert(p);
*p = 0;
if( access( fname, F_OK ) ) {
@ -119,7 +85,30 @@ tdbio_set_dbname( const char *new_dbname, int create )
log_fatal_f(fname, _("directory does not exist!\n") );
}
*p = '/';
create_db( fname );
fp =fopen( fname, "w" );
if( !fp )
log_fatal_f( fname, _("can't create: %s\n"), strerror(errno) );
fclose(fp);
m_free(db_name);
db_name = fname;
db_fd = open( db_name, O_RDWR );
if( db_fd == -1 )
log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) );
memset( &rec, 0, sizeof rec );
rec.r.ver.version = 2;
rec.r.ver.created = make_timestamp();
rec.rectype = RECTYPE_VER;
rec.recnum = 0;
rc = tdbio_write_record( &rec );
if( rc )
log_fatal_f( fname, _("failed to create version record: %s"),
g10_errstr(rc));
/* and read again to check that we are okay */
if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
log_fatal_f( db_name, "invalid trust-db created\n" );
return 0;
}
}
m_free(db_name);
@ -136,37 +125,6 @@ tdbio_get_dbname()
/****************
* Create a new trustdb
*/
static void
create_db( const char *fname )
{
FILE *fp;
fp =fopen( fname, "w" );
if( !fp )
log_fatal_f( fname, _("can't create %s: %s\n"), strerror(errno) );
fwrite_8( fp, 1 ); /* record type */
fwrite_8( fp, 'g' );
fwrite_8( fp, 'p' );
fwrite_8( fp, 'g' );
fwrite_8( fp, 2 ); /* version */
fwrite_zeros( fp, 3 ); /* reserved */
fwrite_32( fp, 0 ); /* not locked */
fwrite_32( fp, make_timestamp() ); /* created */
fwrite_32( fp, 0 ); /* not yet modified */
fwrite_32( fp, 0 ); /* not yet validated*/
fwrite_32( fp, 0 ); /* reserved */
fwrite_8( fp, 3 ); /* marginals needed */
fwrite_8( fp, 1 ); /* completes needed */
fwrite_8( fp, 4 ); /* max_cet_depth */
fwrite_zeros( fp, 9 ); /* filler */
fclose(fp);
}
static void
open_db()
{
@ -182,10 +140,221 @@ open_db()
}
/****************
* Return the record number of the keyhash tbl or create a new one.
*/
static ulong
get_keyhashrec()
{
static ulong keyhashtbl; /* record number of the key hashtable */
TRUSTREC vr;
int rc;
if( keyhashtbl )
return keyhashtbl;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal_f( db_name, _("error reading version record: %s\n"),
g10_errstr(rc) );
if( vr.r.ver.keyhashtbl )
keyhashtbl = vr.r.ver.keyhashtbl;
else {
TRUSTREC rec;
off_t offset;
ulong recnum;
int i, n;
offset = lseek( db_fd, 0, SEEK_END );
if( offset == -1 )
log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
recnum = offset / TRUST_RECORD_LEN;
assert(recnum); /* this is will never be the first record */
keyhashtbl = recnum;
/* Now write the records */
n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
for(i=0; i < n; i++, recnum++ ) {
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HTBL; /* free record */
rec.recnum = recnum;
rc = tdbio_write_record( &rec );
if( rc )
log_fatal_f(db_name,_("failed to create hashtable: %s\n"),
g10_errstr(rc));
}
/* update the version record */
vr.r.ver.keyhashtbl = keyhashtbl;
rc = tdbio_write_record( &vr );
if( rc )
log_fatal_f( db_name, _("error updating version record: %s\n"),
g10_errstr(rc));
}
return keyhashtbl;
}
/****************
* Update the key hashtbl or create the table if it does not exist
*/
static int
update_keyhashtbl( TRUSTREC *kr )
{
TRUSTREC lastrec, rec;
ulong hashrec, item;
int msb;
int level=0;
int rc, i;
hashrec = get_keyhashrec();
next_level:
msb = kr->r.key.fingerprint[level];
hashrec += msb / ITEMS_PER_HTBL_RECORD;
rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "update_keyhashtbl read failed: %s\n",
g10_errstr(rc) );
return rc;
}
item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
if( !item ) { /* insert new one */
rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = kr->recnum;
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name, "update_keyhashtbl write htbl failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else if( item != kr->recnum ) { /* must do an update */
lastrec = rec;
rc = tdbio_read_record( item, &rec, 0 );
if( rc ) {
log_error( db_name, "update_keyhashtbl read item failed: %s\n",
g10_errstr(rc) );
return rc;
}
if( rec.rectype == RECTYPE_HTBL ) {
hashrec = item;
level++;
if( level >= kr->r.key.fingerprint_len ) {
log_error( db_name, "keyhashtbl has invalid indirections\n");
return G10ERR_TRUSTDB;
}
goto next_level;
}
else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
/* see whether the key is already in this list */
for(;;) {
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( rec.r.hlst.rnum[i] == kr->recnum ) {
log_debug("HTBL: no update needed for keyrec %lu\n",
kr->recnum );
return 0;
}
}
if( rec.r.hlst.next ) {
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
log_error( db_name,
"scan keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else
break; /* not there */
}
/* find the next free entry and put it in */
for(;;) {
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( !rec.r.hlst.rnum[i] ) {
rec.r.hlst.rnum[i] = kr->recnum;
rc = tdbio_write_record( &rec );
if( rc )
log_error( db_name,
"update_keyhashtbl write hlst failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
}
if( rec.r.hlst.next ) {
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST );
if( rc ) {
log_error( db_name,
"update_keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else { /* add a new list record */
rec.r.hlst.next = item = tdbio_new_recnum();
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name,
"update_keyhashtbl write hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HLST;
rec.recnum = item;
rec.r.hlst.rnum[0] = kr->recnum;
if( rc )
log_error( db_name,
"update_keyhashtbl write ext hlst failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
}
}
else if( rec.rectype == RECTYPE_KEY ) { /* insert a list record */
if( rec.recnum == kr->recnum ) {
log_debug("HTBL: no update needed for keyrec %lu\n",
kr->recnum );
return 0;
}
item = rec.recnum; /* save number of key record */
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HLST;
rec.recnum = tdbio_new_recnum();
rec.r.hlst.rnum[0] = item; /* old keyrecord */
rec.r.hlst.rnum[1] = kr->recnum; /* and new one */
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name,
"update_keyhashtbl write new hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
/* update the hashtable record */
lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
rc = tdbio_write_record( &lastrec );
if( rc )
log_error( db_name,
"update_keyhashtbl update htbl failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
else {
log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
item);
return G10ERR_TRUSTDB;
}
}
return 0;
}
void
tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{
int i, any;
int i;
ulong rnum = rec->recnum;
fprintf(fp, "rec %5lu, ", rnum );
@ -193,7 +362,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
switch( rec->rectype ) {
case 0: fprintf(fp, "free\n");
break;
case RECTYPE_VER: fprintf(fp, "version\n");
case RECTYPE_VER: fprintf(fp, "version, keyhashtbl=%lu\n",
rec->r.ver.keyhashtbl );
break;
case RECTYPE_DIR:
fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x",
@ -213,11 +383,12 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
putc('\n', fp);
break;
case RECTYPE_KEY:
fprintf(fp, "key %lu, next=%lu, algo=%d, flen=%d",
fprintf(fp, "key %lu, next=%lu, algo=%d, ",
rec->r.key.lid,
rec->r.key.next,
rec->r.key.pubkey_algo,
rec->r.key.fingerprint_len );
rec->r.key.pubkey_algo );
for(i=0; i < rec->r.key.fingerprint_len; i++ )
fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
if( rec->r.key.keyflags & KEYF_REVOKED )
fputs(", revoked", fp );
putc('\n', fp);
@ -239,29 +410,29 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
rec->r.uid.next);
break;
case RECTYPE_SIG:
fprintf(fp, "sig %lu, next=%lu\n",
fprintf(fp, "sig %lu, next=%lu,",
rec->r.sig.lid, rec->r.sig.next );
for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sig.sig[i].lid ) {
if( !any ) {
putc('\t', fp);
any++;
}
fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
for(i=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sig.sig[i].lid )
fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
rec->r.sig.sig[i].flag );
}
}
if( any )
putc('\n', fp);
putc('\n', fp);
break;
case RECTYPE_CACH:
fprintf(fp, "cach\n");
break;
case RECTYPE_HTBL:
fprintf(fp, "htbl\n");
fprintf(fp, "htbl,");
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
fprintf(fp, " %lu", rec->r.htbl.item[i] );
putc('\n', fp);
break;
case RECTYPE_HLST:
fprintf(fp, "hlst\n");
fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
putc('\n', fp);
break;
default:
fprintf(fp, "unknown type %d\n", rec->rectype );
@ -302,30 +473,29 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
recnum, expected, rec->rectype );
return G10ERR_TRUSTDB;
}
p++;
p++; /* skip reserved byte */
switch( rec->rectype ) {
case 0: /* unused record */
case 0: /* unused (free) record */
break;
case RECTYPE_VER: /* version record */
if( memcmp(buf+1, "gpg", 3 ) ) {
log_error_f( db_name, _("not a trustdb file\n") );
rc = G10ERR_TRUSTDB;
}
p += 2; /* skip magic */
p += 2; /* skip "pgp" */
rec->r.ver.version = *p++;
rec->r.ver.locked = buftoulong(p); p += 4;
p += 3; /* reserved bytes */
p += 4; /* lock flags */
rec->r.ver.created = buftoulong(p); p += 4;
rec->r.ver.modified = buftoulong(p); p += 4;
rec->r.ver.validated= buftoulong(p); p += 4;
rec->r.ver.marginals_needed = *p++;
rec->r.ver.completes_needed = *p++;
rec->r.ver.max_cert_depth = *p++;
rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
if( recnum ) {
log_error_f( db_name, "version record with recnum %lu\n",
(ulong)recnum );
rc = G10ERR_TRUSTDB;
}
if( rec->r.ver.version != 2 ) {
else if( rec->r.ver.version != 2 ) {
log_error_f( db_name, "invalid file version %d\n",
rec->r.ver.version );
rc = G10ERR_TRUSTDB;
@ -381,6 +551,17 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
memcpy(rec->r.cache.blockhash, p, 20); p += 20;
rec->r.cache.trustlevel = *p++;
break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
rec->r.htbl.item[i] = buftoulong(p); p += 4;
}
break;
case RECTYPE_HLST:
rec->r.hlst.next = buftoulong(p); p += 4;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
}
break;
default:
log_error_f( db_name, "invalid record type %d at recnum %lu\n",
rec->rectype, (ulong)recnum );
@ -412,8 +593,16 @@ tdbio_write_record( TRUSTREC *rec )
switch( rec->rectype ) {
case 0: /* unused record */
break;
case 1: /* version record */
BUG();
case RECTYPE_VER: /* version record */
if( recnum )
BUG();
memcpy(p-1, "gpg", 3 ); p += 2;
*p++ = rec->r.ver.version;
p += 7; /* skip reserved bytes and lock flags */
ulongtobuf(p, rec->r.ver.created); p += 4;
ulongtobuf(p, rec->r.ver.modified); p += 4;
ulongtobuf(p, rec->r.ver.validated); p += 4;
ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
break;
case RECTYPE_DIR: /*directory record */
@ -466,6 +655,19 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.cache.trustlevel;
break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
}
break;
case RECTYPE_HLST:
ulongtobuf( p, rec->r.hlst.next); p += 4;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
}
break;
default:
BUG();
}
@ -479,6 +681,8 @@ tdbio_write_record( TRUSTREC *rec )
log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
return G10ERR_WRITE_FILE;
}
else if( rec->rectype == RECTYPE_KEY )
rc = update_keyhashtbl( rec );
return rc;
}
@ -528,9 +732,6 @@ tdbio_new_recnum()
/****************
* Search the trustdb for a key which matches PK and return the dir record
* The local_id of PK is set to the correct value
*
* Note: To increase performance, we could use a index search here.
* tdbio_write_record shoudl create this index automagically
*/
int
tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
@ -540,32 +741,111 @@ tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
byte *fingerprint;
size_t fingerlen;
int rc;
ulong hashrec, item;
int msb;
int level=0;
keyid_from_pk( pk, keyid );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
assert( fingerlen == 20 || fingerlen == 16 );
for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) {
if( rec->rectype != RECTYPE_KEY )
continue;
if( rec->r.key.pubkey_algo == pk->pubkey_algo
&& !memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) ) {
/* found: read the dir record for this key */
recnum = rec->r.key.lid;
rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
if( rc )
break;
if( pk->local_id && pk->local_id != recnum )
log_error_f(db_name,
"found record, but LID from memory does "
"not match recnum (%lu,%lu)\n",
pk->local_id, recnum );
pk->local_id = recnum;
return 0;
}
/* locate the key using the hash table */
hashrec = get_keyhashrec();
next_level:
msb = fingerprint[level];
hashrec += msb / ITEMS_PER_HTBL_RECORD;
rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "scan keyhashtbl failed: %s\n", g10_errstr(rc) );
return rc;
}
if( rc != -1 )
log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(rc) );
item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
if( !item )
return -1; /* not found */
rc = tdbio_read_record( item, rec, 0 );
if( rc ) {
log_error( db_name, "keyhashtbl read failed: %s\n", g10_errstr(rc) );
return rc;
}
if( rec->rectype == RECTYPE_HTBL ) {
hashrec = item;
level++;
if( level >= fingerlen ) {
log_error( db_name, "keyhashtbl has invalid indirections\n");
return G10ERR_TRUSTDB;
}
goto next_level;
}
else if( rec->rectype == RECTYPE_HLST ) {
for(;;) {
int i;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( rec->r.hlst.rnum[i] ) {
TRUSTREC tmp;
rc = tdbio_read_record( rec->r.hlst.rnum[i],
&tmp, RECTYPE_KEY );
if( rc ) {
log_error( db_name,
"scan keyhashtbl read key failed: %s\n",
g10_errstr(rc) );
return rc;
}
if( tmp.r.key.pubkey_algo == pk->pubkey_algo
&& tmp.r.key.fingerprint_len == fingerlen
&& !memcmp(tmp.r.key.fingerprint,
fingerprint, fingerlen) ) {
*rec = tmp;
goto found;
}
}
}
if( rec->r.hlst.next ) {
rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
if( rc ) {
log_error( db_name,
"scan keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else
return -1; /* not found */
}
found:
;
}
else if( rec->rectype == RECTYPE_KEY ) {
/* must check that it is the requested key */
if( rec->r.key.pubkey_algo != pk->pubkey_algo
|| rec->r.key.fingerprint_len != fingerlen
|| memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) )
return -1; /* no: not found */
}
else {
log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
item);
return G10ERR_TRUSTDB;
}
recnum = rec->r.key.lid;
if( pk->local_id && pk->local_id != recnum )
log_error_f(db_name,
"found record, but LID from memory does "
"not match recnum (%lu,%lu)\n",
pk->local_id, recnum );
pk->local_id = recnum;
/* Now read the dir record */
rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
if( rc )
log_error_f(db_name, "can't read dirrec %lu: %s\n",
recnum, g10_errstr(rc) );
return rc;
}

View File

@ -60,15 +60,12 @@ struct trust_record {
int mark;
ulong recnum;
union {
struct { /* version record: */
byte version; /* should be 1 */
ulong locked; /* pid of process which holds a lock */
struct { /* version record: */
byte version; /* should be 2 */
ulong created; /* timestamp of trustdb creation */
ulong modified; /* timestamp of last modification */
ulong validated; /* timestamp of last validation */
byte marginals_needed;
byte completes_needed;
byte max_cert_depth;
ulong keyhashtbl;
} ver;
struct { /* directory record */
ulong lid;
@ -117,10 +114,7 @@ struct trust_record {
} htbl;
struct {
ulong next;
struct {
byte hash;
ulong rnum;
} item[ITEMS_PER_HLST_RECORD];
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of a key record */
} hlst;
} r;
};

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -102,6 +103,9 @@ static ulong last_trust_web_key;
static TRUST_SEG_LIST last_trust_web_tslist;
#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
(a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
/**********************************************
************* list helpers *******************
**********************************************/
@ -945,6 +949,7 @@ update_sigs( TRUSTREC *dir )
}
else {
/* fixme: handle other sig classes here */
/* FIXME: Revocations!!! */
}
}
}
@ -1243,7 +1248,16 @@ list_trustdb( const char *username )
{
TRUSTREC rec;
if( username ) {
if( username && *username == '#' ) {
int rc;
ulong lid = atoi(username+1);
if( (rc = list_records( lid)) )
log_error("user '%s' read problem: %s\n", username, g10_errstr(rc));
else if( (rc = list_sigs( lid )) )
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
}
else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
@ -1274,10 +1288,10 @@ list_trustdb( const char *username )
}
/****************
* make a list of all defined owner trust value.
* Print a list of all defined owner trust value.
*/
void
list_ownertrust()
export_ownertrust()
{
TRUSTREC rec;
TRUSTREC rec2;
@ -1307,6 +1321,67 @@ list_ownertrust()
}
}
void
import_ownertrust( const char *fname )
{
FILE *fp;
int is_stdin=0;
char line[256];
char *p;
size_t n, fprlen;
unsigned otrust;
if( !fname || (*fname == '-' && !fname[1]) ) {
fp = stdin;
fname = "[stdin]";
is_stdin = 1;
}
else if( !(fp = fopen( fname, "r" )) ) {
log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
return;
}
while( fgets( line, DIM(line)-1, fp ) ) {
if( !*line || *line == '#' )
continue;
n = strlen(line);
if( line[n-1] != '\n' ) {
log_error_f(fname, "line to long\n" );
break; /* can't continue */
}
for(p = line; *p && *p != ':' ; p++ )
if( !isxdigit(*p) )
break;
if( *p != ':' ) {
log_error_f(fname, "error: missing colon\n" );
continue;
}
fprlen = p - line;
if( fprlen != 32 && fprlen != 40 ) {
log_error_f(fname, "error: invalid fingerprint\n" );
continue;
}
if( sscanf(p, ":%u:", &otrust ) != 1 ) {
log_error_f(fname, "error: no otrust value\n" );
continue;
}
if( !otrust )
continue; /* no otrust defined - no need to update or insert */
/* convert the ascii fingerprint to binary */
for(p=line, fprlen=0; *p != ':'; p += 2 )
line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
line[fprlen] = 0;
log_hexdump("found: ", line, fprlen );
}
if( ferror(fp) )
log_error_f(fname, _("read error: %s\n"), strerror(errno) );
if( !is_stdin )
fclose(fp);
}
void
list_trust_path( int max_depth, const char *username )
{
@ -1405,7 +1480,17 @@ check_trustdb( const char *username )
TRUSTREC rec;
int rc;
if( username ) {
if( username && *username == '#' ) {
int rc;
ulong lid = atoi(username+1);
if( (rc = update_sigs_by_lid( lid )) )
log_error("lid %lu: check failed: %s\n",
lid, g10_errstr(rc));
else
log_info("lid %lu: checked: %s\n", lid, g10_errstr(rc));
}
else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( (rc = get_pubkey_byname( pk, username )) )
@ -1724,7 +1809,7 @@ insert_trust_record( PKT_public_key *orig_pk )
BUG(); /* more than one primary key */
keyid_from_pk( pk, keyid );
}
fingerprint = fingerprint_from_pk( orig_pk, NULL, &fingerlen );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
rec = m_alloc_clear( sizeof *rec );
rec->rectype = RECTYPE_KEY;
rec->r.key.pubkey_algo = pk->pubkey_algo;

View File

@ -38,7 +38,8 @@
/*-- trustdb.c --*/
void list_trustdb(const char *username);
void list_trust_path( int max_depth, const char *username );
void list_ownertrust(void);
void export_ownertrust(void);
void import_ownertrust(const char *fname);
void check_trustdb( const char *username );
int init_trustdb( int level, const char *dbname );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel );

View File

@ -35,6 +35,7 @@
#define CIPHER_ALGO_DES_SK 6
#define CIPHER_ALGO_BLOWFISH160 42 /* blowfish 160 bit key (not in OpenPGP)*/
#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */
#define CIPHER_ALGO_TWOFISH 102 /* experimental: twofish 128 bit */
#define CIPHER_ALGO_DUMMY 110 /* no encryption at all */
#define PUBKEY_ALGO_RSA 1
@ -130,6 +131,7 @@ int string_to_cipher_algo( const char *string );
const char * cipher_algo_to_string( int algo );
int check_cipher_algo( int algo );
unsigned cipher_get_keylen( int algo );
unsigned cipher_get_blocksize( int algo );
CIPHER_HANDLE cipher_open( int algo, int mode, int secure );
void cipher_close( CIPHER_HANDLE c );
void cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen );

View File

@ -25,6 +25,7 @@ void tty_print_string( byte *p, size_t n );
char *tty_get( const char *prompt );
char *tty_get_hidden( const char *prompt );
void tty_kill_prompt(void);
int tty_get_answer_is_yes( const char *prompt );
#endif /*G10_TTYIO_H*/

View File

@ -49,7 +49,7 @@ g10m_release( MPI a )
void
g10m_resize( MPI a, unsigned nbits )
{
return mpi_resize( a, (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
mpi_resize( a, (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
}
MPI g10m_copy( MPI a ) { return mpi_copy( a ); }

View File

@ -120,6 +120,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t2, t2, 1);
mpi_rshift(t3, t3, 1);
Y4:
;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) {
@ -216,6 +217,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t3, t3, 1);
}
Y4:
;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) {

View File

@ -400,11 +400,6 @@ msgstr "--clearsign [Dateiname]"
msgid "--decrypt [filename]"
msgstr "--decrypt [Dateiname]"
#. sign the key given as argument
#: g10/g10.c:802
msgid "--sign-key username"
msgstr "--sign-key Benutzername"
#: g10/g10.c:810
msgid "--edit-key username"
msgstr "--edit-key Benutzername"
@ -417,12 +412,6 @@ msgstr "--delete-secret-key Benutzername"
msgid "--delete-key username"
msgstr "--delete-key Benutzername"
#. Change the passphrase
#. no arg: use default, 1 arg use this one
#: g10/g10.c:829
msgid "--change-passphrase [username]"
msgstr "--change-passphrase [Benutzername]"
#. prepare iobufs
#: g10/encode.c:200 g10/g10.c:853 g10/keylist.c:79
msgid "can't open %s: %s\n"
@ -810,12 +799,12 @@ msgstr "\"passphrase\" nicht richtig wiederholt; noch einmal.\n"
msgid ""
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
"using this program with the option \"--change-passphrase\".\n"
"using this program with the option \"--edit-key\".\n"
"\n"
msgstr ""
"Sie m\366chten keine \"passphrase\" - Dies ist eine *schlechte* Idee!\n"
"Es ist trotzdem m\366glich. Sie k\366nnen Ihre \"phassphrase\" jederzeit\n"
"\344ndern, indem sie dieses Programm mit dem Kommando \"--change-passphrase\"\n"
"\344ndern, indem sie dieses Programm mit dem Kommando \"--edit-key\"\n"
"aufrufen.\n"
"\n"

View File

@ -1,3 +1,7 @@
Wed Jul 29 14:53:34 1998 Werner Koch (wk@(none))
* ttyio.c (tty_get_answer_is_yes): New.
Tue Jul 21 10:35:48 1998 Werner Koch (wk@(none))
* argparse.c: New option flag to distinguish options and commands.

View File

@ -91,3 +91,4 @@ answer_is_yes( const char *s )
return 0;
}

View File

@ -204,7 +204,7 @@ secmem_malloc( size_t size )
}
/* allocate a new block */
if( (poollen + size <= poolsize) ) {
mb = pool + poollen;
mb = (void*)((char*)pool + poollen);
poollen += size;
mb->size = size;
}
@ -240,7 +240,7 @@ secmem_realloc( void *p, size_t newsize )
return p; /* it is easier not to shrink the memory */
a = secmem_malloc( newsize );
memcpy(a, p, size);
memset(a+size, 0, newsize-size);
memset((char*)a+size, 0, newsize-size);
secmem_free(p);
return a;
}
@ -271,7 +271,7 @@ secmem_free( void *a )
int
m_is_secure( const void *p )
{
return p >= pool && p < (pool+poolsize);
return p >= pool && p < ((char*)pool+poolsize);
}
void

View File

@ -328,3 +328,15 @@ tty_kill_prompt()
last_prompt_len = 0;
}
int
tty_get_answer_is_yes( const char *prompt )
{
int yes;
char *p = tty_get( prompt );
tty_kill_prompt();
yes = answer_is_yes(p);
m_free(p);
return yes;
}