mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
added some stuff for signing keys
This commit is contained in:
parent
68ea0f4353
commit
15426c6d96
26
INSTALL
26
INSTALL
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
1) Configure for your machine:
|
||||||
|
|
||||||
|
./configure
|
||||||
|
|
||||||
|
or use
|
||||||
|
|
||||||
|
./configure --enable-m-debug
|
||||||
|
|
||||||
|
to ebanle the integrated malloc debugging stuff.
|
||||||
|
|
||||||
|
|
||||||
|
2) Run make:
|
||||||
|
|
||||||
|
make
|
||||||
|
|
||||||
|
|
||||||
|
3) Install
|
||||||
|
|
||||||
|
make install
|
||||||
|
|
||||||
|
|
||||||
|
4) You end up with a binary "g10" in /usr/local/bin
|
||||||
|
|
||||||
|
|
||||||
|
|
50
README
50
README
@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
G10 - The GNU Enryption and Signing Tool
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
THIS IS VERSION IS ONLY a TEST VERSION ! YOU SHOULD NOT
|
||||||
|
USE IT FOR OTHER PURPOSES THAN EVALUATING THE CURRENT CODE.
|
||||||
|
|
||||||
|
* The data format may change in the next version!
|
||||||
|
|
||||||
|
* The code to generate keys is not secure!
|
||||||
|
|
||||||
|
* Some features are not implemented
|
||||||
|
|
||||||
|
|
||||||
|
I provide this version as a reality check to start discussion.
|
||||||
|
Please subscribe to g10@net.lut.ac.uk be sending a mail with
|
||||||
|
the word "subscribe" in the body to "g10-request@net.lut.ac.uk".
|
||||||
|
|
||||||
|
|
||||||
|
See the file COPYING for copyright and warranty information.
|
||||||
|
|
||||||
|
|
||||||
|
Due to the fact that G10 does not use use any patented algorithm,
|
||||||
|
it cannot be compatible to old PGP versions, because those use
|
||||||
|
IDEA (which is worldwide patented) and RSA (which is patented in
|
||||||
|
the United States until Sep 20, 2000). I'm sorry about this, but
|
||||||
|
this is the world we have created (e.g. by using propiertary software).
|
||||||
|
|
||||||
|
|
||||||
|
Because the OpenPGP standard is still a draft, G10 is not yet
|
||||||
|
compatible to it (or PGP 5) - but it will. The data structures
|
||||||
|
used are compatible with PGP 2.x, so it can parse an list such files
|
||||||
|
and PGP should be able to parse data created by G10 and complain
|
||||||
|
about unsupported alogorithms.
|
||||||
|
|
||||||
|
The default algorithms used by G10 are ElGamal for public-key
|
||||||
|
encryption and signing; Blowfish with a 160 bit key for protecting
|
||||||
|
the secret-key components, conventional and session encryption;
|
||||||
|
RIPE MD-160 to create message digest. DSA, SHA-1 and CAST are
|
||||||
|
also implemented, but not used on default. I decided not
|
||||||
|
to use DSA as default signing algorithm, cecause it allows only for
|
||||||
|
1024 bit keys and this may be not enough in a couple of years.
|
||||||
|
|
||||||
|
Key generation takes a long time and should be improved!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
12
TODO
12
TODO
@ -8,14 +8,10 @@
|
|||||||
* keyring editing
|
* keyring editing
|
||||||
* add trust stuff
|
* add trust stuff
|
||||||
* make ttyio.c work (hide passwords etc..)
|
* make ttyio.c work (hide passwords etc..)
|
||||||
* add option file handling.
|
|
||||||
* use correct ASN values for DEK encoding
|
* use correct ASN values for DEK encoding
|
||||||
* add checking of armor trailers
|
* add checking of armor trailers
|
||||||
* add real secure memory
|
* add real secure memory
|
||||||
* look for a way to reuse RSA signatures
|
* look for a way to reuse RSA signatures
|
||||||
* find a way to remove the armor filter after it
|
|
||||||
has detected, that the data is not armored.
|
|
||||||
* Use the Chinese Remainder Theorem to speed up RSA calculations.
|
|
||||||
* remove all "Fixmes"
|
* remove all "Fixmes"
|
||||||
* speed up the RIPE-MD-160
|
* speed up the RIPE-MD-160
|
||||||
* add signal handling
|
* add signal handling
|
||||||
@ -33,3 +29,11 @@
|
|||||||
* complete cipher/cast.c
|
* complete cipher/cast.c
|
||||||
* complete cipher/dsa.c
|
* complete cipher/dsa.c
|
||||||
|
|
||||||
|
* define a standard way to specify keyid/userid and other stuff
|
||||||
|
to identify a user. We could look at the first character and
|
||||||
|
say: If it's a digit, a keyid follows (need to add a zero in
|
||||||
|
case the keyid starts with A..F); if it is a left angle bracket,
|
||||||
|
this is a email address and should be used, all others are substrings
|
||||||
|
of the userid.
|
||||||
|
[can be handles in get_pubkey_by_name()]
|
||||||
|
|
||||||
|
@ -24,6 +24,6 @@ cipher_SOURCES = blowfish.c \
|
|||||||
md.c \
|
md.c \
|
||||||
smallprime.c
|
smallprime.c
|
||||||
|
|
||||||
cipher_LIBADD = rsa.o
|
##cipher_LIBADD = rsa.o
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,8 +60,6 @@ cipher_SOURCES = blowfish.c \
|
|||||||
dsa.c \
|
dsa.c \
|
||||||
md.c \
|
md.c \
|
||||||
smallprime.c
|
smallprime.c
|
||||||
|
|
||||||
cipher_LIBADD = rsa.o
|
|
||||||
mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
|
mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
|
||||||
CONFIG_HEADER = ../config.h
|
CONFIG_HEADER = ../config.h
|
||||||
LIBRARIES = $(noinst_LIBRARIES)
|
LIBRARIES = $(noinst_LIBRARIES)
|
||||||
@ -80,6 +78,7 @@ LIBS = @LIBS@
|
|||||||
|
|
||||||
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
|
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
|
||||||
LINK = $(CC) $(LDFLAGS) -o $@
|
LINK = $(CC) $(LDFLAGS) -o $@
|
||||||
|
cipher_LIBADD =
|
||||||
cipher_OBJECTS = blowfish.o elgamal.o gost.o md5.o primegen.o random.o \
|
cipher_OBJECTS = blowfish.o elgamal.o gost.o md5.o primegen.o random.o \
|
||||||
rmd160.o sha1.o dsa.o md.o smallprime.o
|
rmd160.o sha1.o dsa.o md.o smallprime.o
|
||||||
EXTRA_cipher_SOURCES =
|
EXTRA_cipher_SOURCES =
|
||||||
|
16
configure.in
16
configure.in
@ -22,21 +22,20 @@ fi
|
|||||||
CFLAGS="-g"
|
CFLAGS="-g"
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_SYSTEM
|
||||||
AC_MSG_CHECKING(cached information)
|
AC_MSG_CHECKING(cached information)
|
||||||
hostcheck="$host"
|
hostcheck="$target"
|
||||||
AC_CACHE_VAL(ac_cv_mpi_hostcheck, [ ac_cv_mpi_hostcheck="$hostcheck" ])
|
AC_CACHE_VAL(ac_cv_mpi_hostcheck, [ ac_cv_mpi_hostcheck="$hostcheck" ])
|
||||||
if test "$ac_cv_mpi_hostcheck" != "$hostcheck"; then
|
if test "$ac_cv_mpi_hostcheck" != "$hostcheck"; then
|
||||||
AC_MSG_RESULT(changed)
|
AC_MSG_RESULT(changed)
|
||||||
AC_MSG_WARN(config.cache exists!)
|
AC_MSG_WARN(config.cache exists!)
|
||||||
AC_MSG_ERROR(you must do 'make distclean' first to compile for
|
AC_MSG_ERROR(you must do 'make distclean' first to compile for
|
||||||
different host or different parameters.)
|
different target or different parameters.)
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(ok)
|
AC_MSG_RESULT(ok)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
|
|
||||||
AC_PROG_MAKE_SET
|
AC_PROG_MAKE_SET
|
||||||
@ -71,8 +70,12 @@ AC_CHECK_FUNCS(strerror strtol strtoul)
|
|||||||
|
|
||||||
|
|
||||||
dnl setup assembler stuff
|
dnl setup assembler stuff
|
||||||
|
if test -f ./mpi/config.links ; then
|
||||||
|
. ./mpi/config.links
|
||||||
|
AC_LINK_FILES( ${mpi_ln_src}, ${mpi_ln_dst} )
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([mpi/config.links missing!])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -91,6 +94,7 @@ fi
|
|||||||
AC_SUBST(add_cipher_SOURCES)
|
AC_SUBST(add_cipher_SOURCES)
|
||||||
|
|
||||||
AC_OUTPUT([ Makefile scripts/Makefile util/Makefile mpi/Makefile \
|
AC_OUTPUT([ Makefile scripts/Makefile util/Makefile mpi/Makefile \
|
||||||
|
mpi/generic/Makefile mpi/i386/Makefile \
|
||||||
cipher/Makefile \
|
cipher/Makefile \
|
||||||
include/Makefile \
|
include/Makefile \
|
||||||
g10/Makefile tools/Makefile ],
|
g10/Makefile tools/Makefile ],
|
||||||
|
@ -218,7 +218,7 @@ encode_crypt( const char *filename, STRLIST remusr )
|
|||||||
pkc = m_alloc_clear( sizeof *pkc );
|
pkc = m_alloc_clear( sizeof *pkc );
|
||||||
pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
|
pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
|
||||||
|
|
||||||
if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
|
if( (rc = get_pubkey_byname( pkc, remusr->d )) ) {
|
||||||
last_rc = rc;
|
last_rc = rc;
|
||||||
log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
|
log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
|
||||||
continue;
|
continue;
|
||||||
|
47
g10/g10.c
47
g10/g10.c
@ -125,20 +125,21 @@ main( int argc, char **argv )
|
|||||||
{ 510, "debug" ,4|16, "set debugging flags" },
|
{ 510, "debug" ,4|16, "set debugging flags" },
|
||||||
{ 511, "debug-all" ,0, "enable full debugging"},
|
{ 511, "debug-all" ,0, "enable full debugging"},
|
||||||
{ 512, "cache-all" ,0, "hold everything in memory"},
|
{ 512, "cache-all" ,0, "hold everything in memory"},
|
||||||
{ 513, "gen-prime" , 1, "\rgenerate a prime of length n" },
|
{ 513, "gen-prime" , 1, "\r" },
|
||||||
{ 514, "test" , 0, "\rdevelopment usage" },
|
{ 514, "test" , 0, "\r" },
|
||||||
{ 515, "change-passphrase", 0, "change the passphrase of your secret keyring"},
|
{ 515, "change-passphrase", 0, "change the passphrase of your secret keyring"},
|
||||||
{ 515, "fingerprint", 0, "show the fingerprints"},
|
{ 515, "fingerprint", 0, "show the fingerprints"},
|
||||||
{ 516, "print-mds" , 0, "print all message digests"},
|
{ 516, "print-mds" , 0, "print all message digests"},
|
||||||
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
|
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
|
||||||
{ 518, "config" , 2, "use this config file" },
|
{ 518, "config" , 2, "use this config file" },
|
||||||
|
{ 519, "no-armor", 0, "\r"},
|
||||||
|
|
||||||
{0} };
|
{0} };
|
||||||
ARGPARSE_ARGS pargs;
|
ARGPARSE_ARGS pargs;
|
||||||
IOBUF a;
|
IOBUF a;
|
||||||
int rc;
|
int rc;
|
||||||
enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr,
|
enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr,
|
||||||
aTest, aPrintMDs,
|
aTest, aPrintMDs, aSignKey,
|
||||||
} action = aNull;
|
} action = aNull;
|
||||||
int orig_argc;
|
int orig_argc;
|
||||||
char **orig_argv;
|
char **orig_argv;
|
||||||
@ -189,7 +190,7 @@ main( int argc, char **argv )
|
|||||||
configfp = fopen( configname, "r" );
|
configfp = fopen( configname, "r" );
|
||||||
if( !configfp ) {
|
if( !configfp ) {
|
||||||
if( default_config ) {
|
if( default_config ) {
|
||||||
if( parse_verbose )
|
if( parse_verbose > 1 )
|
||||||
log_info("note: no default option file '%s'\n", configname );
|
log_info("note: no default option file '%s'\n", configname );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -197,7 +198,7 @@ main( int argc, char **argv )
|
|||||||
configname, strerror(errno) );
|
configname, strerror(errno) );
|
||||||
m_free(configname); configname = NULL;
|
m_free(configname); configname = NULL;
|
||||||
}
|
}
|
||||||
if( parse_verbose )
|
if( parse_verbose > 1 )
|
||||||
log_info("reading options from '%s'\n", configname );
|
log_info("reading options from '%s'\n", configname );
|
||||||
default_config = 0;
|
default_config = 0;
|
||||||
}
|
}
|
||||||
@ -209,7 +210,7 @@ main( int argc, char **argv )
|
|||||||
opt.list_sigs=1;
|
opt.list_sigs=1;
|
||||||
break;
|
break;
|
||||||
case 'z': opt.compress = pargs.r.ret_int; break;
|
case 'z': opt.compress = pargs.r.ret_int; break;
|
||||||
case 'a': opt.armor = 1; break;
|
case 'a': opt.armor = 1; opt.no_armor=0; break;
|
||||||
case 'c': action = aSym; break;
|
case 'c': action = aSym; break;
|
||||||
case 'o': opt.outfile = pargs.r.ret_str;
|
case 'o': opt.outfile = pargs.r.ret_str;
|
||||||
if( opt.outfile[0] == '-' && !opt.outfile[1] )
|
if( opt.outfile[0] == '-' && !opt.outfile[1] )
|
||||||
@ -235,6 +236,7 @@ main( int argc, char **argv )
|
|||||||
case 501: opt.answer_yes = 1; break;
|
case 501: opt.answer_yes = 1; break;
|
||||||
case 502: opt.answer_no = 1; break;
|
case 502: opt.answer_no = 1; break;
|
||||||
case 503: action = aKeygen; break;
|
case 503: action = aKeygen; break;
|
||||||
|
case 506: action = aSignKey; break;
|
||||||
case 507: action = aStore; break;
|
case 507: action = aStore; break;
|
||||||
case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
|
case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
|
||||||
case 509: add_keyring(pargs.r.ret_str); nrings++; break;
|
case 509: add_keyring(pargs.r.ret_str); nrings++; break;
|
||||||
@ -254,6 +256,7 @@ main( int argc, char **argv )
|
|||||||
goto next_pass;
|
goto next_pass;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 519: opt.no_armor=1; opt.armor=0; break;
|
||||||
default : errors++; pargs.err = configfp? 1:2; break;
|
default : errors++; pargs.err = configfp? 1:2; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,7 +273,7 @@ main( int argc, char **argv )
|
|||||||
set_debug();
|
set_debug();
|
||||||
if( opt.verbose > 1 )
|
if( opt.verbose > 1 )
|
||||||
set_packet_list_mode(1);
|
set_packet_list_mode(1);
|
||||||
if( !opt.batch && isatty(fileno(stdin)) ) {
|
if( opt.verbose && isatty(fileno(stdin)) ) {
|
||||||
if( *(s=strusage(10)) )
|
if( *(s=strusage(10)) )
|
||||||
fputs(s, stderr);
|
fputs(s, stderr);
|
||||||
if( *(s=strusage(30)) )
|
if( *(s=strusage(30)) )
|
||||||
@ -278,11 +281,14 @@ main( int argc, char **argv )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !sec_nrings ) { /* add default secret rings */
|
if( !sec_nrings ) { /* add default secret rings */
|
||||||
add_keyring("../keys/secring.g10");
|
char *p = make_filename("~/.g10", "secring.g10", NULL );
|
||||||
|
add_secret_keyring(p);
|
||||||
|
m_free(p);
|
||||||
}
|
}
|
||||||
if( !nrings ) { /* add default rings */
|
if( !nrings ) { /* add default ring */
|
||||||
add_keyring("../keys/ring.pgp");
|
char *p = make_filename("~/.g10", "pubring.g10", NULL );
|
||||||
add_keyring("../keys/pubring.g10");
|
add_keyring(p);
|
||||||
|
m_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( argc ) {
|
if( argc ) {
|
||||||
@ -323,10 +329,21 @@ main( int argc, char **argv )
|
|||||||
log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
|
log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case aSignEncr: /* sign and encrypt the given file */
|
case aSignEncr: /* sign and encrypt the given file */
|
||||||
usage(1); /* FIXME */
|
usage(1); /* FIXME */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case aSignKey: /* sign the key given as argument */
|
||||||
|
if( argc != 1 )
|
||||||
|
usage(1);
|
||||||
|
/* note: fname is the user id! */
|
||||||
|
if( (rc = sign_key(fname, locusr)) )
|
||||||
|
log_error("sign_key('%s'): %s\n", fname_print, g10_errstr(rc) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case aPrimegen:
|
case aPrimegen:
|
||||||
if( argc )
|
if( argc )
|
||||||
usage(1);
|
usage(1);
|
||||||
@ -356,9 +373,11 @@ main( int argc, char **argv )
|
|||||||
usage(1);
|
usage(1);
|
||||||
if( !(a = iobuf_open(fname)) )
|
if( !(a = iobuf_open(fname)) )
|
||||||
log_fatal("can't open '%s'\n", fname_print);
|
log_fatal("can't open '%s'\n", fname_print);
|
||||||
/* push the armor filter, so it can peek at the input data */
|
if( !opt.no_armor ) {
|
||||||
memset( &afx, 0, sizeof afx);
|
/* push the armor filter, so it can peek at the input data */
|
||||||
iobuf_push_filter( a, armor_filter, &afx );
|
memset( &afx, 0, sizeof afx);
|
||||||
|
iobuf_push_filter( a, armor_filter, &afx );
|
||||||
|
}
|
||||||
proc_packets( a );
|
proc_packets( a );
|
||||||
iobuf_close(a);
|
iobuf_close(a);
|
||||||
break;
|
break;
|
||||||
|
13
g10/getkey.c
13
g10/getkey.c
@ -83,9 +83,9 @@ add_keyring( const char *name )
|
|||||||
* combine it with the keyblock stuff from ringedit.c
|
* combine it with the keyblock stuff from ringedit.c
|
||||||
* For now we will simple add the filename as keyblock resource
|
* For now we will simple add the filename as keyblock resource
|
||||||
*/
|
*/
|
||||||
rc = add_keyblock_resource( name );
|
rc = add_keyblock_resource( name, 0 );
|
||||||
if( rc )
|
if( rc )
|
||||||
log_error("keyblock resource '%s': %s\n", name, rc );
|
log_error("keyblock resource '%s': %s\n", name, g10_errstr(rc) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -245,7 +245,7 @@ get_pubkey( PKT_public_cert *pkc, u32 *keyid )
|
|||||||
* a pubkey with that algo.
|
* a pubkey with that algo.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
get_pubkey_by_name( PKT_public_cert *pkc, const char *name )
|
get_pubkey_byname( PKT_public_cert *pkc, const char *name )
|
||||||
{
|
{
|
||||||
int internal = 0;
|
int internal = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -304,7 +304,7 @@ get_seckey( PKT_secret_cert *skc, u32 *keyid )
|
|||||||
* If NAME is NULL use the default certificate
|
* If NAME is NULL use the default certificate
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
get_seckey_by_name( PKT_secret_cert *skc, const char *name )
|
get_seckey_byname( PKT_secret_cert *skc, const char *name, int unprotect )
|
||||||
{
|
{
|
||||||
STRLIST sl;
|
STRLIST sl;
|
||||||
int rc=0;
|
int rc=0;
|
||||||
@ -319,8 +319,9 @@ get_seckey_by_name( PKT_secret_cert *skc, const char *name )
|
|||||||
/* get the secret key (this may prompt for a passprase to
|
/* get the secret key (this may prompt for a passprase to
|
||||||
* unlock the secret key
|
* unlock the secret key
|
||||||
*/
|
*/
|
||||||
if( (rc = check_secret_key( skc )) )
|
if( unprotect )
|
||||||
goto leave;
|
if( (rc = check_secret_key( skc )) )
|
||||||
|
goto leave;
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
return rc;
|
return rc;
|
||||||
|
63
g10/kbnode.c
63
g10/kbnode.c
@ -56,6 +56,36 @@ release_kbnode( KBNODE n )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Append NODE to ROOT, ROOT must exist!
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
add_kbnode( KBNODE root, KBNODE node )
|
||||||
|
{
|
||||||
|
KBNODE n1;
|
||||||
|
|
||||||
|
for(n1=root; n1->next; n1 = n1->next)
|
||||||
|
;
|
||||||
|
n1->next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Append NODE to ROOT as child of ROOT
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
add_kbnode_as_child( KBNODE root, KBNODE node )
|
||||||
|
{
|
||||||
|
KBNODE n1;
|
||||||
|
|
||||||
|
if( !(n1=root->child) )
|
||||||
|
root->child = node;
|
||||||
|
else {
|
||||||
|
for( ; n1->next; n1 = n1->next)
|
||||||
|
;
|
||||||
|
n1->next = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Return the parent node of KBNODE from the tree with ROOT
|
* Return the parent node of KBNODE from the tree with ROOT
|
||||||
*/
|
*/
|
||||||
@ -72,8 +102,39 @@ find_kbparent( KBNODE root, KBNODE node )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log_bug(NULL);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Walk through a tree of kbnodes. This functions returns
|
||||||
|
* the next kbnode for each call; before using the function the first
|
||||||
|
* time, the caller must set CONTEXT to NULL (This has simply the effect
|
||||||
|
* to start with ROOT).
|
||||||
|
*/
|
||||||
|
KBNODE
|
||||||
|
walk_kbtree( KBNODE root, KBNODE *context )
|
||||||
|
{
|
||||||
|
KBNODE n;
|
||||||
|
|
||||||
|
if( !*context ) {
|
||||||
|
*context = root;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = *context;
|
||||||
|
if( n->child ) {
|
||||||
|
n = n->child;
|
||||||
|
*context = n;
|
||||||
|
}
|
||||||
|
else if( n->next ) {
|
||||||
|
n = n->next;
|
||||||
|
*context = n;
|
||||||
|
}
|
||||||
|
else if( (n = find_kbparent( root, n )) ) {
|
||||||
|
n = n->next;
|
||||||
|
*context = n;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
13
g10/keydb.h
13
g10/keydb.h
@ -66,13 +66,14 @@ void add_secret_keyring( const char *name );
|
|||||||
void cache_public_cert( PKT_public_cert *pkc );
|
void cache_public_cert( PKT_public_cert *pkc );
|
||||||
void cache_user_id( PKT_user_id *uid, u32 *keyid );
|
void cache_user_id( PKT_user_id *uid, u32 *keyid );
|
||||||
int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
|
int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
|
||||||
int get_pubkey_by_name( PKT_public_cert *pkc, const char *name );
|
int get_pubkey_byname( PKT_public_cert *pkc, const char *name );
|
||||||
int get_seckey( PKT_secret_cert *skc, u32 *keyid );
|
int get_seckey( PKT_secret_cert *skc, u32 *keyid );
|
||||||
int get_seckey_by_name( PKT_secret_cert *skc, const char *name );
|
int get_seckey_byname( PKT_secret_cert *skc, const char *name, int unlock );
|
||||||
char*get_user_id_string( u32 *keyid );
|
char*get_user_id_string( u32 *keyid );
|
||||||
char*get_user_id( u32 *keyid, size_t *rn );
|
char*get_user_id( u32 *keyid, size_t *rn );
|
||||||
|
|
||||||
/*-- keyid.c --*/
|
/*-- keyid.c --*/
|
||||||
|
int pubkey_letter( int algo );
|
||||||
u32 keyid_from_skc( PKT_secret_cert *skc, u32 *keyid );
|
u32 keyid_from_skc( PKT_secret_cert *skc, u32 *keyid );
|
||||||
u32 keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid );
|
u32 keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid );
|
||||||
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
|
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
|
||||||
@ -87,14 +88,18 @@ byte *fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len );
|
|||||||
/*-- kbnode.c --*/
|
/*-- kbnode.c --*/
|
||||||
KBNODE new_kbnode( PACKET *pkt );
|
KBNODE new_kbnode( PACKET *pkt );
|
||||||
void release_kbnode( KBNODE n );
|
void release_kbnode( KBNODE n );
|
||||||
|
void add_kbnode( KBNODE root, KBNODE node );
|
||||||
|
void add_kbnode_as_child( KBNODE root, KBNODE node );
|
||||||
KBNODE find_kbparent( KBNODE root, KBNODE node );
|
KBNODE find_kbparent( KBNODE root, KBNODE node );
|
||||||
|
KBNODE walk_kbtree( KBNODE root, KBNODE *context );
|
||||||
|
|
||||||
/*-- ringedit.c --*/
|
/*-- ringedit.c --*/
|
||||||
int add_keyblock_resource( const char *filename );
|
int add_keyblock_resource( const char *filename, int force );
|
||||||
int get_keyblock_handle( const char *filename, KBPOS *kbpos );
|
int get_keyblock_handle( const char *filename, KBPOS *kbpos );
|
||||||
int search_keyblock( PACKET *pkt, KBPOS *kbpos );
|
int search_keyblock( PACKET *pkt, KBPOS *kbpos );
|
||||||
|
int search_keyblock_byname( KBPOS *kbpos, const char *username );
|
||||||
int lock_keyblock( KBPOS *kbpos );
|
int lock_keyblock( KBPOS *kbpos );
|
||||||
int unlock_keyblock( KBPOS *kbpos );
|
void unlock_keyblock( KBPOS *kbpos );
|
||||||
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
|
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
|
||||||
int insert_keyblock( KBPOS *kbpos, KBNODE root );
|
int insert_keyblock( KBPOS *kbpos, KBNODE root );
|
||||||
int delete_keyblock( KBPOS *kbpos );
|
int delete_keyblock( KBPOS *kbpos );
|
||||||
|
363
g10/keygen.c
363
g10/keygen.c
@ -30,6 +30,7 @@
|
|||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
#include "ttyio.h"
|
#include "ttyio.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define TEST_ALGO 1
|
#define TEST_ALGO 1
|
||||||
@ -88,52 +89,128 @@ checksum_mpi( MPI a )
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_uid( IOBUF out, const char *s, PKT_user_id **upkt )
|
write_uid( KBNODE root, const char *s )
|
||||||
{
|
{
|
||||||
PACKET pkt;
|
PACKET *pkt = m_alloc_clear(sizeof *pkt );
|
||||||
size_t n = strlen(s);
|
size_t n = strlen(s);
|
||||||
int rc;
|
|
||||||
|
|
||||||
pkt.pkttype = PKT_USER_ID;
|
pkt->pkttype = PKT_USER_ID;
|
||||||
pkt.pkt.user_id = m_alloc( sizeof *pkt.pkt.user_id + n - 1 );
|
pkt->pkt.user_id = m_alloc( sizeof *pkt->pkt.user_id + n - 1 );
|
||||||
pkt.pkt.user_id->len = n;
|
pkt->pkt.user_id->len = n;
|
||||||
strcpy(pkt.pkt.user_id->name, s);
|
strcpy(pkt->pkt.user_id->name, s);
|
||||||
if( (rc = build_packet( out, &pkt )) )
|
add_kbnode( root, new_kbnode( pkt ) );
|
||||||
log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) );
|
|
||||||
if( upkt ) {
|
|
||||||
*upkt = pkt.pkt.user_id;
|
|
||||||
pkt.pkt.user_id = NULL;
|
|
||||||
}
|
|
||||||
free_packet( &pkt );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
write_selfsig( IOBUF out, PKT_public_cert *pkc, PKT_user_id *uid,
|
write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc )
|
||||||
PKT_secret_cert *skc )
|
|
||||||
{
|
{
|
||||||
PACKET pkt;
|
PACKET *pkt;
|
||||||
PKT_signature *sig;
|
PKT_signature *sig;
|
||||||
|
PKT_user_id *uid;
|
||||||
int rc=0;
|
int rc=0;
|
||||||
|
KBNODE kbctx, node;
|
||||||
|
PKT_public_cert *pkc;
|
||||||
|
|
||||||
if( opt.verbose )
|
if( opt.verbose )
|
||||||
log_info("writing self signature\n");
|
log_info("writing self signature\n");
|
||||||
|
|
||||||
|
/* get the uid packet from the tree */
|
||||||
|
for( kbctx=NULL; (node=walk_kbtree( root, &kbctx)) ; ) {
|
||||||
|
if( node->pkt->pkttype == PKT_USER_ID )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( !node )
|
||||||
|
log_bug(NULL); /* no user id packet in tree */
|
||||||
|
uid = node->pkt->pkt.user_id;
|
||||||
|
/* get the pkc packet from the pub_tree */
|
||||||
|
for( kbctx=NULL; (node=walk_kbtree( pub_root, &kbctx)) ; ) {
|
||||||
|
if( node->pkt->pkttype == PKT_PUBLIC_CERT )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( !node )
|
||||||
|
log_bug(NULL);
|
||||||
|
pkc = node->pkt->pkt.public_cert;
|
||||||
|
|
||||||
|
/* and make the signature */
|
||||||
rc = make_keysig_packet( &sig, pkc, uid, skc, 0x13, DIGEST_ALGO_RMD160 );
|
rc = make_keysig_packet( &sig, pkc, uid, skc, 0x13, DIGEST_ALGO_RMD160 );
|
||||||
if( rc ) {
|
if( rc ) {
|
||||||
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
|
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt.pkttype = PKT_SIGNATURE;
|
pkt = m_alloc_clear( sizeof *pkt );
|
||||||
pkt.pkt.signature = sig;
|
pkt->pkttype = PKT_SIGNATURE;
|
||||||
if( (rc = build_packet( out, &pkt )) )
|
pkt->pkt.signature = sig;
|
||||||
log_error("build_packet(signature) failed: %s\n", g10_errstr(rc) );
|
add_kbnode( root, new_kbnode( pkt ) );
|
||||||
free_packet( &pkt );
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
||||||
|
PKT_secret_cert **ret_skc )
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
PACKET *pkt;
|
||||||
|
PKT_secret_cert *skc;
|
||||||
|
PKT_public_cert *pkc;
|
||||||
|
ELG_public_key pk;
|
||||||
|
ELG_secret_key sk;
|
||||||
|
unsigned nbytes;
|
||||||
|
|
||||||
|
elg_generate( &pk, &sk, nbits );
|
||||||
|
|
||||||
|
skc = m_alloc( sizeof *skc );
|
||||||
|
pkc = m_alloc( sizeof *pkc );
|
||||||
|
skc->timestamp = pkc->timestamp = make_timestamp();
|
||||||
|
skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
|
||||||
|
skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL;
|
||||||
|
memset(&pkc->mfx, 0, sizeof pkc->mfx);
|
||||||
|
pkc->d.elg.p = pk.p;
|
||||||
|
pkc->d.elg.g = pk.g;
|
||||||
|
pkc->d.elg.y = pk.y;
|
||||||
|
skc->d.elg.p = sk.p;
|
||||||
|
skc->d.elg.g = sk.g;
|
||||||
|
skc->d.elg.y = sk.y;
|
||||||
|
skc->d.elg.x = sk.x;
|
||||||
|
|
||||||
|
skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
|
||||||
|
/* return an unprotected version of the skc */
|
||||||
|
*ret_skc = copy_secret_cert( NULL, skc );
|
||||||
|
|
||||||
|
if( !dek ) {
|
||||||
|
skc->d.elg.is_protected = 0;
|
||||||
|
skc->d.elg.protect_algo = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skc->d.elg.is_protected = 0;
|
||||||
|
skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
|
||||||
|
randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
|
||||||
|
rc = protect_secret_key( skc, dek );
|
||||||
|
if( rc ) {
|
||||||
|
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
|
||||||
|
free_public_cert(pkc);
|
||||||
|
free_secret_cert(skc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = m_alloc_clear(sizeof *pkt);
|
||||||
|
pkt->pkttype = PKT_PUBLIC_CERT;
|
||||||
|
pkt->pkt.public_cert = pkc;
|
||||||
|
add_kbnode(pub_root, new_kbnode( pkt ));
|
||||||
|
|
||||||
|
pkt = m_alloc_clear(sizeof *pkt);
|
||||||
|
pkt->pkttype = PKT_SECRET_CERT;
|
||||||
|
pkt->pkt.secret_cert = skc;
|
||||||
|
add_kbnode(sec_root, new_kbnode( pkt ));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_RSA_CIPHER
|
#ifdef HAVE_RSA_CIPHER
|
||||||
static int
|
static int
|
||||||
gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
|
gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
|
||||||
@ -210,79 +287,12 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
|
|||||||
}
|
}
|
||||||
#endif /*HAVE_RSA_CIPHER*/
|
#endif /*HAVE_RSA_CIPHER*/
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
|
gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
||||||
PKT_public_cert **ret_pkc, PKT_secret_cert **ret_skc )
|
PKT_secret_cert **ret_skc )
|
||||||
{
|
{
|
||||||
int rc;
|
return G10ERR_GENERAL;
|
||||||
PACKET pkt1, pkt2;
|
|
||||||
PKT_secret_cert *skc, *unprotected_skc;
|
|
||||||
PKT_public_cert *pkc;
|
|
||||||
ELG_public_key pk;
|
|
||||||
ELG_secret_key sk;
|
|
||||||
unsigned nbytes;
|
|
||||||
|
|
||||||
init_packet(&pkt1);
|
|
||||||
init_packet(&pkt2);
|
|
||||||
|
|
||||||
elg_generate( &pk, &sk, nbits );
|
|
||||||
|
|
||||||
skc = m_alloc( sizeof *skc );
|
|
||||||
pkc = m_alloc( sizeof *pkc );
|
|
||||||
skc->timestamp = pkc->timestamp = make_timestamp();
|
|
||||||
skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
|
|
||||||
skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL;
|
|
||||||
memset(&pkc->mfx, 0, sizeof pkc->mfx);
|
|
||||||
pkc->d.elg.p = pk.p;
|
|
||||||
pkc->d.elg.g = pk.g;
|
|
||||||
pkc->d.elg.y = pk.y;
|
|
||||||
skc->d.elg.p = sk.p;
|
|
||||||
skc->d.elg.g = sk.g;
|
|
||||||
skc->d.elg.y = sk.y;
|
|
||||||
skc->d.elg.x = sk.x;
|
|
||||||
|
|
||||||
skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
|
|
||||||
unprotected_skc = copy_secret_cert( NULL, skc );
|
|
||||||
if( !dek ) {
|
|
||||||
skc->d.elg.is_protected = 0;
|
|
||||||
skc->d.elg.protect_algo = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
skc->d.elg.is_protected = 0;
|
|
||||||
skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
|
|
||||||
randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
|
|
||||||
rc = protect_secret_key( skc, dek );
|
|
||||||
if( rc ) {
|
|
||||||
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt1.pkttype = PKT_PUBLIC_CERT;
|
|
||||||
pkt1.pkt.public_cert = pkc;
|
|
||||||
pkt2.pkttype = PKT_SECRET_CERT;
|
|
||||||
pkt2.pkt.secret_cert = skc;
|
|
||||||
|
|
||||||
if( (rc = build_packet( pub_io, &pkt1 )) ) {
|
|
||||||
log_error("build public_cert packet failed: %s\n", g10_errstr(rc) );
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
if( (rc = build_packet( sec_io, &pkt2 )) ) {
|
|
||||||
log_error("build secret_cert packet failed: %s\n", g10_errstr(rc) );
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
*ret_pkc = pkt1.pkt.public_cert;
|
|
||||||
pkt1.pkt.public_cert = NULL;
|
|
||||||
*ret_skc = unprotected_skc;
|
|
||||||
unprotected_skc = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
leave:
|
|
||||||
free_packet(&pkt1);
|
|
||||||
free_packet(&pkt2);
|
|
||||||
if( unprotected_skc )
|
|
||||||
free_secret_cert( unprotected_skc );
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -295,14 +305,14 @@ generate_keypair()
|
|||||||
{
|
{
|
||||||
char *answer;
|
char *answer;
|
||||||
unsigned nbits;
|
unsigned nbits;
|
||||||
char *pub_fname = "./pubring.g10";
|
char *pub_fname = NULL;
|
||||||
char *sec_fname = "./secring.g10";
|
char *sec_fname = NULL;
|
||||||
char *uid = NULL;
|
char *uid = NULL;
|
||||||
IOBUF pub_io = NULL;
|
IOBUF pub_io = NULL;
|
||||||
IOBUF sec_io = NULL;
|
IOBUF sec_io = NULL;
|
||||||
PKT_public_cert *pkc = NULL;
|
KBNODE pub_root = NULL;
|
||||||
|
KBNODE sec_root = NULL;
|
||||||
PKT_secret_cert *skc = NULL;
|
PKT_secret_cert *skc = NULL;
|
||||||
PKT_user_id *upkt = NULL;
|
|
||||||
DEK *dek = NULL;
|
DEK *dek = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
int algo;
|
int algo;
|
||||||
@ -315,8 +325,9 @@ generate_keypair()
|
|||||||
tty_printf("Please select the algorithm to use:\n"
|
tty_printf("Please select the algorithm to use:\n"
|
||||||
" (1) ElGamal is the suggested one.\n"
|
" (1) ElGamal is the suggested one.\n"
|
||||||
#ifdef HAVE_RSA_CIPHER
|
#ifdef HAVE_RSA_CIPHER
|
||||||
" (2) RSA cannot be used inthe U.S.\n"
|
" (2) RSA cannot be used in the U.S.\n"
|
||||||
#endif
|
#endif
|
||||||
|
" (3) DSA can only be used for signatures.\n"
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -324,7 +335,11 @@ generate_keypair()
|
|||||||
#ifdef TEST_ALGO
|
#ifdef TEST_ALGO
|
||||||
algo = TEST_ALGO;
|
algo = TEST_ALGO;
|
||||||
#else
|
#else
|
||||||
answer = tty_get("Your selection? (1,2) ");
|
answer = tty_get("Your selection? (1"
|
||||||
|
#ifdef HAVE_RSA_CIPHER
|
||||||
|
",2"
|
||||||
|
#endif
|
||||||
|
",3) ");
|
||||||
tty_kill_prompt();
|
tty_kill_prompt();
|
||||||
algo = *answer? atoi(answer): 1;
|
algo = *answer? atoi(answer): 1;
|
||||||
m_free(answer);
|
m_free(answer);
|
||||||
@ -341,6 +356,11 @@ generate_keypair()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
else if( algo == 3 ) {
|
||||||
|
algo = PUBKEY_ALGO_DSA;
|
||||||
|
algo_name = "DSA";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -361,7 +381,9 @@ generate_keypair()
|
|||||||
nbits = *answer? atoi(answer): 1024;
|
nbits = *answer? atoi(answer): 1024;
|
||||||
m_free(answer);
|
m_free(answer);
|
||||||
#endif
|
#endif
|
||||||
if( nbits < 128 ) /* FIXME: change this to 768 */
|
if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
|
||||||
|
tty_printf("DSA does only allow keysizes from 512 to 1024\n");
|
||||||
|
else if( nbits < 128 ) /* FIXME: change this to 768 */
|
||||||
tty_printf("keysize too small; please select a larger one\n");
|
tty_printf("keysize too small; please select a larger one\n");
|
||||||
else if( nbits > 2048 ) {
|
else if( nbits > 2048 ) {
|
||||||
tty_printf("Keysizes larger than 2048 are not suggested, because "
|
tty_printf("Keysizes larger than 2048 are not suggested, because "
|
||||||
@ -381,7 +403,11 @@ generate_keypair()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tty_printf("Requested keysize is %u bits\n", nbits );
|
tty_printf("Requested keysize is %u bits\n", nbits );
|
||||||
if( (nbits % 32) ) {
|
if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
|
||||||
|
nbits = ((nbits + 63) / 64) * 64;
|
||||||
|
tty_printf("rounded up to %u bits\n", nbits );
|
||||||
|
}
|
||||||
|
else if( (nbits % 32) ) {
|
||||||
nbits = ((nbits + 31) / 32) * 32;
|
nbits = ((nbits + 31) / 32) * 32;
|
||||||
tty_printf("rounded up to %u bits\n", nbits );
|
tty_printf("rounded up to %u bits\n", nbits );
|
||||||
}
|
}
|
||||||
@ -435,74 +461,103 @@ generate_keypair()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* now check wether we a are allowed to write the keyrings */
|
/* now check wether we a are allowed to write to the keyrings */
|
||||||
if( !(rc=overwrite_filep( pub_fname )) ) {
|
pub_fname = make_filename("~/.g10", "pubring.g10", NULL );
|
||||||
if( !(pub_io = iobuf_create( pub_fname )) )
|
sec_fname = make_filename("~/.g10", "secring.g10", NULL );
|
||||||
log_error("can't create %s: %s\n", pub_fname, strerror(errno) );
|
if( opt.verbose ) {
|
||||||
else if( opt.verbose )
|
tty_printf("writing public certificate to '%s'\n", pub_fname );
|
||||||
log_info("writing to '%s'\n", pub_fname );
|
tty_printf("writing secret certificate to '%s'\n", sec_fname );
|
||||||
}
|
|
||||||
else if( rc != -1 ) {
|
|
||||||
log_error("Oops: overwrite_filep(%s): %s\n", pub_fname, g10_errstr(rc) );
|
|
||||||
m_free(uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_free(uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( !(rc=overwrite_filep( sec_fname )) ) {
|
|
||||||
if( !(sec_io = iobuf_create( sec_fname )) )
|
|
||||||
log_error("can't create %s: %s\n", sec_fname, strerror(errno) );
|
|
||||||
else if( opt.verbose )
|
|
||||||
log_info("writing to '%s'\n", sec_fname );
|
|
||||||
}
|
|
||||||
else if( rc != -1 ) {
|
|
||||||
log_error("Oops: overwrite_filep(%s): %s\n", sec_fname, g10_errstr(rc) );
|
|
||||||
m_free(uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iobuf_cancel(pub_io);
|
|
||||||
m_free(uid);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write_comment( pub_io, "#public key created by G10 pre-release " VERSION );
|
/* we create the packets as a tree of kbnodes. Because the structure
|
||||||
write_comment( sec_io, "#secret key created by G10 pre-release " VERSION );
|
* we create is known in advance we simply generate a linked list
|
||||||
|
* The first packet is a comment packet, followed by the userid and
|
||||||
|
* the self signature.
|
||||||
|
*/
|
||||||
|
pub_root = make_comment_node("#created by G10 pre-release " VERSION );
|
||||||
|
sec_root = make_comment_node("#created by G10 pre-release " VERSION );
|
||||||
|
|
||||||
if( algo == PUBKEY_ALGO_ELGAMAL )
|
if( algo == PUBKEY_ALGO_ELGAMAL )
|
||||||
rc = gen_elg(nbits, pub_io, sec_io, dek, &pkc, &skc);
|
rc = gen_elg(nbits, pub_root, sec_root, dek, &skc );
|
||||||
#ifdef HAVE_RSA_CIPHER
|
#ifdef HAVE_RSA_CIPHER
|
||||||
else if( algo == PUBKEY_ALGO_RSA )
|
else if( algo == PUBKEY_ALGO_RSA )
|
||||||
rc = gen_rsa(nbits, pub_io, sec_io, dek, &pkc, &skc);
|
rc = gen_rsa(nbits, pub_io, sec_io, dek, &skc );
|
||||||
#endif
|
#endif
|
||||||
|
else if( algo == PUBKEY_ALGO_DSA )
|
||||||
|
rc = gen_dsa(nbits, pub_root, sec_root, dek, &skc );
|
||||||
else
|
else
|
||||||
log_bug(NULL);
|
log_bug(NULL);
|
||||||
if( !rc )
|
if( !rc )
|
||||||
write_uid(pub_io, uid, &upkt );
|
write_uid(pub_root, uid );
|
||||||
if( !rc )
|
if( !rc )
|
||||||
write_uid(sec_io, uid, NULL );
|
write_uid(sec_root, uid );
|
||||||
if( !rc )
|
if( !rc )
|
||||||
rc = write_selfsig(pub_io, pkc, upkt, skc );
|
rc = write_selfsig(pub_root, pub_root, skc);
|
||||||
|
if( !rc )
|
||||||
|
rc = write_selfsig(sec_root, pub_root, skc);
|
||||||
|
|
||||||
if( rc ) {
|
if( !rc ) {
|
||||||
iobuf_cancel(pub_io);
|
KBPOS pub_kbpos;
|
||||||
iobuf_cancel(sec_io);
|
KBPOS sec_kbpos;
|
||||||
|
int rc1 = -1;
|
||||||
|
int rc2 = -1;
|
||||||
|
|
||||||
|
/* we can now write the certificates */
|
||||||
|
/* FIXME: should we check wether the user-id already exists? */
|
||||||
|
|
||||||
|
if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
|
||||||
|
if( add_keyblock_resource( pub_fname, 1 ) ) {
|
||||||
|
log_error("can add keyblock file '%s'\n", pub_fname );
|
||||||
|
rc = G10ERR_CREATE_FILE;
|
||||||
|
}
|
||||||
|
else if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
|
||||||
|
log_error("can get keyblock handle for '%s'\n", pub_fname );
|
||||||
|
rc = G10ERR_CREATE_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( rc )
|
||||||
|
;
|
||||||
|
else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
|
||||||
|
if( add_keyblock_resource( sec_fname, 1 ) ) {
|
||||||
|
log_error("can add keyblock file '%s'\n", sec_fname );
|
||||||
|
rc = G10ERR_CREATE_FILE;
|
||||||
|
}
|
||||||
|
else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
|
||||||
|
log_error("can get keyblock handle for '%s'\n", sec_fname );
|
||||||
|
rc = G10ERR_CREATE_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc )
|
||||||
|
;
|
||||||
|
else if( (rc=rc1=lock_keyblock( &pub_kbpos )) )
|
||||||
|
log_error("can't lock public keyring: %s\n", g10_errstr(rc) );
|
||||||
|
else if( (rc=rc2=lock_keyblock( &sec_kbpos )) )
|
||||||
|
log_error("can't lock secret keyring: %s\n", g10_errstr(rc) );
|
||||||
|
else if( (rc=insert_keyblock( &pub_kbpos, pub_root )) )
|
||||||
|
log_error("can't write public key: %s\n", g10_errstr(rc) );
|
||||||
|
else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) )
|
||||||
|
log_error("can't write secret key: %s\n", g10_errstr(rc) );
|
||||||
|
else {
|
||||||
|
tty_printf("public and secret key created and signed.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !rc1 )
|
||||||
|
unlock_keyblock( &pub_kbpos );
|
||||||
|
if( !rc2 )
|
||||||
|
unlock_keyblock( &sec_kbpos );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( rc )
|
||||||
tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
|
tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
|
||||||
}
|
release_kbnode( pub_root );
|
||||||
else {
|
release_kbnode( sec_root );
|
||||||
iobuf_close(pub_io);
|
if( skc ) /* the unprotected secret certificate */
|
||||||
iobuf_close(sec_io);
|
free_secret_cert(skc);
|
||||||
tty_printf("public and secret key created and signed.\n" );
|
|
||||||
}
|
|
||||||
if( pkc )
|
|
||||||
free_public_cert( pkc );
|
|
||||||
if( skc )
|
|
||||||
free_secret_cert( skc );
|
|
||||||
if( upkt )
|
|
||||||
free_user_id( upkt );
|
|
||||||
m_free(uid);
|
m_free(uid);
|
||||||
m_free(dek);
|
m_free(dek);
|
||||||
|
m_free(pub_fname);
|
||||||
|
m_free(sec_fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
g10/keyid.c
12
g10/keyid.c
@ -33,6 +33,18 @@
|
|||||||
#include "keydb.h"
|
#include "keydb.h"
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pubkey_letter( int algo )
|
||||||
|
{
|
||||||
|
switch( algo ) {
|
||||||
|
case PUBKEY_ALGO_RSA: return 'R' ;
|
||||||
|
case PUBKEY_ALGO_RSA_E: return 'r' ;
|
||||||
|
case PUBKEY_ALGO_RSA_S: return 's' ;
|
||||||
|
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
||||||
|
case PUBKEY_ALGO_DSA: return 'D' ;
|
||||||
|
default: return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "iobuf.h"
|
#include "iobuf.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
|
||||||
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH
|
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH
|
||||||
#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL
|
#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL
|
||||||
@ -34,6 +35,7 @@ int encode_crypt( const char *filename, STRLIST remusr );
|
|||||||
|
|
||||||
/*-- sign.c --*/
|
/*-- sign.c --*/
|
||||||
int sign_file( const char *filename, int detached, STRLIST locusr );
|
int sign_file( const char *filename, int detached, STRLIST locusr );
|
||||||
|
int sign_key( const char *username, STRLIST locusr );
|
||||||
|
|
||||||
/*-- keygen.c --*/
|
/*-- keygen.c --*/
|
||||||
void generate_keypair(void);
|
void generate_keypair(void);
|
||||||
@ -49,5 +51,7 @@ MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits );
|
|||||||
MPI encode_md5_value( byte *md, unsigned len, unsigned nbits );
|
MPI encode_md5_value( byte *md, unsigned len, unsigned nbits );
|
||||||
MPI encode_md_value( MD_HANDLE *md, unsigned nbits );
|
MPI encode_md_value( MD_HANDLE *md, unsigned nbits );
|
||||||
|
|
||||||
|
/*-- comment.c --*/
|
||||||
|
KBNODE make_comment_node( const char *s );
|
||||||
|
|
||||||
#endif /*G10_MAIN_H*/
|
#endif /*G10_MAIN_H*/
|
||||||
|
@ -56,19 +56,6 @@ typedef struct {
|
|||||||
static void list_node( CTX c, KBNODE node );
|
static void list_node( CTX c, KBNODE node );
|
||||||
static void proc_tree( CTX c, KBNODE node );
|
static void proc_tree( CTX c, KBNODE node );
|
||||||
|
|
||||||
static int
|
|
||||||
pubkey_letter( int algo )
|
|
||||||
{
|
|
||||||
switch( algo ) {
|
|
||||||
case PUBKEY_ALGO_RSA: return 'R' ;
|
|
||||||
case PUBKEY_ALGO_RSA_E: return 'r' ;
|
|
||||||
case PUBKEY_ALGO_RSA_S: return 's' ;
|
|
||||||
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
|
||||||
case PUBKEY_ALGO_DSA: return 'D' ;
|
|
||||||
default: return '?';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
release_cert( CTX c )
|
release_cert( CTX c )
|
||||||
@ -509,7 +496,6 @@ proc_packets( IOBUF a )
|
|||||||
CTX c = m_alloc_clear( sizeof *c );
|
CTX c = m_alloc_clear( sizeof *c );
|
||||||
PACKET *pkt = m_alloc( sizeof *pkt );
|
PACKET *pkt = m_alloc( sizeof *pkt );
|
||||||
int rc, result;
|
int rc, result;
|
||||||
char *ustr;
|
|
||||||
int lvl0, lvl1;
|
int lvl0, lvl1;
|
||||||
u32 keyid[2];
|
u32 keyid[2];
|
||||||
int newpkt;
|
int newpkt;
|
||||||
|
@ -34,7 +34,7 @@ struct {
|
|||||||
int cache_all;
|
int cache_all;
|
||||||
int fingerprint; /* list fingerprints */
|
int fingerprint; /* list fingerprints */
|
||||||
int list_sigs; /* list signatures */
|
int list_sigs; /* list signatures */
|
||||||
int reserved4;
|
int no_armor;
|
||||||
int reserved5;
|
int reserved5;
|
||||||
int reserved6;
|
int reserved6;
|
||||||
int reserved7;
|
int reserved7;
|
||||||
|
130
g10/ringedit.c
130
g10/ringedit.c
@ -60,9 +60,10 @@ struct resource_table_struct {
|
|||||||
char *fname;
|
char *fname;
|
||||||
IOBUF iobuf;
|
IOBUF iobuf;
|
||||||
};
|
};
|
||||||
|
typedef struct resource_table_struct RESTBL;
|
||||||
|
|
||||||
#define MAX_RESOURCES 10
|
#define MAX_RESOURCES 10
|
||||||
static struct resource_table_struct resource_table[MAX_RESOURCES];
|
static RESTBL resource_table[MAX_RESOURCES];
|
||||||
|
|
||||||
|
|
||||||
static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
|
static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
|
||||||
@ -72,14 +73,14 @@ static int keyring_delete( KBPOS *kbpos );
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static RESTBL *
|
||||||
check_pos( KBPOS *kbpos )
|
check_pos( KBPOS *kbpos )
|
||||||
{
|
{
|
||||||
if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
|
if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
|
||||||
return G10ERR_GENERAL;
|
return NULL;
|
||||||
if( !resource_table[kbpos->resno].used )
|
if( !resource_table[kbpos->resno].used )
|
||||||
return G10ERR_GENERAL;
|
return NULL;
|
||||||
return 0;
|
return resource_table + kbpos->resno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ check_pos( KBPOS *kbpos )
|
|||||||
* Register a resource (which currently may ionly be a keyring file).
|
* Register a resource (which currently may ionly be a keyring file).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
add_keyblock_resource( const char *filename )
|
add_keyblock_resource( const char *filename, int force )
|
||||||
{
|
{
|
||||||
IOBUF iobuf;
|
IOBUF iobuf;
|
||||||
int i;
|
int i;
|
||||||
@ -104,7 +105,7 @@ add_keyblock_resource( const char *filename )
|
|||||||
return G10ERR_RESOURCE_LIMIT;
|
return G10ERR_RESOURCE_LIMIT;
|
||||||
|
|
||||||
iobuf = iobuf_open( filename );
|
iobuf = iobuf_open( filename );
|
||||||
if( !iobuf )
|
if( !iobuf && !force )
|
||||||
return G10ERR_OPEN_FILE;
|
return G10ERR_OPEN_FILE;
|
||||||
resource_table[i].used = 1;
|
resource_table[i].used = 1;
|
||||||
resource_table[i].fname = m_strdup(filename);
|
resource_table[i].fname = m_strdup(filename);
|
||||||
@ -170,6 +171,31 @@ search_keyblock( PACKET *pkt, KBPOS *kbpos )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Combined function to search for a username and get the position
|
||||||
|
* of the keyblock.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
search_keyblock_byname( KBPOS *kbpos, const char *username )
|
||||||
|
{
|
||||||
|
PACKET pkt;
|
||||||
|
PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = get_pubkey_byname( pkc, username );
|
||||||
|
if( rc ) {
|
||||||
|
free_public_cert(pkc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_packet( &pkt );
|
||||||
|
pkt.pkttype = PKT_PUBLIC_CERT;
|
||||||
|
pkt.pkt.public_cert = pkc;
|
||||||
|
rc = search_keyblock( &pkt, kbpos );
|
||||||
|
free_public_cert(pkc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Lock the keyblock; wait until it's available
|
* Lock the keyblock; wait until it's available
|
||||||
@ -182,22 +208,19 @@ lock_keyblock( KBPOS *kbpos )
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( (rc=check_pos(kbpos)) )
|
if( !check_pos(kbpos) )
|
||||||
return rc;
|
return G10ERR_GENERAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Release a lock on a keyblock
|
* Release a lock on a keyblock
|
||||||
*/
|
*/
|
||||||
int
|
void
|
||||||
unlock_keyblock( KBPOS *kbpos )
|
unlock_keyblock( KBPOS *kbpos )
|
||||||
{
|
{
|
||||||
int rc;
|
if( !check_pos(kbpos) )
|
||||||
|
log_bug(NULL);
|
||||||
if( (rc=check_pos(kbpos)) )
|
|
||||||
return rc;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
@ -206,10 +229,8 @@ unlock_keyblock( KBPOS *kbpos )
|
|||||||
int
|
int
|
||||||
read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
|
read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
|
||||||
{
|
{
|
||||||
int rc;
|
if( !check_pos(kbpos) )
|
||||||
|
return G10ERR_GENERAL;
|
||||||
if( (rc=check_pos(kbpos)) )
|
|
||||||
return rc;
|
|
||||||
return keyring_read( kbpos, ret_root );
|
return keyring_read( kbpos, ret_root );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +243,8 @@ insert_keyblock( KBPOS *kbpos, KBNODE root )
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( (rc=check_pos(kbpos)) )
|
if( !check_pos(kbpos) )
|
||||||
return rc;
|
return G10ERR_GENERAL;
|
||||||
|
|
||||||
rc = keyring_insert( kbpos, root );
|
rc = keyring_insert( kbpos, root );
|
||||||
|
|
||||||
@ -241,8 +262,8 @@ delete_keyblock( KBPOS *kbpos )
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( (rc=check_pos(kbpos)) )
|
if( !check_pos(kbpos) )
|
||||||
return rc;
|
return G10ERR_GENERAL;
|
||||||
|
|
||||||
rc = keyring_delete( kbpos );
|
rc = keyring_delete( kbpos );
|
||||||
|
|
||||||
@ -358,13 +379,26 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
|
|||||||
{
|
{
|
||||||
PACKET *pkt;
|
PACKET *pkt;
|
||||||
int rc;
|
int rc;
|
||||||
|
RESTBL *rentry;
|
||||||
KBNODE root = NULL;
|
KBNODE root = NULL;
|
||||||
KBNODE node, n1, n2;
|
KBNODE node, n1, n2;
|
||||||
IOBUF a;
|
IOBUF a;
|
||||||
|
|
||||||
if( (rc=check_pos(kbpos)) )
|
if( !(rentry=check_pos(kbpos)) )
|
||||||
return rc;
|
return G10ERR_GENERAL;
|
||||||
a = resource_table[kbpos->resno].iobuf;
|
|
||||||
|
a = iobuf_open( rentry->fname );
|
||||||
|
if( !a ) {
|
||||||
|
log_error("can't open '%s'\n", rentry->fname );
|
||||||
|
return G10ERR_OPEN_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iobuf_seek( a, kbpos->offset ) ) {
|
||||||
|
log_error("can't seek to %lu: %s\n", kbpos->offset, g10_errstr(rc));
|
||||||
|
iobuf_close(a);
|
||||||
|
return G10ERR_KEYRING_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pkt = m_alloc( sizeof *pkt );
|
pkt = m_alloc( sizeof *pkt );
|
||||||
init_packet(pkt);
|
init_packet(pkt);
|
||||||
@ -377,7 +411,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
|
|||||||
case PKT_PUBLIC_CERT:
|
case PKT_PUBLIC_CERT:
|
||||||
case PKT_SECRET_CERT:
|
case PKT_SECRET_CERT:
|
||||||
if( root )
|
if( root )
|
||||||
break;
|
goto ready;
|
||||||
root = new_kbnode( pkt );
|
root = new_kbnode( pkt );
|
||||||
pkt = m_alloc( sizeof *pkt );
|
pkt = m_alloc( sizeof *pkt );
|
||||||
init_packet(pkt);
|
init_packet(pkt);
|
||||||
@ -386,8 +420,8 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
|
|||||||
case PKT_USER_ID:
|
case PKT_USER_ID:
|
||||||
if( !root ) {
|
if( !root ) {
|
||||||
log_error("read_keyblock: orphaned user id\n" );
|
log_error("read_keyblock: orphaned user id\n" );
|
||||||
rc = G10ERR_INV_KEYRING; /* or wron kbpos */
|
rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
|
||||||
break;
|
goto ready;
|
||||||
}
|
}
|
||||||
/* append the user id */
|
/* append the user id */
|
||||||
node = new_kbnode( pkt );
|
node = new_kbnode( pkt );
|
||||||
@ -434,6 +468,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ready:
|
||||||
kbpos->last_block = rc == -1; /* flag, that this is the last block */
|
kbpos->last_block = rc == -1; /* flag, that this is the last block */
|
||||||
if( rc == -1 && root )
|
if( rc == -1 && root )
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@ -446,14 +481,49 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
|
|||||||
}
|
}
|
||||||
free_packet( pkt );
|
free_packet( pkt );
|
||||||
m_free( pkt );
|
m_free( pkt );
|
||||||
|
iobuf_close(a);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Insert the keyblock described by ROOT into the keyring described
|
||||||
|
* by KBPOS. This actually appends the data to the keyfile.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
keyring_insert( KBPOS *kbpos, KBNODE root )
|
keyring_insert( KBPOS *kbpos, KBNODE root )
|
||||||
{
|
{
|
||||||
return -1;
|
RESTBL *rentry;
|
||||||
|
IOBUF fp;
|
||||||
|
KBNODE kbctx, node;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if( !(rentry = check_pos( kbpos )) )
|
||||||
|
return G10ERR_GENERAL;
|
||||||
|
|
||||||
|
/* FIXME: we must close the file if it's already open, due to
|
||||||
|
* 2 reasons:
|
||||||
|
* - cannot open the same file twice on DOSish OSes
|
||||||
|
* - must sync with iobufs somehow
|
||||||
|
*/
|
||||||
|
/* open the file for append */
|
||||||
|
fp = iobuf_append( rentry->fname );
|
||||||
|
if( !fp ) {
|
||||||
|
log_error("can't append to '%s'\n", rentry->fname );
|
||||||
|
return G10ERR_OPEN_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbctx=NULL;
|
||||||
|
while( (node = walk_kbtree( root, &kbctx )) ) {
|
||||||
|
if( (rc = build_packet( fp, node->pkt )) ) {
|
||||||
|
log_error("build_packet(%d) failed: %s\n",
|
||||||
|
node->pkt->pkttype, g10_errstr(rc) );
|
||||||
|
return G10ERR_WRITE_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iobuf_close(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -49,7 +49,7 @@ make_session_key( DEK *dek )
|
|||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Encode the session key. NBITS is the number of bits which should be used
|
* Encode the session key. NBITS is the number of bits which should be used
|
||||||
* for packing teh session key.
|
* for packing the session key.
|
||||||
* returns: A mpi with the session key (caller must free)
|
* returns: A mpi with the session key (caller must free)
|
||||||
*/
|
*/
|
||||||
MPI
|
MPI
|
||||||
|
@ -64,6 +64,7 @@ IOBUF iobuf_alloc(int usage, size_t bufsize);
|
|||||||
IOBUF iobuf_temp(void);
|
IOBUF iobuf_temp(void);
|
||||||
IOBUF iobuf_open( const char *fname );
|
IOBUF iobuf_open( const char *fname );
|
||||||
IOBUF iobuf_create( const char *fname );
|
IOBUF iobuf_create( const char *fname );
|
||||||
|
IOBUF iobuf_append( const char *fname );
|
||||||
int iobuf_close( IOBUF iobuf );
|
int iobuf_close( IOBUF iobuf );
|
||||||
int iobuf_cancel( IOBUF iobuf );
|
int iobuf_cancel( IOBUF iobuf );
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define G10_TTYIO_H
|
#define G10_TTYIO_H
|
||||||
|
|
||||||
void tty_printf( const char *fmt, ... );
|
void tty_printf( const char *fmt, ... );
|
||||||
|
void tty_print_string( byte *p, size_t n );
|
||||||
char *tty_get( const char *prompt );
|
char *tty_get( const char *prompt );
|
||||||
char *tty_get_hidden( const char *prompt );
|
char *tty_get_hidden( const char *prompt );
|
||||||
void tty_kill_prompt(void);
|
void tty_kill_prompt(void);
|
||||||
|
@ -5,6 +5,10 @@ CFLAGS += -O2
|
|||||||
|
|
||||||
SUFFIXES = .S .s
|
SUFFIXES = .S .s
|
||||||
|
|
||||||
|
SUBDIRS = generic i386
|
||||||
|
EXTRA_DIST = config.links
|
||||||
|
|
||||||
|
|
||||||
noinst_LIBRARIES = mpi
|
noinst_LIBRARIES = mpi
|
||||||
noinst_HEADERS = sysdep.h
|
noinst_HEADERS = sysdep.h
|
||||||
|
|
||||||
|
110
mpi/Makefile.in
110
mpi/Makefile.in
@ -42,6 +42,9 @@ INCLUDES = -I$(top_srcdir)/include
|
|||||||
|
|
||||||
SUFFIXES = .S .s
|
SUFFIXES = .S .s
|
||||||
|
|
||||||
|
SUBDIRS = generic i386
|
||||||
|
EXTRA_DIST = config.links
|
||||||
|
|
||||||
noinst_LIBRARIES = mpi
|
noinst_LIBRARIES = mpi
|
||||||
noinst_HEADERS = sysdep.h
|
noinst_HEADERS = sysdep.h
|
||||||
|
|
||||||
@ -158,13 +161,45 @@ libmpi.a: $(mpi_OBJECTS) $(mpi_LIBADD)
|
|||||||
$(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD)
|
$(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD)
|
||||||
$(RANLIB) libmpi.a
|
$(RANLIB) libmpi.a
|
||||||
|
|
||||||
ID: $(HEADERS) $(SOURCES)
|
# This directory's subdirectories are mostly independent; you can cd
|
||||||
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
|
# into them and run `make' without going through this Makefile.
|
||||||
|
# To change the values of `make' variables: instead of editing Makefiles,
|
||||||
|
# (1) if the variable is set in `config.status', edit `config.status'
|
||||||
|
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||||
|
# (2) otherwise, pass the desired values on the `make' command line.
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
|
||||||
|
all-recursive install-data-recursive install-exec-recursive \
|
||||||
|
installdirs-recursive install-recursive uninstall-recursive \
|
||||||
|
check-recursive installcheck-recursive info-recursive dvi-recursive \
|
||||||
|
mostlyclean-recursive clean-recursive distclean-recursive \
|
||||||
|
maintainer-clean-recursive:
|
||||||
|
for subdir in $(SUBDIRS); do \
|
||||||
|
target=`echo $@ | sed s/-recursive//`; \
|
||||||
|
echo making $$target in $$subdir; \
|
||||||
|
(cd $$subdir && $(MAKE) $$target) \
|
||||||
|
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||||
|
done && test -z "$$fail"
|
||||||
|
|
||||||
tags: TAGS
|
tags: TAGS
|
||||||
|
|
||||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
|
tags-recursive:
|
||||||
here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
|
list="$(SUBDIRS)"; for subdir in $$list; do \
|
||||||
|
(cd $$subdir && $(MAKE) tags); \
|
||||||
|
done
|
||||||
|
|
||||||
|
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(CONFIG_HEADER) \
|
||||||
|
$(TAGS_DEPENDENCIES)
|
||||||
|
tags=; \
|
||||||
|
here=`pwd`; \
|
||||||
|
for subdir in $(SUBDIRS); do \
|
||||||
|
test -f $$subdir/TAGS && { \
|
||||||
|
tags="$$tags -i $$here/$$subdir/TAGS"; \
|
||||||
|
}; \
|
||||||
|
done; \
|
||||||
|
test -z "$(ETAGS_ARGS)$(CONFIG_HEADER)$(SOURCES)$(HEADERS)$$tags" \
|
||||||
|
|| etags $(ETAGS_ARGS) $$tags $(CONFIG_HEADER) $(SOURCES) $(HEADERS)
|
||||||
|
|
||||||
mostlyclean-tags:
|
mostlyclean-tags:
|
||||||
|
|
||||||
@ -183,6 +218,14 @@ distdir: $(DEP_DISTFILES)
|
|||||||
|| ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
|
|| ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
|
||||||
|| cp -p $(srcdir)/$$file $(distdir)/$$file; \
|
|| cp -p $(srcdir)/$$file $(distdir)/$$file; \
|
||||||
done
|
done
|
||||||
|
for subdir in $(SUBDIRS); do \
|
||||||
|
test -d $(distdir)/$$subdir \
|
||||||
|
|| mkdir $(distdir)/$$subdir \
|
||||||
|
|| exit 1; \
|
||||||
|
chmod 777 $(distdir)/$$subdir; \
|
||||||
|
(cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \
|
||||||
|
|| exit 1; \
|
||||||
|
done
|
||||||
|
|
||||||
# This fragment is probably only useful for maintainers. It relies on
|
# This fragment is probably only useful for maintainers. It relies on
|
||||||
# GNU make and gcc. It is only included in the generated Makefile.in
|
# GNU make and gcc. It is only included in the generated Makefile.in
|
||||||
@ -210,28 +253,30 @@ $(srcdir)/.deps/%.P: $(srcdir)/%.c
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# End of maintainer-only section
|
# End of maintainer-only section
|
||||||
info:
|
info: info-recursive
|
||||||
|
|
||||||
dvi:
|
dvi: dvi-recursive
|
||||||
|
|
||||||
check: all
|
check: all check-recursive
|
||||||
|
|
||||||
installcheck:
|
installcheck: installcheck-recursive
|
||||||
|
|
||||||
install-exec:
|
all-am: $(LIBFILES) $(HEADERS) Makefile
|
||||||
|
|
||||||
install-data:
|
install-exec: install-exec-recursive
|
||||||
|
|
||||||
install: install-exec install-data all
|
install-data: install-data-recursive
|
||||||
|
|
||||||
|
install: install-recursive
|
||||||
@:
|
@:
|
||||||
|
|
||||||
uninstall:
|
uninstall: uninstall-recursive
|
||||||
|
|
||||||
all: $(LIBFILES) $(HEADERS) Makefile
|
all: all-recursive all-am
|
||||||
|
|
||||||
install-strip:
|
install-strip:
|
||||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
||||||
installdirs:
|
installdirs: installdirs-recursive
|
||||||
|
|
||||||
|
|
||||||
mostlyclean-generic:
|
mostlyclean-generic:
|
||||||
@ -247,29 +292,42 @@ distclean-generic:
|
|||||||
maintainer-clean-generic:
|
maintainer-clean-generic:
|
||||||
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||||
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
|
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
|
||||||
mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
|
mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
|
||||||
mostlyclean-tags mostlyclean-generic
|
mostlyclean-tags mostlyclean-generic
|
||||||
|
|
||||||
clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
|
clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
|
||||||
mostlyclean
|
mostlyclean-am
|
||||||
|
|
||||||
distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
|
distclean-am: distclean-noinstLIBRARIES distclean-compile \
|
||||||
distclean-generic clean
|
distclean-tags distclean-generic clean-am
|
||||||
|
|
||||||
|
maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
|
||||||
|
maintainer-clean-compile maintainer-clean-tags \
|
||||||
|
maintainer-clean-generic distclean-am
|
||||||
|
|
||||||
|
mostlyclean: mostlyclean-am mostlyclean-recursive
|
||||||
|
|
||||||
|
clean: clean-am clean-recursive
|
||||||
|
|
||||||
|
distclean: distclean-am distclean-recursive
|
||||||
rm -f config.status
|
rm -f config.status
|
||||||
|
|
||||||
maintainer-clean: maintainer-clean-noinstLIBRARIES \
|
maintainer-clean: maintainer-clean-am maintainer-clean-recursive
|
||||||
maintainer-clean-compile maintainer-clean-tags \
|
|
||||||
maintainer-clean-generic distclean
|
|
||||||
@echo "This command is intended for maintainers to use;"
|
@echo "This command is intended for maintainers to use;"
|
||||||
@echo "it deletes files that may require special tools to rebuild."
|
@echo "it deletes files that may require special tools to rebuild."
|
||||||
|
|
||||||
.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
|
.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
|
||||||
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
|
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
|
||||||
mostlyclean-compile distclean-compile clean-compile \
|
mostlyclean-compile distclean-compile clean-compile \
|
||||||
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
|
maintainer-clean-compile install-data-recursive \
|
||||||
clean-tags maintainer-clean-tags distdir info dvi check installcheck \
|
uninstall-data-recursive install-exec-recursive \
|
||||||
install-exec install-data install uninstall all installdirs \
|
uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
|
||||||
mostlyclean-generic distclean-generic clean-generic \
|
all-recursive check-recursive installcheck-recursive info-recursive \
|
||||||
|
dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
|
||||||
|
maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
|
||||||
|
distclean-tags clean-tags maintainer-clean-tags distdir info dvi check \
|
||||||
|
installcheck all-am install-exec install-data install uninstall all \
|
||||||
|
installdirs mostlyclean-generic distclean-generic clean-generic \
|
||||||
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
|
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
|
||||||
|
|
||||||
CFLAGS += -O2
|
CFLAGS += -O2
|
||||||
|
51
mpi/config.links
Normal file
51
mpi/config.links
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# sourced my ../configure to get the list of files to link
|
||||||
|
# this should set $mpi_ln_src and mpi_ln_dst.
|
||||||
|
# Note: this is called from the above directory.
|
||||||
|
|
||||||
|
echo '# created by config.links - do not edit' >./mpi/asm-syntax.h
|
||||||
|
|
||||||
|
case "${target}" in
|
||||||
|
i[3456]86*-*-*)
|
||||||
|
echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
|
||||||
|
echo '#include "./i386/syntax.h"' >>./mpi/asm-syntax.h
|
||||||
|
path="i386"
|
||||||
|
;;
|
||||||
|
i[56]86*-*-* | pentium-*-* | pentiumpro-*-*)
|
||||||
|
echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
|
||||||
|
echo '#include "./i586/syntax.h"' >>./mpi/asm-syntax.h
|
||||||
|
path="i586"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h
|
||||||
|
path=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
# fixme: grep these modules from Makefile.in
|
||||||
|
mpi_ln_modules="mpih-add1 mpih-mul1 mpih-mul2 mpih-mul3 \
|
||||||
|
mpih-shift mpih-sub1"
|
||||||
|
|
||||||
|
mpi_ln_objects=
|
||||||
|
mpi_ln_src=
|
||||||
|
mpi_ln_dst=
|
||||||
|
|
||||||
|
# try to get file to link from the assembler subdirectory and
|
||||||
|
# if this fails get it from the generic subdirectory.
|
||||||
|
path="$path generic"
|
||||||
|
for fn in $mpi_ln_modules ; do
|
||||||
|
mpi_ln_objects="$mpi_ln_objects $fn.o"
|
||||||
|
for dir in $path ; do
|
||||||
|
rm -f ./mpi/$fn.[Sc]
|
||||||
|
if test -f ./mpi/$dir/$fn.S ; then
|
||||||
|
mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.S"
|
||||||
|
mpi_ln_dst="$mpi_ln_dst mpi/$fn.S"
|
||||||
|
break;
|
||||||
|
elif test -f ./mpi/$dir/$fn.c ; then
|
||||||
|
mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.c"
|
||||||
|
mpi_ln_dst="$mpi_ln_dst mpi/$fn.c"
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
@ -194,6 +194,7 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
|
|||||||
char keyword[100];
|
char keyword[100];
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
|
int inverse=0;
|
||||||
|
|
||||||
if( !fp ) /* same as arg_parse() in this case */
|
if( !fp ) /* same as arg_parse() in this case */
|
||||||
return arg_parse( arg, opts );
|
return arg_parse( arg, opts );
|
||||||
@ -216,6 +217,8 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
|
|||||||
break;
|
break;
|
||||||
index = i;
|
index = i;
|
||||||
arg->r_opt = opts[index].short_opt;
|
arg->r_opt = opts[index].short_opt;
|
||||||
|
if( inverse )
|
||||||
|
arg->r_opt = -arg->r_opt;
|
||||||
if( !opts[index].short_opt )
|
if( !opts[index].short_opt )
|
||||||
arg->r_opt = -2; /* unknown option */
|
arg->r_opt = -2; /* unknown option */
|
||||||
else if( (opts[index].flags & 8) ) /* no optional argument */
|
else if( (opts[index].flags & 8) ) /* no optional argument */
|
||||||
|
49
util/iobuf.c
49
util/iobuf.c
@ -370,6 +370,36 @@ iobuf_create( const char *fname )
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* append to a iobuf if the file does not exits; create it.
|
||||||
|
* cannont be used for stdout.
|
||||||
|
*/
|
||||||
|
IOBUF
|
||||||
|
iobuf_append( const char *fname )
|
||||||
|
{
|
||||||
|
IOBUF a;
|
||||||
|
FILE *fp;
|
||||||
|
file_filter_ctx_t *fcx;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if( !fname )
|
||||||
|
return NULL;
|
||||||
|
else if( !(fp = fopen(fname, "ab")) )
|
||||||
|
return NULL;
|
||||||
|
a = iobuf_alloc(2, 8192 );
|
||||||
|
fcx = m_alloc( sizeof *fcx + strlen(fname) );
|
||||||
|
fcx->fp = fp;
|
||||||
|
strcpy(fcx->fname, fname );
|
||||||
|
a->filter = file_filter;
|
||||||
|
a->filter_ov = fcx;
|
||||||
|
file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
|
||||||
|
file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
|
||||||
|
if( DBG_IOBUF )
|
||||||
|
log_debug("iobuf-%d.%d: append '%s'\n", a->no, a->subno, a->desc );
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Register an i/o filter.
|
* Register an i/o filter.
|
||||||
*/
|
*/
|
||||||
@ -709,8 +739,25 @@ iobuf_tell( IOBUF a )
|
|||||||
int
|
int
|
||||||
iobuf_seek( IOBUF a, ulong newpos )
|
iobuf_seek( IOBUF a, ulong newpos )
|
||||||
{
|
{
|
||||||
|
file_filter_ctx_t *b = NULL;
|
||||||
|
|
||||||
return -1;
|
for( ; a; a = a->chain ) {
|
||||||
|
if( !a->chain && a->filter == file_filter ) {
|
||||||
|
b = a->filter_ov;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !a )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if( fseek( b->fp, newpos, SEEK_SET ) ) {
|
||||||
|
log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: flush all buffers (and remove filters?)*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ print_string( FILE *fp, byte *p, size_t n )
|
|||||||
else if( !*p )
|
else if( !*p )
|
||||||
putc('0', fp);
|
putc('0', fp);
|
||||||
else
|
else
|
||||||
printf("x%02x", *p );
|
fprintf(fp, "x%02x", *p );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
putc(*p, fp);
|
putc(*p, fp);
|
||||||
|
22
util/ttyio.c
22
util/ttyio.c
@ -60,6 +60,28 @@ tty_printf( const char *fmt, ... )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Print a string, but filter all control characters out.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tty_print_string( byte *p, size_t n )
|
||||||
|
{
|
||||||
|
for( ; n; n--, p++ )
|
||||||
|
if( iscntrl( *p ) ) {
|
||||||
|
putc('\\', stderr);
|
||||||
|
if( *p == '\n' )
|
||||||
|
putc('n', stderr);
|
||||||
|
else if( !*p )
|
||||||
|
putc('0', stderr);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "x%02x", *p );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
putc(*p, stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
tty_get( const char *prompt )
|
tty_get( const char *prompt )
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user