2003-06-05 07:14:21 +00:00
/* keygen.c - generate a key pair
2006-04-19 11:26:11 +00:00
* Copyright ( C ) 1998 , 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 ,
2010-04-14 14:39:16 +00:00
* 2006 , 2007 , 2009 , 2010 Free Software Foundation , Inc .
2003-06-05 07:14:21 +00:00
*
* This file is part of GnuPG .
*
* GnuPG is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2007-07-04 19:49:40 +00:00
* the Free Software Foundation ; either version 3 of the License , or
2003-06-05 07:14:21 +00:00
* ( at your option ) any later version .
*
* GnuPG is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2007-07-04 19:49:40 +00:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2003-06-05 07:14:21 +00:00
*/
2011-01-21 12:00:57 +01:00
# warning wk: check these changes.
2003-06-05 07:14:21 +00:00
# include <config.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <assert.h>
2006-04-19 11:26:11 +00:00
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
2003-06-18 19:56:13 +00:00
# include "gpg.h"
2003-06-05 07:14:21 +00:00
# include "util.h"
# include "main.h"
# include "packet.h"
# include "cipher.h"
# include "ttyio.h"
# include "options.h"
# include "keydb.h"
# include "trustdb.h"
# include "status.h"
# include "i18n.h"
2006-06-27 14:30:59 +00:00
# include "keyserver-internal.h"
2003-06-27 20:53:09 +00:00
# include "call-agent.h"
2011-01-05 17:33:17 -08:00
# include "pkglue.h"
2003-06-27 20:53:09 +00:00
2009-12-04 19:47:54 +00:00
/* The default algorithms. If you change them remember to change them
also in gpg . c : gpgconf_list . You should also check that the value
is inside the bounds enforced by ask_keysize and gen_xxx . */
# define DEFAULT_STD_ALGO GCRY_PK_RSA
# define DEFAULT_STD_KEYSIZE 2048
2003-06-05 07:14:21 +00:00
# define MAX_PREFS 30
enum para_name {
pKEYTYPE ,
pKEYLENGTH ,
pKEYUSAGE ,
pSUBKEYTYPE ,
pSUBKEYLENGTH ,
pSUBKEYUSAGE ,
2003-07-23 07:11:06 +00:00
pAUTHKEYTYPE ,
2003-06-05 07:14:21 +00:00
pNAMEREAL ,
pNAMEEMAIL ,
pNAMECOMMENT ,
pPREFERENCES ,
pREVOKER ,
pUSERID ,
2007-07-05 16:58:19 +00:00
pCREATIONDATE ,
pKEYCREATIONDATE , /* Same in seconds since epoch. */
2003-06-05 07:14:21 +00:00
pEXPIREDATE ,
pKEYEXPIRE , /* in n seconds */
pSUBKEYEXPIRE , /* in n seconds */
pPASSPHRASE ,
pPASSPHRASE_DEK ,
2003-07-01 08:34:45 +00:00
pPASSPHRASE_S2K ,
2006-04-19 11:26:11 +00:00
pSERIALNO ,
2010-11-17 13:21:24 +00:00
pCARDBACKUPKEY ,
2006-06-27 14:30:59 +00:00
pHANDLE ,
pKEYSERVER
2003-06-05 07:14:21 +00:00
} ;
struct para_data_s {
struct para_data_s * next ;
int lnr ;
enum para_name key ;
union {
DEK * dek ;
STRING2KEY * s2k ;
u32 expire ;
2007-07-05 16:58:19 +00:00
u32 creation ;
2003-06-05 07:14:21 +00:00
unsigned int usage ;
struct revocation_key revkey ;
char value [ 1 ] ;
} u ;
} ;
2010-11-17 13:21:24 +00:00
struct output_control_s
{
int lnr ;
int dryrun ;
int ask_passphrase ;
unsigned int keygen_flags ;
int use_files ;
struct {
char * fname ;
char * newfname ;
IOBUF stream ;
armor_filter_context_t * afx ;
} pub ;
2003-06-05 07:14:21 +00:00
} ;
struct opaque_data_usage_and_pk {
unsigned int usage ;
PKT_public_key * pk ;
} ;
static int prefs_initialized = 0 ;
static byte sym_prefs [ MAX_PREFS ] ;
static int nsym_prefs ;
static byte hash_prefs [ MAX_PREFS ] ;
static int nhash_prefs ;
static byte zip_prefs [ MAX_PREFS ] ;
static int nzip_prefs ;
static int mdc_available , ks_modify ;
static void do_generate_keypair ( struct para_data_s * para ,
2006-04-19 11:26:11 +00:00
struct output_control_s * outctrl , int card ) ;
2010-04-20 17:57:50 +00:00
static int write_keyblock ( iobuf_t out , kbnode_t node ) ;
2010-11-17 13:21:24 +00:00
static gpg_error_t gen_card_key ( int algo , int keyno , int is_primary ,
kbnode_t pub_root ,
u32 * timestamp , u32 expireval ) ;
2006-04-19 11:26:11 +00:00
static int gen_card_key_with_backup ( int algo , int keyno , int is_primary ,
2010-04-20 17:57:50 +00:00
kbnode_t pub_root , u32 timestamp ,
2010-11-17 13:21:24 +00:00
u32 expireval , struct para_data_s * para ) ;
2006-04-19 11:26:11 +00:00
static void
print_status_key_created ( int letter , PKT_public_key * pk , const char * handle )
{
byte array [ MAX_FINGERPRINT_LEN ] , * s ;
char * buf , * p ;
size_t i , n ;
if ( ! handle )
handle = " " ;
buf = xmalloc ( MAX_FINGERPRINT_LEN * 2 + 31 + strlen ( handle ) + 1 ) ;
p = buf ;
if ( letter | | pk )
{
* p + + = letter ;
* p + + = ' ' ;
fingerprint_from_pk ( pk , array , & n ) ;
s = array ;
for ( i = 0 ; i < n ; i + + , s + + , p + = 2 )
sprintf ( p , " %02X " , * s ) ;
}
if ( * handle )
{
* p + + = ' ' ;
for ( i = 0 ; handle [ i ] & & i < 100 ; i + + )
* p + + = isspace ( ( unsigned int ) handle [ i ] ) ? ' _ ' : handle [ i ] ;
}
* p = 0 ;
write_status_text ( ( letter | | pk ) ? STATUS_KEY_CREATED : STATUS_KEY_NOT_CREATED ,
buf ) ;
xfree ( buf ) ;
}
static void
print_status_key_not_created ( const char * handle )
{
print_status_key_created ( 0 , NULL , handle ) ;
}
2003-06-27 20:53:09 +00:00
2003-06-05 07:14:21 +00:00
static void
write_uid ( KBNODE root , const char * s )
{
2006-04-19 11:26:11 +00:00
PACKET * pkt = xmalloc_clear ( sizeof * pkt ) ;
2003-06-05 07:14:21 +00:00
size_t n = strlen ( s ) ;
pkt - > pkttype = PKT_USER_ID ;
2006-04-19 11:26:11 +00:00
pkt - > pkt . user_id = xmalloc_clear ( sizeof * pkt - > pkt . user_id + n - 1 ) ;
2003-06-05 07:14:21 +00:00
pkt - > pkt . user_id - > len = n ;
pkt - > pkt . user_id - > ref = 1 ;
strcpy ( pkt - > pkt . user_id - > name , s ) ;
add_kbnode ( root , new_kbnode ( pkt ) ) ;
}
static void
do_add_key_flags ( PKT_signature * sig , unsigned int use )
{
byte buf [ 1 ] ;
buf [ 0 ] = 0 ;
2006-04-19 11:26:11 +00:00
/* The spec says that all primary keys MUST be able to certify. */
if ( sig - > sig_class ! = 0x18 )
buf [ 0 ] | = 0x01 ;
2003-06-05 07:14:21 +00:00
if ( use & PUBKEY_USAGE_SIG )
2006-04-19 11:26:11 +00:00
buf [ 0 ] | = 0x02 ;
2003-06-05 07:14:21 +00:00
if ( use & PUBKEY_USAGE_ENC )
buf [ 0 ] | = 0x04 | 0x08 ;
2003-09-05 07:40:18 +00:00
if ( use & PUBKEY_USAGE_AUTH )
buf [ 0 ] | = 0x20 ;
2006-04-19 11:26:11 +00:00
if ( ! buf [ 0 ] )
return ;
2003-06-05 07:14:21 +00:00
build_sig_subpkt ( sig , SIGSUBPKT_KEY_FLAGS , buf , 1 ) ;
}
int
2010-04-20 17:57:50 +00:00
keygen_add_key_expire ( PKT_signature * sig , void * opaque )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
PKT_public_key * pk = opaque ;
byte buf [ 8 ] ;
u32 u ;
if ( pk - > expiredate )
{
if ( pk - > expiredate > pk - > timestamp )
u = pk - > expiredate - pk - > timestamp ;
else
u = 1 ;
buf [ 0 ] = ( u > > 24 ) & 0xff ;
buf [ 1 ] = ( u > > 16 ) & 0xff ;
buf [ 2 ] = ( u > > 8 ) & 0xff ;
buf [ 3 ] = u & 0xff ;
build_sig_subpkt ( sig , SIGSUBPKT_KEY_EXPIRE , buf , 4 ) ;
}
else
{
/* Make sure we don't leave a key expiration subpacket lying
around */
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_KEY_EXPIRE ) ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
return 0 ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
2003-06-05 07:14:21 +00:00
static int
keygen_add_key_flags_and_expire ( PKT_signature * sig , void * opaque )
{
2010-04-20 17:57:50 +00:00
struct opaque_data_usage_and_pk * oduap = opaque ;
do_add_key_flags ( sig , oduap - > usage ) ;
return keygen_add_key_expire ( sig , oduap - > pk ) ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
2003-06-05 07:14:21 +00:00
static int
set_one_pref ( int val , int type , const char * item , byte * buf , int * nbuf )
{
int i ;
for ( i = 0 ; i < * nbuf ; i + + )
if ( buf [ i ] = = val )
{
log_info ( _ ( " preference `%s' duplicated \n " ) , item ) ;
return - 1 ;
}
if ( * nbuf > = MAX_PREFS )
{
if ( type = = 1 )
log_info ( _ ( " too many cipher preferences \n " ) ) ;
else if ( type = = 2 )
log_info ( _ ( " too many digest preferences \n " ) ) ;
else if ( type = = 3 )
log_info ( _ ( " too many compression preferences \n " ) ) ;
else
BUG ( ) ;
return - 1 ;
}
buf [ ( * nbuf ) + + ] = val ;
return 0 ;
}
/*
* Parse the supplied string and use it to set the standard
* preferences . The string may be in a form like the one printed by
* " pref " ( something like : " S10 S3 H3 H2 Z2 Z1 " ) or the actual
* cipher / hash / compress names . Use NULL to set the default
* preferences . Returns : 0 = okay
*/
int
keygen_set_std_prefs ( const char * string , int personal )
{
byte sym [ MAX_PREFS ] , hash [ MAX_PREFS ] , zip [ MAX_PREFS ] ;
int nsym = 0 , nhash = 0 , nzip = 0 , val , rc = 0 ;
int mdc = 1 , modify = 0 ; /* mdc defaults on, modify defaults off. */
2009-07-09 08:52:31 +00:00
char dummy_string [ 20 * 4 + 1 ] ; /* Enough for 20 items. */
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
if ( ! string | | ! ascii_strcasecmp ( string , " default " ) )
{
if ( opt . def_preference_list )
string = opt . def_preference_list ;
else
{
2010-04-26 11:53:14 +00:00
int any_compress = 0 ;
2006-04-19 11:26:11 +00:00
dummy_string [ 0 ] = ' \0 ' ;
/* The rationale why we use the order AES256,192,128 is
for compatibility reasons with PGP . If gpg would
define AES128 first , we would get the somewhat
confusing situation :
gpg - r pgpkey - r gpgkey - - - gives - - > AES256
gpg - r gpgkey - r pgpkey - - - gives - - > AES
Note that by using - - personal - cipher - preferences it is
possible to prefer AES128 .
*/
/* Make sure we do not add more than 15 items here, as we
could overflow the size of dummy_string . We currently
have at most 12. */
2006-04-19 13:24:36 +00:00
if ( ! openpgp_cipher_test_algo ( CIPHER_ALGO_AES256 ) )
2006-04-19 11:26:11 +00:00
strcat ( dummy_string , " S9 " ) ;
2006-04-19 13:24:36 +00:00
if ( ! openpgp_cipher_test_algo ( CIPHER_ALGO_AES192 ) )
2006-04-19 11:26:11 +00:00
strcat ( dummy_string , " S8 " ) ;
2006-04-19 13:24:36 +00:00
if ( ! openpgp_cipher_test_algo ( CIPHER_ALGO_AES ) )
2006-04-19 11:26:11 +00:00
strcat ( dummy_string , " S7 " ) ;
2006-04-19 13:24:36 +00:00
if ( ! openpgp_cipher_test_algo ( CIPHER_ALGO_CAST5 ) )
2006-04-19 11:26:11 +00:00
strcat ( dummy_string , " S3 " ) ;
strcat ( dummy_string , " S2 " ) ; /* 3DES */
/* If we have it, IDEA goes *after* 3DES so it won't be
used unless we ' re encrypting along with a V3 key .
Ideally , we would only put the S1 preference in if the
key was RSA and < = 2048 bits , as that is what won ' t
break PGP2 , but that is difficult with the current
code , and not really worth checking as a non - RSA < = 2048
bit key wouldn ' t be usable by PGP2 anyway . - dms */
2006-04-19 13:24:36 +00:00
if ( ! openpgp_cipher_test_algo ( CIPHER_ALGO_IDEA ) )
2006-04-19 11:26:11 +00:00
strcat ( dummy_string , " S1 " ) ;
2009-07-09 08:52:31 +00:00
/* The default hash algo order is:
SHA - 256 , SHA - 1 , SHA - 384 , SHA - 512 , SHA - 224.
Ordering SHA - 1 before SHA - 384 might be viewed as a bit
strange ; it is done because we expect that soon enough
SHA - 3 will be available and at that point there should
be no more need for SHA - 384 etc . Anyway this order is
just a default and can easily be changed by a config
option . */
if ( ! openpgp_md_test_algo ( DIGEST_ALGO_SHA256 ) )
strcat ( dummy_string , " H8 " ) ;
strcat ( dummy_string , " H2 " ) ; /* SHA-1 */
if ( ! openpgp_md_test_algo ( DIGEST_ALGO_SHA384 ) )
strcat ( dummy_string , " H9 " ) ;
if ( ! openpgp_md_test_algo ( DIGEST_ALGO_SHA512 ) )
strcat ( dummy_string , " H10 " ) ;
if ( ! openpgp_md_test_algo ( DIGEST_ALGO_SHA224 ) )
strcat ( dummy_string , " H11 " ) ;
2006-04-19 11:26:11 +00:00
2010-04-14 14:39:16 +00:00
if ( ! check_compress_algo ( COMPRESS_ALGO_ZLIB ) )
2010-04-26 11:53:14 +00:00
{
strcat ( dummy_string , " Z2 " ) ;
any_compress = 1 ;
}
2006-04-19 11:26:11 +00:00
if ( ! check_compress_algo ( COMPRESS_ALGO_BZIP2 ) )
2010-04-26 11:53:14 +00:00
{
strcat ( dummy_string , " Z3 " ) ;
any_compress = 1 ;
}
2006-04-19 11:26:11 +00:00
2010-04-14 14:39:16 +00:00
if ( ! check_compress_algo ( COMPRESS_ALGO_ZIP ) )
2010-04-26 11:53:14 +00:00
{
strcat ( dummy_string , " Z1 " ) ;
any_compress = 1 ;
}
/* In case we have no compress algo at all, declare that
we prefer no compresssion . */
if ( ! any_compress )
strcat ( dummy_string , " Z0 " ) ;
/* Remove the trailing space. */
if ( * dummy_string & & dummy_string [ strlen ( dummy_string ) - 1 ] = = ' ' )
dummy_string [ strlen ( dummy_string ) - 1 ] = 0 ;
2006-04-19 11:26:11 +00:00
string = dummy_string ;
}
}
2003-06-05 07:14:21 +00:00
else if ( ! ascii_strcasecmp ( string , " none " ) )
string = " " ;
if ( strlen ( string ) )
{
char * tok , * prefstring ;
2006-04-19 11:26:11 +00:00
prefstring = xstrdup ( string ) ; /* need a writable string! */
2003-06-05 07:14:21 +00:00
while ( ( tok = strsep ( & prefstring , " , " ) ) )
{
2006-05-24 11:12:28 +00:00
if ( ( val = string_to_cipher_algo ( tok ) ) )
2003-06-05 07:14:21 +00:00
{
if ( set_one_pref ( val , 1 , tok , sym , & nsym ) )
rc = - 1 ;
}
2006-05-24 11:12:28 +00:00
else if ( ( val = string_to_digest_algo ( tok ) ) )
2003-06-05 07:14:21 +00:00
{
if ( set_one_pref ( val , 2 , tok , hash , & nhash ) )
rc = - 1 ;
}
else if ( ( val = string_to_compress_algo ( tok ) ) > - 1 )
{
if ( set_one_pref ( val , 3 , tok , zip , & nzip ) )
rc = - 1 ;
}
else if ( ascii_strcasecmp ( tok , " mdc " ) = = 0 )
mdc = 1 ;
else if ( ascii_strcasecmp ( tok , " no-mdc " ) = = 0 )
mdc = 0 ;
else if ( ascii_strcasecmp ( tok , " ks-modify " ) = = 0 )
modify = 1 ;
else if ( ascii_strcasecmp ( tok , " no-ks-modify " ) = = 0 )
modify = 0 ;
else
{
log_info ( _ ( " invalid item `%s' in preference string \n " ) , tok ) ;
/* Complain if IDEA is not available. */
if ( ascii_strcasecmp ( tok , " s1 " ) = = 0
| | ascii_strcasecmp ( tok , " idea " ) = = 0 )
idea_cipher_warn ( 1 ) ;
rc = - 1 ;
}
}
2006-04-19 11:26:11 +00:00
xfree ( prefstring ) ;
2003-06-05 07:14:21 +00:00
}
if ( ! rc )
{
if ( personal )
{
if ( personal = = PREFTYPE_SYM )
{
2006-04-19 11:26:11 +00:00
xfree ( opt . personal_cipher_prefs ) ;
2003-06-05 07:14:21 +00:00
if ( nsym = = 0 )
opt . personal_cipher_prefs = NULL ;
else
{
int i ;
opt . personal_cipher_prefs =
2006-04-19 11:26:11 +00:00
xmalloc ( sizeof ( prefitem_t * ) * ( nsym + 1 ) ) ;
2003-06-05 07:14:21 +00:00
for ( i = 0 ; i < nsym ; i + + )
{
opt . personal_cipher_prefs [ i ] . type = PREFTYPE_SYM ;
opt . personal_cipher_prefs [ i ] . value = sym [ i ] ;
}
opt . personal_cipher_prefs [ i ] . type = PREFTYPE_NONE ;
opt . personal_cipher_prefs [ i ] . value = 0 ;
}
}
else if ( personal = = PREFTYPE_HASH )
{
2006-04-19 11:26:11 +00:00
xfree ( opt . personal_digest_prefs ) ;
2003-06-05 07:14:21 +00:00
if ( nhash = = 0 )
opt . personal_digest_prefs = NULL ;
else
{
int i ;
opt . personal_digest_prefs =
2006-04-19 11:26:11 +00:00
xmalloc ( sizeof ( prefitem_t * ) * ( nhash + 1 ) ) ;
2003-06-05 07:14:21 +00:00
for ( i = 0 ; i < nhash ; i + + )
{
opt . personal_digest_prefs [ i ] . type = PREFTYPE_HASH ;
opt . personal_digest_prefs [ i ] . value = hash [ i ] ;
}
opt . personal_digest_prefs [ i ] . type = PREFTYPE_NONE ;
opt . personal_digest_prefs [ i ] . value = 0 ;
}
}
else if ( personal = = PREFTYPE_ZIP )
{
2006-04-19 11:26:11 +00:00
xfree ( opt . personal_compress_prefs ) ;
2003-06-05 07:14:21 +00:00
if ( nzip = = 0 )
opt . personal_compress_prefs = NULL ;
else
{
int i ;
opt . personal_compress_prefs =
2006-04-19 11:26:11 +00:00
xmalloc ( sizeof ( prefitem_t * ) * ( nzip + 1 ) ) ;
2003-06-05 07:14:21 +00:00
for ( i = 0 ; i < nzip ; i + + )
{
opt . personal_compress_prefs [ i ] . type = PREFTYPE_ZIP ;
opt . personal_compress_prefs [ i ] . value = zip [ i ] ;
}
opt . personal_compress_prefs [ i ] . type = PREFTYPE_NONE ;
opt . personal_compress_prefs [ i ] . value = 0 ;
}
}
}
else
{
memcpy ( sym_prefs , sym , ( nsym_prefs = nsym ) ) ;
memcpy ( hash_prefs , hash , ( nhash_prefs = nhash ) ) ;
memcpy ( zip_prefs , zip , ( nzip_prefs = nzip ) ) ;
mdc_available = mdc ;
ks_modify = modify ;
prefs_initialized = 1 ;
}
}
return rc ;
}
/* Return a fake user ID containing the preferences. Caller must
free . */
2009-07-09 08:52:31 +00:00
PKT_user_id *
keygen_get_std_prefs ( void )
2003-06-05 07:14:21 +00:00
{
int i , j = 0 ;
2006-04-19 11:26:11 +00:00
PKT_user_id * uid = xmalloc_clear ( sizeof ( PKT_user_id ) ) ;
2003-06-05 07:14:21 +00:00
if ( ! prefs_initialized )
keygen_set_std_prefs ( NULL , 0 ) ;
2006-04-19 11:26:11 +00:00
uid - > ref = 1 ;
uid - > prefs = xmalloc ( ( sizeof ( prefitem_t * ) *
2003-06-05 07:14:21 +00:00
( nsym_prefs + nhash_prefs + nzip_prefs + 1 ) ) ) ;
for ( i = 0 ; i < nsym_prefs ; i + + , j + + )
{
uid - > prefs [ j ] . type = PREFTYPE_SYM ;
uid - > prefs [ j ] . value = sym_prefs [ i ] ;
}
for ( i = 0 ; i < nhash_prefs ; i + + , j + + )
{
uid - > prefs [ j ] . type = PREFTYPE_HASH ;
uid - > prefs [ j ] . value = hash_prefs [ i ] ;
}
for ( i = 0 ; i < nzip_prefs ; i + + , j + + )
{
uid - > prefs [ j ] . type = PREFTYPE_ZIP ;
uid - > prefs [ j ] . value = zip_prefs [ i ] ;
}
uid - > prefs [ j ] . type = PREFTYPE_NONE ;
uid - > prefs [ j ] . value = 0 ;
2006-04-19 11:26:11 +00:00
uid - > flags . mdc = mdc_available ;
uid - > flags . ks_modify = ks_modify ;
2003-06-05 07:14:21 +00:00
return uid ;
}
static void
add_feature_mdc ( PKT_signature * sig , int enabled )
{
const byte * s ;
size_t n ;
int i ;
char * buf ;
s = parse_sig_subpkt ( sig - > hashed , SIGSUBPKT_FEATURES , & n ) ;
/* Already set or cleared */
if ( s & & n & &
( ( enabled & & ( s [ 0 ] & 0x01 ) ) | | ( ! enabled & & ! ( s [ 0 ] & 0x01 ) ) ) )
return ;
if ( ! s | | ! n ) { /* create a new one */
n = 1 ;
2006-04-19 11:26:11 +00:00
buf = xmalloc_clear ( n ) ;
2003-06-05 07:14:21 +00:00
}
else {
2003-06-18 19:56:13 +00:00
buf = xmalloc ( n ) ;
2003-06-05 07:14:21 +00:00
memcpy ( buf , s , n ) ;
}
if ( enabled )
buf [ 0 ] | = 0x01 ; /* MDC feature */
else
buf [ 0 ] & = ~ 0x01 ;
/* Are there any bits set? */
for ( i = 0 ; i < n ; i + + )
if ( buf [ i ] ! = 0 )
break ;
if ( i = = n )
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_FEATURES ) ;
else
build_sig_subpkt ( sig , SIGSUBPKT_FEATURES , buf , n ) ;
2003-06-18 19:56:13 +00:00
xfree ( buf ) ;
2003-06-05 07:14:21 +00:00
}
static void
add_keyserver_modify ( PKT_signature * sig , int enabled )
{
const byte * s ;
size_t n ;
int i ;
char * buf ;
/* The keyserver modify flag is a negative flag (i.e. no-modify) */
enabled = ! enabled ;
s = parse_sig_subpkt ( sig - > hashed , SIGSUBPKT_KS_FLAGS , & n ) ;
/* Already set or cleared */
if ( s & & n & &
( ( enabled & & ( s [ 0 ] & 0x80 ) ) | | ( ! enabled & & ! ( s [ 0 ] & 0x80 ) ) ) )
return ;
if ( ! s | | ! n ) { /* create a new one */
n = 1 ;
2006-04-19 11:26:11 +00:00
buf = xmalloc_clear ( n ) ;
2003-06-05 07:14:21 +00:00
}
else {
2003-06-18 19:56:13 +00:00
buf = xmalloc ( n ) ;
2003-06-05 07:14:21 +00:00
memcpy ( buf , s , n ) ;
}
if ( enabled )
buf [ 0 ] | = 0x80 ; /* no-modify flag */
else
buf [ 0 ] & = ~ 0x80 ;
/* Are there any bits set? */
for ( i = 0 ; i < n ; i + + )
if ( buf [ i ] ! = 0 )
break ;
if ( i = = n )
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_KS_FLAGS ) ;
else
build_sig_subpkt ( sig , SIGSUBPKT_KS_FLAGS , buf , n ) ;
2003-06-18 19:56:13 +00:00
xfree ( buf ) ;
2003-06-05 07:14:21 +00:00
}
2008-10-20 13:53:23 +00:00
2003-06-05 07:14:21 +00:00
int
2008-10-20 13:53:23 +00:00
keygen_upd_std_prefs ( PKT_signature * sig , void * opaque )
2003-06-05 07:14:21 +00:00
{
2008-10-20 13:53:23 +00:00
( void ) opaque ;
if ( ! prefs_initialized )
keygen_set_std_prefs ( NULL , 0 ) ;
if ( nsym_prefs )
build_sig_subpkt ( sig , SIGSUBPKT_PREF_SYM , sym_prefs , nsym_prefs ) ;
else
{
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_PREF_SYM ) ;
delete_sig_subpkt ( sig - > unhashed , SIGSUBPKT_PREF_SYM ) ;
}
if ( nhash_prefs )
build_sig_subpkt ( sig , SIGSUBPKT_PREF_HASH , hash_prefs , nhash_prefs ) ;
else
{
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_PREF_HASH ) ;
delete_sig_subpkt ( sig - > unhashed , SIGSUBPKT_PREF_HASH ) ;
}
2003-06-05 07:14:21 +00:00
2008-10-20 13:53:23 +00:00
if ( nzip_prefs )
build_sig_subpkt ( sig , SIGSUBPKT_PREF_COMPR , zip_prefs , nzip_prefs ) ;
else
{
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_PREF_COMPR ) ;
delete_sig_subpkt ( sig - > unhashed , SIGSUBPKT_PREF_COMPR ) ;
}
/* Make sure that the MDC feature flag is set if needed. */
add_feature_mdc ( sig , mdc_available ) ;
add_keyserver_modify ( sig , ks_modify ) ;
keygen_add_keyserver_url ( sig , NULL ) ;
2003-06-05 07:14:21 +00:00
2008-10-20 13:53:23 +00:00
return 0 ;
2003-06-05 07:14:21 +00:00
}
/****************
* Add preference to the self signature packet .
* This is only called for packets with version > 3.
*/
int
2010-04-20 17:57:50 +00:00
keygen_add_std_prefs ( PKT_signature * sig , void * opaque )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
PKT_public_key * pk = opaque ;
do_add_key_flags ( sig , pk - > pubkey_usage ) ;
keygen_add_key_expire ( sig , opaque ) ;
keygen_upd_std_prefs ( sig , opaque ) ;
keygen_add_keyserver_url ( sig , NULL ) ;
return 0 ;
2003-06-05 07:14:21 +00:00
}
2003-09-23 17:48:33 +00:00
int
keygen_add_keyserver_url ( PKT_signature * sig , void * opaque )
{
const char * url = opaque ;
2006-06-27 14:30:59 +00:00
if ( ! url )
url = opt . def_keyserver_url ;
2006-04-19 11:26:11 +00:00
if ( url )
build_sig_subpkt ( sig , SIGSUBPKT_PREF_KS , url , strlen ( url ) ) ;
else
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_PREF_KS ) ;
2003-09-23 17:48:33 +00:00
return 0 ;
}
2006-04-19 11:26:11 +00:00
int
keygen_add_notations ( PKT_signature * sig , void * opaque )
{
struct notation * notation ;
/* We always start clean */
delete_sig_subpkt ( sig - > hashed , SIGSUBPKT_NOTATION ) ;
delete_sig_subpkt ( sig - > unhashed , SIGSUBPKT_NOTATION ) ;
sig - > flags . notation = 0 ;
for ( notation = opaque ; notation ; notation = notation - > next )
if ( ! notation - > flags . ignore )
{
unsigned char * buf ;
unsigned int n1 , n2 ;
n1 = strlen ( notation - > name ) ;
if ( notation - > altvalue )
n2 = strlen ( notation - > altvalue ) ;
else if ( notation - > bdat )
n2 = notation - > blen ;
else
n2 = strlen ( notation - > value ) ;
buf = xmalloc ( 8 + n1 + n2 ) ;
/* human readable or not */
buf [ 0 ] = notation - > bdat ? 0 : 0x80 ;
buf [ 1 ] = buf [ 2 ] = buf [ 3 ] = 0 ;
buf [ 4 ] = n1 > > 8 ;
buf [ 5 ] = n1 ;
buf [ 6 ] = n2 > > 8 ;
buf [ 7 ] = n2 ;
memcpy ( buf + 8 , notation - > name , n1 ) ;
if ( notation - > altvalue )
memcpy ( buf + 8 + n1 , notation - > altvalue , n2 ) ;
else if ( notation - > bdat )
memcpy ( buf + 8 + n1 , notation - > bdat , n2 ) ;
else
memcpy ( buf + 8 + n1 , notation - > value , n2 ) ;
build_sig_subpkt ( sig , SIGSUBPKT_NOTATION |
( notation - > flags . critical ? SIGSUBPKT_FLAG_CRITICAL : 0 ) ,
buf , 8 + n1 + n2 ) ;
xfree ( buf ) ;
}
return 0 ;
}
2003-09-23 17:48:33 +00:00
2003-06-05 07:14:21 +00:00
int
2010-04-20 17:57:50 +00:00
keygen_add_revkey ( PKT_signature * sig , void * opaque )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
struct revocation_key * revkey = opaque ;
2003-06-05 07:14:21 +00:00
byte buf [ 2 + MAX_FINGERPRINT_LEN ] ;
2010-04-20 17:57:50 +00:00
buf [ 0 ] = revkey - > class ;
buf [ 1 ] = revkey - > algid ;
memcpy ( & buf [ 2 ] , revkey - > fpr , MAX_FINGERPRINT_LEN ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
build_sig_subpkt ( sig , SIGSUBPKT_REV_KEY , buf , 2 + MAX_FINGERPRINT_LEN ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
/* All sigs with revocation keys set are nonrevocable. */
sig - > flags . revocable = 0 ;
2003-06-05 07:14:21 +00:00
buf [ 0 ] = 0 ;
2010-04-20 17:57:50 +00:00
build_sig_subpkt ( sig , SIGSUBPKT_REVOCABLE , buf , 1 ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
parse_revkeys ( sig ) ;
2003-06-05 07:14:21 +00:00
return 0 ;
}
2007-07-05 16:58:19 +00:00
/* Create a back-signature. If TIMESTAMP is not NULL, use it for the
signature creation time . */
2010-04-20 17:57:50 +00:00
gpg_error_t
make_backsig ( PKT_signature * sig , PKT_public_key * pk ,
PKT_public_key * sub_pk , PKT_public_key * sub_psk ,
2010-09-01 12:49:05 +00:00
u32 timestamp , const char * cache_nonce )
2006-04-19 11:26:11 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2006-04-19 11:26:11 +00:00
PKT_signature * backsig ;
2010-04-20 17:57:50 +00:00
cache_public_key ( sub_pk ) ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
err = make_keysig_packet ( & backsig , pk , NULL , sub_pk , sub_psk , 0x19 ,
2010-09-01 12:49:05 +00:00
0 , 0 , timestamp , 0 , NULL , NULL , cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( err )
log_error ( " make_keysig_packet failed for backsig: %s \n " , g10_errstr ( err ) ) ;
2006-04-19 11:26:11 +00:00
else
{
2007-07-05 16:58:19 +00:00
/* Get it into a binary packed form. */
2010-04-20 17:57:50 +00:00
IOBUF backsig_out = iobuf_temp ( ) ;
2006-04-19 11:26:11 +00:00
PACKET backsig_pkt ;
2010-04-20 17:57:50 +00:00
init_packet ( & backsig_pkt ) ;
backsig_pkt . pkttype = PKT_SIGNATURE ;
backsig_pkt . pkt . signature = backsig ;
err = build_packet ( backsig_out , & backsig_pkt ) ;
free_packet ( & backsig_pkt ) ;
if ( err )
log_error ( " build_packet failed for backsig: %s \n " , g10_errstr ( err ) ) ;
2006-04-19 11:26:11 +00:00
else
{
2010-04-20 17:57:50 +00:00
size_t pktlen = 0 ;
byte * buf = iobuf_get_temp_buffer ( backsig_out ) ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
/* Remove the packet header. */
2006-04-19 11:26:11 +00:00
if ( buf [ 0 ] & 0x40 )
{
2010-04-20 17:57:50 +00:00
if ( buf [ 1 ] < 192 )
2006-04-19 11:26:11 +00:00
{
2010-04-20 17:57:50 +00:00
pktlen = buf [ 1 ] ;
buf + = 2 ;
}
else if ( buf [ 1 ] < 224 )
2006-04-19 11:26:11 +00:00
{
2010-04-20 17:57:50 +00:00
pktlen = ( buf [ 1 ] - 192 ) * 256 ;
pktlen + = buf [ 2 ] + 192 ;
buf + = 3 ;
2006-04-19 11:26:11 +00:00
}
2010-04-20 17:57:50 +00:00
else if ( buf [ 1 ] = = 255 )
2006-04-19 11:26:11 +00:00
{
2010-04-20 17:57:50 +00:00
pktlen = buf [ 2 ] < < 24 ;
pktlen | = buf [ 3 ] < < 16 ;
pktlen | = buf [ 4 ] < < 8 ;
pktlen | = buf [ 5 ] ;
buf + = 6 ;
2006-04-19 11:26:11 +00:00
}
else
2010-04-20 17:57:50 +00:00
BUG ( ) ;
2006-04-19 11:26:11 +00:00
}
else
{
2010-04-20 17:57:50 +00:00
int mark = 1 ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
switch ( buf [ 0 ] & 3 )
2006-04-19 11:26:11 +00:00
{
case 3 :
2010-04-20 17:57:50 +00:00
BUG ( ) ;
2006-04-19 11:26:11 +00:00
break ;
case 2 :
2010-04-20 17:57:50 +00:00
pktlen = buf [ mark + + ] < < 24 ;
pktlen | = buf [ mark + + ] < < 16 ;
2006-04-19 11:26:11 +00:00
case 1 :
2010-04-20 17:57:50 +00:00
pktlen | = buf [ mark + + ] < < 8 ;
2006-04-19 11:26:11 +00:00
case 0 :
2010-04-20 17:57:50 +00:00
pktlen | = buf [ mark + + ] ;
2006-04-19 11:26:11 +00:00
}
2010-04-20 17:57:50 +00:00
buf + = mark ;
2006-04-19 11:26:11 +00:00
}
2007-07-05 16:58:19 +00:00
/* Now make the binary blob into a subpacket. */
2010-04-20 17:57:50 +00:00
build_sig_subpkt ( sig , SIGSUBPKT_SIGNATURE , buf , pktlen ) ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
iobuf_close ( backsig_out ) ;
2006-04-19 11:26:11 +00:00
}
}
2010-04-20 17:57:50 +00:00
return err ;
2006-04-19 11:26:11 +00:00
}
2010-04-20 17:57:50 +00:00
/* Write a direct key signature to the first key in ROOT using the key
PSK . REVKEY is describes the direct key signature and TIMESTAMP is
the timestamp to set on the signature . */
static gpg_error_t
write_direct_sig ( KBNODE root , PKT_public_key * psk ,
2010-09-01 12:49:05 +00:00
struct revocation_key * revkey , u32 timestamp ,
const char * cache_nonce )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2007-07-05 16:58:19 +00:00
PACKET * pkt ;
PKT_signature * sig ;
KBNODE node ;
PKT_public_key * pk ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
if ( opt . verbose )
log_info ( _ ( " writing direct signature \n " ) ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
/* Get the pk packet from the pub_tree. */
2010-04-20 17:57:50 +00:00
node = find_kbnode ( root , PKT_PUBLIC_KEY ) ;
if ( ! node )
BUG ( ) ;
2007-07-05 16:58:19 +00:00
pk = node - > pkt - > pkt . public_key ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
/* We have to cache the key, so that the verification of the
signature creation is able to retrieve the public key . */
cache_public_key ( pk ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
/* Make the signature. */
2010-04-20 17:57:50 +00:00
err = make_keysig_packet ( & sig , pk , NULL , NULL , psk , 0x1F ,
0 , 0 , timestamp , 0 ,
2010-09-01 12:49:05 +00:00
keygen_add_revkey , revkey , cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( err )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
log_error ( " make_keysig_packet failed: %s \n " , g10_errstr ( err ) ) ;
return err ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
pkt = xmalloc_clear ( sizeof * pkt ) ;
2007-07-05 16:58:19 +00:00
pkt - > pkttype = PKT_SIGNATURE ;
pkt - > pkt . signature = sig ;
2010-04-20 17:57:50 +00:00
add_kbnode ( root , new_kbnode ( pkt ) ) ;
return err ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
/* Write a self-signature to the first user id in ROOT using the key
PSK . USE and TIMESTAMP give the extra data we need for the
signature . */
static gpg_error_t
write_selfsigs ( KBNODE root , PKT_public_key * psk ,
2010-09-01 12:49:05 +00:00
unsigned int use , u32 timestamp , const char * cache_nonce )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2007-07-05 16:58:19 +00:00
PACKET * pkt ;
PKT_signature * sig ;
PKT_user_id * uid ;
KBNODE node ;
PKT_public_key * pk ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
if ( opt . verbose )
log_info ( _ ( " writing self signature \n " ) ) ;
2007-07-05 16:58:19 +00:00
/* Get the uid packet from the list. */
2010-04-20 17:57:50 +00:00
node = find_kbnode ( root , PKT_USER_ID ) ;
if ( ! node )
2007-07-05 16:58:19 +00:00
BUG ( ) ; /* No user id packet in tree. */
uid = node - > pkt - > pkt . user_id ;
/* Get the pk packet from the pub_tree. */
2010-04-20 17:57:50 +00:00
node = find_kbnode ( root , PKT_PUBLIC_KEY ) ;
if ( ! node )
2007-07-05 16:58:19 +00:00
BUG ( ) ;
pk = node - > pkt - > pkt . public_key ;
2010-04-20 17:57:50 +00:00
/* The usage has not yet been set - do it now. */
2007-07-05 16:58:19 +00:00
pk - > pubkey_usage = use ;
/* We have to cache the key, so that the verification of the
signature creation is able to retrieve the public key . */
cache_public_key ( pk ) ;
/* Make the signature. */
2010-04-20 17:57:50 +00:00
err = make_keysig_packet ( & sig , pk , uid , NULL , psk , 0x13 ,
0 , 0 , timestamp , 0 ,
2010-09-01 12:49:05 +00:00
keygen_add_std_prefs , pk , cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( err )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
log_error ( " make_keysig_packet failed: %s \n " , g10_errstr ( err ) ) ;
return err ;
2007-07-05 16:58:19 +00:00
}
2010-04-20 17:57:50 +00:00
pkt = xmalloc_clear ( sizeof * pkt ) ;
2007-07-05 16:58:19 +00:00
pkt - > pkttype = PKT_SIGNATURE ;
pkt - > pkt . signature = sig ;
2010-04-20 17:57:50 +00:00
add_kbnode ( root , new_kbnode ( pkt ) ) ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
/* Write the key binding signature. If TIMESTAMP is not NULL use the
2010-04-20 17:57:50 +00:00
signature creation time . PRI_PSK is the key use for signing .
SUB_PSK is a key used to create a back - signature ; that one is only
used if USE has the PUBKEY_USAGE_SIG capability . */
2003-06-05 07:14:21 +00:00
static int
2010-04-20 17:57:50 +00:00
write_keybinding ( KBNODE root , PKT_public_key * pri_psk , PKT_public_key * sub_psk ,
2010-09-01 12:49:05 +00:00
unsigned int use , u32 timestamp , const char * cache_nonce )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2007-07-05 16:58:19 +00:00
PACKET * pkt ;
PKT_signature * sig ;
KBNODE node ;
PKT_public_key * pri_pk , * sub_pk ;
struct opaque_data_usage_and_pk oduap ;
2010-04-20 17:57:50 +00:00
if ( opt . verbose )
2007-07-05 16:58:19 +00:00
log_info ( _ ( " writing key binding signature \n " ) ) ;
2010-04-20 17:57:50 +00:00
/* Get the primary pk packet from the tree. */
node = find_kbnode ( root , PKT_PUBLIC_KEY ) ;
if ( ! node )
2007-07-05 16:58:19 +00:00
BUG ( ) ;
pri_pk = node - > pkt - > pkt . public_key ;
/* We have to cache the key, so that the verification of the
* signature creation is able to retrieve the public key . */
cache_public_key ( pri_pk ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
/* Find the last subkey. */
sub_pk = NULL ;
2010-04-20 17:57:50 +00:00
for ( node = root ; node ; node = node - > next )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
if ( node - > pkt - > pkttype = = PKT_PUBLIC_SUBKEY )
2007-07-05 16:58:19 +00:00
sub_pk = node - > pkt - > pkt . public_key ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
if ( ! sub_pk )
BUG ( ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
/* Make the signature. */
oduap . usage = use ;
oduap . pk = sub_pk ;
2010-04-20 17:57:50 +00:00
err = make_keysig_packet ( & sig , pri_pk , NULL , sub_pk , pri_psk , 0x18 ,
0 , 0 , timestamp , 0 ,
2010-09-01 12:49:05 +00:00
keygen_add_key_flags_and_expire , & oduap ,
cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( err )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
log_error ( " make_keysig_packet failed: %s \n " , g10_errstr ( err ) ) ;
return err ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
/* Make a backsig. */
2010-04-20 17:57:50 +00:00
if ( use & PUBKEY_USAGE_SIG )
2007-07-05 16:58:19 +00:00
{
2010-09-01 12:49:05 +00:00
err = make_backsig ( sig , pri_pk , sub_pk , sub_psk , timestamp , cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( err )
return err ;
2007-07-05 16:58:19 +00:00
}
pkt = xmalloc_clear ( sizeof * pkt ) ;
pkt - > pkttype = PKT_SIGNATURE ;
pkt - > pkt . signature = sig ;
add_kbnode ( root , new_kbnode ( pkt ) ) ;
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
2003-06-05 07:14:21 +00:00
static int
2003-07-29 08:53:19 +00:00
key_from_sexp ( gcry_mpi_t * array , gcry_sexp_t sexp ,
const char * topname , const char * elems )
2003-06-05 07:14:21 +00:00
{
2003-07-29 08:53:19 +00:00
gcry_sexp_t list , l2 ;
const char * s ;
int i , idx ;
int rc = 0 ;
list = gcry_sexp_find_token ( sexp , topname , 0 ) ;
if ( ! list )
return gpg_error ( GPG_ERR_INV_OBJ ) ;
l2 = gcry_sexp_cadr ( list ) ;
gcry_sexp_release ( list ) ;
list = l2 ;
if ( ! list )
return gpg_error ( GPG_ERR_NO_OBJ ) ;
for ( idx = 0 , s = elems ; * s ; s + + , idx + + )
{
l2 = gcry_sexp_find_token ( list , s , 1 ) ;
if ( ! l2 )
{
rc = gpg_error ( GPG_ERR_NO_OBJ ) ; /* required parameter not found */
goto leave ;
}
array [ idx ] = gcry_sexp_nth_mpi ( l2 , 1 , GCRYMPI_FMT_USG ) ;
gcry_sexp_release ( l2 ) ;
if ( ! array [ idx ] )
{
rc = gpg_error ( GPG_ERR_INV_OBJ ) ; /* required parameter invalid */
goto leave ;
}
}
gcry_sexp_release ( list ) ;
leave :
if ( rc )
{
for ( i = 0 ; i < idx ; i + + )
{
2010-10-01 20:33:53 +00:00
gcry_mpi_release ( array [ i ] ) ;
2003-07-29 08:53:19 +00:00
array [ i ] = NULL ;
}
gcry_sexp_release ( list ) ;
}
return rc ;
}
2003-06-05 07:14:21 +00:00
2003-07-29 08:53:19 +00:00
static int
2011-01-05 17:33:17 -08:00
common_key_gen ( const char * keyparms , int algo , const char * algoelem ,
int keygen_flags , char * * cache_nonce_addr , PKT_public_key * * pk_out )
2003-07-29 08:53:19 +00:00
{
2010-04-20 17:57:50 +00:00
int err ;
PKT_public_key * pk ;
gcry_sexp_t s_key ;
2011-01-05 17:33:17 -08:00
* pk_out = NULL ;
2010-04-20 17:57:50 +00:00
2010-10-14 16:34:31 +00:00
err = agent_genkey ( NULL , cache_nonce_addr , keyparms ,
! ! ( keygen_flags & KEYGEN_FLAG_NO_PROTECTION ) , & s_key ) ;
2010-04-20 17:57:50 +00:00
if ( err )
{
log_error ( " agent_genkey failed: %s \n " , gpg_strerror ( err ) ) ;
return err ;
}
pk = xtrycalloc ( 1 , sizeof * pk ) ;
if ( ! pk )
2003-07-29 08:53:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = gpg_error_from_syserror ( ) ;
gcry_sexp_release ( s_key ) ;
return err ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
pk - > version = 4 ;
pk - > pubkey_algo = algo ;
2003-07-29 08:53:19 +00:00
2010-04-20 17:57:50 +00:00
err = key_from_sexp ( pk - > pkey , s_key , " public-key " , algoelem ) ;
if ( err )
{
log_error ( " key_from_sexp failed: %s \n " , gpg_strerror ( err ) ) ;
gcry_sexp_release ( s_key ) ;
free_public_key ( pk ) ;
return err ;
}
gcry_sexp_release ( s_key ) ;
2003-07-29 08:53:19 +00:00
2011-01-05 17:33:17 -08:00
* pk_out = pk ;
2010-04-20 17:57:50 +00:00
return 0 ;
2003-07-29 08:53:19 +00:00
}
2003-06-05 07:14:21 +00:00
2011-01-05 17:33:17 -08:00
/* Common code for the key generation fucntion gen_xxx. */
static int
common_gen ( const char * keyparms , int algo , const char * algoelem ,
kbnode_t pub_root , u32 timestamp , u32 expireval , int is_subkey ,
int keygen_flags , char * * cache_nonce_addr )
{
PKT_public_key * pk ;
int err ;
err = common_key_gen ( keyparms , algo , algoelem , keygen_flags , cache_nonce_addr , & pk ) ;
if ( ! err ) {
PACKET * pkt ;
pk - > timestamp = timestamp ;
if ( expireval )
pk - > expiredate = pk - > timestamp + expireval ;
pkt = xtrycalloc ( 1 , sizeof * pkt ) ;
if ( ! pkt )
{
err = gpg_error_from_syserror ( ) ;
free_public_key ( pk ) ;
return err ;
}
pkt - > pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY ;
pkt - > pkt . public_key = pk ;
add_kbnode ( pub_root , new_kbnode ( pkt ) ) ;
}
return err ;
}
2003-07-29 08:53:19 +00:00
2010-04-20 17:57:50 +00:00
/*
* Generate an Elgamal key .
*/
2003-07-29 08:53:19 +00:00
static int
2010-04-20 17:57:50 +00:00
gen_elg ( int algo , unsigned int nbits , KBNODE pub_root ,
2010-10-14 16:34:31 +00:00
u32 timestamp , u32 expireval , int is_subkey ,
int keygen_flags , char * * cache_nonce_addr )
2003-07-29 08:53:19 +00:00
{
2010-04-20 17:57:50 +00:00
int err ;
char * keyparms ;
char nbitsstr [ 35 ] ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
assert ( is_ELGAMAL ( algo ) ) ;
2006-04-19 11:26:11 +00:00
2007-07-05 16:58:19 +00:00
if ( nbits < 512 )
{
nbits = 1024 ;
log_info ( _ ( " keysize invalid; using %u bits \n " ) , nbits ) ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
if ( ( nbits % 32 ) )
{
nbits = ( ( nbits + 31 ) / 32 ) * 32 ;
log_info ( _ ( " keysize rounded up to %u bits \n " ) , nbits ) ;
2003-07-29 08:53:19 +00:00
}
2010-10-14 16:34:31 +00:00
/* Note that we use transient-key only if no-protection has also
been enabled . */
2010-04-20 17:57:50 +00:00
snprintf ( nbitsstr , sizeof nbitsstr , " %u " , nbits ) ;
2010-10-14 16:34:31 +00:00
keyparms = xtryasprintf ( " (genkey(%s(nbits %zu:%s)%s)) " ,
2010-04-20 17:57:50 +00:00
algo = = GCRY_PK_ELG_E ? " openpgp-elg " :
algo = = GCRY_PK_ELG ? " elg " : " x-oops " ,
2010-10-14 16:34:31 +00:00
strlen ( nbitsstr ) , nbitsstr ,
( ( keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY )
& & ( keygen_flags & KEYGEN_FLAG_NO_PROTECTION ) ) ?
" (transient-key) " : " " ) ;
2010-04-20 17:57:50 +00:00
if ( ! keyparms )
err = gpg_error_from_syserror ( ) ;
else
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = common_gen ( keyparms , algo , " pgy " ,
2010-09-01 09:48:35 +00:00
pub_root , timestamp , expireval , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2010-04-20 17:57:50 +00:00
xfree ( keyparms ) ;
2007-07-05 16:58:19 +00:00
}
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
/*
* Generate an DSA key
2003-06-05 07:14:21 +00:00
*/
2010-04-20 17:57:50 +00:00
static gpg_error_t
gen_dsa ( unsigned int nbits , KBNODE pub_root ,
2010-10-14 16:34:31 +00:00
u32 timestamp , u32 expireval , int is_subkey ,
int keygen_flags , char * * cache_nonce_addr )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
int err ;
2007-07-05 16:58:19 +00:00
unsigned int qbits ;
2010-04-20 17:57:50 +00:00
char * keyparms ;
char nbitsstr [ 35 ] ;
char qbitsstr [ 35 ] ;
2003-06-05 07:14:21 +00:00
2009-05-20 09:57:10 +00:00
if ( nbits < 512 )
2007-07-05 16:58:19 +00:00
{
nbits = 1024 ;
log_info ( _ ( " keysize invalid; using %u bits \n " ) , nbits ) ;
}
else if ( nbits > 3072 )
{
nbits = 3072 ;
log_info ( _ ( " keysize invalid; using %u bits \n " ) , nbits ) ;
}
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
if ( ( nbits % 64 ) )
{
nbits = ( ( nbits + 63 ) / 64 ) * 64 ;
log_info ( _ ( " keysize rounded up to %u bits \n " ) , nbits ) ;
}
2006-06-27 14:30:59 +00:00
2009-07-09 08:52:31 +00:00
/* To comply with FIPS rules we round up to the next value unless in
expert mode . */
if ( ! opt . expert & & nbits > 1024 & & ( nbits % 1024 ) )
{
nbits = ( ( nbits + 1023 ) / 1024 ) * 1024 ;
log_info ( _ ( " keysize rounded up to %u bits \n " ) , nbits ) ;
}
2007-07-05 16:58:19 +00:00
/*
Figure out a q size based on the key size . FIPS 180 - 3 says :
2006-06-27 14:30:59 +00:00
2007-07-05 16:58:19 +00:00
L = 1024 , N = 160
L = 2048 , N = 224
L = 2048 , N = 256
L = 3072 , N = 256
2006-06-27 14:30:59 +00:00
2007-07-05 16:58:19 +00:00
2048 / 256 is an odd pair since there is also a 2048 / 224 and
3072 / 256. Matching sizes is not a very exact science .
2006-06-27 14:30:59 +00:00
2009-07-09 08:52:31 +00:00
We ' ll do 256 qbits for nbits over 2047 , 224 for nbits over 1024
2007-07-05 16:58:19 +00:00
but less than 2048 , and 160 for 1024 ( DSA1 ) .
*/
2006-06-27 14:30:59 +00:00
2009-07-09 08:52:31 +00:00
if ( nbits > 2047 )
2007-07-05 16:58:19 +00:00
qbits = 256 ;
else if ( nbits > 1024 )
qbits = 224 ;
else
qbits = 160 ;
2006-06-27 14:30:59 +00:00
2007-07-05 16:58:19 +00:00
if ( qbits ! = 160 )
log_info ( _ ( " WARNING: some OpenPGP programs can't "
" handle a DSA key with this digest size \n " ) ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
snprintf ( nbitsstr , sizeof nbitsstr , " %u " , nbits ) ;
snprintf ( qbitsstr , sizeof qbitsstr , " %u " , qbits ) ;
2010-10-14 16:34:31 +00:00
keyparms = xtryasprintf ( " (genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s)) " ,
2010-04-20 17:57:50 +00:00
strlen ( nbitsstr ) , nbitsstr ,
2010-10-14 16:34:31 +00:00
strlen ( qbitsstr ) , qbitsstr ,
( ( keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY )
& & ( keygen_flags & KEYGEN_FLAG_NO_PROTECTION ) ) ?
" (transient-key) " : " " ) ;
2010-04-20 17:57:50 +00:00
if ( ! keyparms )
err = gpg_error_from_syserror ( ) ;
else
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = common_gen ( keyparms , PUBKEY_ALGO_DSA , " pqgy " ,
2010-09-01 09:48:35 +00:00
pub_root , timestamp , expireval , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2010-04-20 17:57:50 +00:00
xfree ( keyparms ) ;
2007-07-05 16:58:19 +00:00
}
2003-07-29 08:53:19 +00:00
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
2011-01-05 17:33:17 -08:00
/* Returns allocated ECC key generation S-explression
call gcry_sexp_release ( out ) to free it .
*/
static int
delme__pk_ecc_build_sexp ( int qbits , int algo , int is_long_term , gcry_sexp_t * out ) {
gcry_mpi_t kek_params ;
char * kek_params_s ;
int rc ;
if ( is_long_term & & algo = = PUBKEY_ALGO_ECDH )
kek_params = pk_ecdh_default_params_to_mpi ( qbits ) ;
else
kek_params = NULL ;
if ( kek_params ) {
kek_params_s = mpi2hex ( kek_params ) ;
mpi_release ( kek_params ) ;
}
rc = gcry_sexp_build ( out , NULL ,
algo = = PUBKEY_ALGO_ECDSA ?
" (genkey(ecdsa(nbits %d)(qbits %d))) " :
" (genkey(ecdh(nbits %d)(qbits %d)(transient-key %d)(kek-params %s))) " ,
( int ) qbits , ( int ) qbits , ( int ) ( is_long_term = = 0 ) , kek_params_s ) ;
xfree ( kek_params_s ) ;
if ( rc ) {
log_debug ( " ec gen gcry_sexp_build failed: %s \n " , gpg_strerror ( rc ) ) ;
return rc ;
}
return 0 ;
}
static char *
pk_ecc_build_key_params ( int qbits , int algo , int transient ) {
byte * kek_params = NULL ;
size_t kek_params_size ;
char nbitsstr [ 35 ] ;
char qbitsstr [ 35 ] ;
char * keyparms ;
int n ;
/* KEK parameters are only needed for long term key generation */
if ( ! transient & & algo = = PUBKEY_ALGO_ECDH )
kek_params = pk_ecdh_default_params ( qbits , & kek_params_size ) ;
else
kek_params = NULL ;
snprintf ( nbitsstr , sizeof nbitsstr , " %u " , qbits ) ;
snprintf ( qbitsstr , sizeof qbitsstr , " %u " , qbits ) ;
if ( algo = = PUBKEY_ALGO_ECDSA | | kek_params = = NULL )
keyparms = xtryasprintf (
" (genkey(%s(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d))) " ,
algo = = PUBKEY_ALGO_ECDSA ? " ecdsa " : " ecdh " ,
strlen ( nbitsstr ) , nbitsstr ,
strlen ( qbitsstr ) , qbitsstr ,
transient ) ;
else {
assert ( kek_params ! = NULL ) ;
keyparms = xtryasprintf (
" (genkey(ecdh(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d)(kek-params %u: " ,
strlen ( nbitsstr ) , nbitsstr ,
strlen ( qbitsstr ) , qbitsstr ,
transient ,
( unsigned ) kek_params_size ) ;
if ( keyparms ! = NULL ) {
n = strlen ( keyparms ) ;
keyparms = xtryrealloc ( keyparms , n + kek_params_size + 4 ) ;
}
if ( keyparms = = NULL ) {
xfree ( kek_params ) ;
return NULL ;
}
memcpy ( keyparms + n , kek_params , kek_params_size ) ;
xfree ( kek_params ) ;
memcpy ( keyparms + n + kek_params_size , " ))) " , 4 ) ;
}
return keyparms ;
}
/* This common function is used in this file and also to generate ephemeral keys for ECDH.
* Caller must call free_public_key and free_secret_key */
int
pk_ecc_keypair_gen ( PKT_public_key * * pk_out , int algo , int keygen_flags , char * * cache_nonce_addr , unsigned nbits ) {
int err ;
unsigned int qbits ;
char * keyparms ;
// PUBKEY_ALGO_ECDH, PUBKEY_ALGO_ECDSA
static const char * const ec_pub_params [ 2 ] = { " cqp " , " cq " } ;
//static const char * const ec_priv_params[2] = { "cqpd", "cqd" };
assert ( algo = = PUBKEY_ALGO_ECDSA | | algo = = PUBKEY_ALGO_ECDH ) ;
assert ( PUBKEY_ALGO_ECDSA = = PUBKEY_ALGO_ECDH + 1 ) ;
* pk_out = NULL ;
if ( pubkey_get_npkey ( PUBKEY_ALGO_ECDSA ) ! = 2 | | pubkey_get_nskey ( PUBKEY_ALGO_ECDSA ) ! = 3 | |
pubkey_get_npkey ( PUBKEY_ALGO_ECDH ) ! = 3 | | pubkey_get_nskey ( PUBKEY_ALGO_ECDH ) ! = 4 )
{
log_info ( _ ( " incompatible version of gcrypt library (expect named curve logic for ECC) \n " ) ) ;
return GPG_ERR_EPROGMISMATCH ;
}
if ( nbits ! = 256 & & nbits ! = 384 & & nbits ! = 521 )
{
log_info ( _ ( " keysize invalid; using 256 bits instead of passed in %d \n " ) , nbits ) ;
}
/*
Figure out a q size based on the key size . See gen_dsa for more details .
Due to 8 - bit rounding we may get 528 here instead of 521
*/
nbits = qbits = ( nbits < 521 ? nbits : 521 ) ;
keyparms = pk_ecc_build_key_params ( qbits , algo , ! ! ( ( keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY ) & & ( keygen_flags & KEYGEN_FLAG_NO_PROTECTION ) ) ) ;
if ( ! keyparms ) {
err = gpg_error_from_syserror ( ) ;
log_error ( " ec pk_ecc_build_key_params failed: %s \n " , gpg_strerror ( err ) ) ;
}
else
{
err = common_key_gen ( keyparms , algo , ec_pub_params [ algo - PUBKEY_ALGO_ECDH ] ,
keygen_flags , cache_nonce_addr , pk_out ) ;
xfree ( keyparms ) ;
}
#if 0
/* always allocase seckey_info for EC keys. TODO: is this needed? */
if ( * pk_out ) {
struct seckey_info * ski ;
( * pk_out ) - > seckey_info = ski = xtrycalloc ( 1 , sizeof * ski ) ;
if ( ! ( * pk_out ) - > seckey_info ) {
free_public_key ( * pk_out ) ;
* pk_out = NULL ;
return gpg_error_from_syserror ( ) ;
}
ski - > is_protected = 0 ;
ski - > algo = 0 ;
}
# endif
return err ;
}
/****************
* Generate an ECC OpenPGP key
*/
static gpg_error_t
gen_ecc ( int algo , unsigned int nbits , KBNODE pub_root ,
u32 timestamp , u32 expireval , int is_subkey ,
int keygen_flags , char * * cache_nonce_addr )
{
int rc ;
PACKET * pkt ;
PKT_public_key * pk ;
rc = pk_ecc_keypair_gen ( & pk , algo , keygen_flags , cache_nonce_addr , nbits ) ;
if ( rc )
return rc ;
/* the rest is very similar to common_gen */
pk - > timestamp = timestamp ;
if ( expireval )
pk - > expiredate = pk - > timestamp + expireval ;
//assert( pk->seckey_info != NULL );
/// TODO: the new agent-based model doesn't return private portion here (the pkey array is allocated, but private MPIs are NULL, so this will cause a crash... )
///pk->seckey_info->csum = checksum_mpi ( pk->pkey[algo==PUBKEY_ALGO_ECDSA ? 2 : 3] ); /* corresponds to 'd' in 'cqd' or 'cqpd' */
pkt = xmalloc_clear ( sizeof * pkt ) ;
pkt - > pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY ;
pkt - > pkt . public_key = pk ;
add_kbnode ( pub_root , new_kbnode ( pkt ) ) ;
return 0 ;
}
2003-06-05 07:14:21 +00:00
/*
* Generate an RSA key .
*/
static int
2010-04-20 17:57:50 +00:00
gen_rsa ( int algo , unsigned int nbits , KBNODE pub_root ,
2010-10-14 16:34:31 +00:00
u32 timestamp , u32 expireval , int is_subkey ,
int keygen_flags , char * * cache_nonce_addr )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
int err ;
char * keyparms ;
char nbitsstr [ 35 ] ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
assert ( is_RSA ( algo ) ) ;
2003-06-05 07:14:21 +00:00
2009-12-04 19:47:54 +00:00
if ( ! nbits )
nbits = DEFAULT_STD_KEYSIZE ;
2007-07-05 16:58:19 +00:00
if ( nbits < 1024 )
{
nbits = 1024 ;
log_info ( _ ( " keysize invalid; using %u bits \n " ) , nbits ) ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
if ( ( nbits % 32 ) )
{
nbits = ( ( nbits + 31 ) / 32 ) * 32 ;
log_info ( _ ( " keysize rounded up to %u bits \n " ) , nbits ) ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
snprintf ( nbitsstr , sizeof nbitsstr , " %u " , nbits ) ;
2010-10-14 16:34:31 +00:00
keyparms = xtryasprintf ( " (genkey(rsa(nbits %zu:%s)%s)) " ,
strlen ( nbitsstr ) , nbitsstr ,
( ( keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY )
& & ( keygen_flags & KEYGEN_FLAG_NO_PROTECTION ) ) ?
" (transient-key) " : " " ) ;
2010-04-20 17:57:50 +00:00
if ( ! keyparms )
err = gpg_error_from_syserror ( ) ;
else
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = common_gen ( keyparms , algo , " ne " ,
2010-09-01 09:48:35 +00:00
pub_root , timestamp , expireval , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2010-04-20 17:57:50 +00:00
xfree ( keyparms ) ;
2007-07-05 16:58:19 +00:00
}
2003-07-29 08:53:19 +00:00
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
/****************
* check valid days :
* return 0 on error or the multiplier
*/
static int
check_valid_days ( const char * s )
{
2003-09-23 17:48:33 +00:00
if ( ! digitp ( s ) )
2003-06-05 07:14:21 +00:00
return 0 ;
for ( s + + ; * s ; s + + )
2003-09-23 17:48:33 +00:00
if ( ! digitp ( s ) )
2003-06-05 07:14:21 +00:00
break ;
if ( ! * s )
return 1 ;
if ( s [ 1 ] )
return 0 ; /* e.g. "2323wc" */
if ( * s = = ' d ' | | * s = = ' D ' )
return 1 ;
if ( * s = = ' w ' | | * s = = ' W ' )
return 7 ;
if ( * s = = ' m ' | | * s = = ' M ' )
return 30 ;
if ( * s = = ' y ' | | * s = = ' Y ' )
return 365 ;
return 0 ;
}
2006-04-19 11:26:11 +00:00
static void
print_key_flags ( int flags )
{
if ( flags & PUBKEY_USAGE_SIG )
tty_printf ( " %s " , _ ( " Sign " ) ) ;
if ( flags & PUBKEY_USAGE_CERT )
tty_printf ( " %s " , _ ( " Certify " ) ) ;
if ( flags & PUBKEY_USAGE_ENC )
tty_printf ( " %s " , _ ( " Encrypt " ) ) ;
if ( flags & PUBKEY_USAGE_AUTH )
tty_printf ( " %s " , _ ( " Authenticate " ) ) ;
}
/* Returns the key flags */
static unsigned int
ask_key_flags ( int algo , int subkey )
{
2007-12-04 11:23:31 +00:00
/* TRANSLATORS: Please use only plain ASCII characters for the
translation . If this is not possible use single digits . The
string needs to 8 bytes long . Here is a description of the
functions :
s = Toggle signing capability
e = Toggle encryption capability
a = Toggle authentication capability
q = Finish
*/
2006-04-19 11:26:11 +00:00
const char * togglers = _ ( " SsEeAaQq " ) ;
char * answer = NULL ;
unsigned int current = 0 ;
unsigned int possible = openpgp_pk_algo_usage ( algo ) ;
2009-05-20 09:08:48 +00:00
if ( strlen ( togglers ) ! = 8 )
2007-12-04 11:23:31 +00:00
{
tty_printf ( " NOTE: Bad translation at %s:%d. "
" Please report. \n " , __FILE__ , __LINE__ ) ;
togglers = " 11223300 " ;
}
2006-04-19 11:26:11 +00:00
/* Only primary keys may certify. */
if ( subkey )
possible & = ~ PUBKEY_USAGE_CERT ;
/* Preload the current set with the possible set, minus
authentication , since nobody really uses auth yet . */
current = possible & ~ PUBKEY_USAGE_AUTH ;
for ( ; ; )
{
tty_printf ( " \n " ) ;
tty_printf ( _ ( " Possible actions for a %s key: " ) ,
2006-04-19 13:24:36 +00:00
gcry_pk_algo_name ( algo ) ) ;
2006-04-19 11:26:11 +00:00
print_key_flags ( possible ) ;
tty_printf ( " \n " ) ;
tty_printf ( _ ( " Current allowed actions: " ) ) ;
print_key_flags ( current ) ;
tty_printf ( " \n \n " ) ;
if ( possible & PUBKEY_USAGE_SIG )
tty_printf ( _ ( " (%c) Toggle the sign capability \n " ) ,
togglers [ 0 ] ) ;
if ( possible & PUBKEY_USAGE_ENC )
tty_printf ( _ ( " (%c) Toggle the encrypt capability \n " ) ,
togglers [ 2 ] ) ;
if ( possible & PUBKEY_USAGE_AUTH )
tty_printf ( _ ( " (%c) Toggle the authenticate capability \n " ) ,
togglers [ 4 ] ) ;
tty_printf ( _ ( " (%c) Finished \n " ) , togglers [ 6 ] ) ;
tty_printf ( " \n " ) ;
xfree ( answer ) ;
answer = cpr_get ( " keygen.flags " , _ ( " Your selection? " ) ) ;
cpr_kill_prompt ( ) ;
if ( strlen ( answer ) > 1 )
tty_printf ( _ ( " Invalid selection. \n " ) ) ;
else if ( * answer = = ' \0 ' | | * answer = = togglers [ 6 ] | | * answer = = togglers [ 7 ] )
break ;
else if ( ( * answer = = togglers [ 0 ] | | * answer = = togglers [ 1 ] )
& & possible & PUBKEY_USAGE_SIG )
{
if ( current & PUBKEY_USAGE_SIG )
current & = ~ PUBKEY_USAGE_SIG ;
else
current | = PUBKEY_USAGE_SIG ;
}
else if ( ( * answer = = togglers [ 2 ] | | * answer = = togglers [ 3 ] )
& & possible & PUBKEY_USAGE_ENC )
{
if ( current & PUBKEY_USAGE_ENC )
current & = ~ PUBKEY_USAGE_ENC ;
else
current | = PUBKEY_USAGE_ENC ;
}
else if ( ( * answer = = togglers [ 4 ] | | * answer = = togglers [ 5 ] )
& & possible & PUBKEY_USAGE_AUTH )
{
if ( current & PUBKEY_USAGE_AUTH )
current & = ~ PUBKEY_USAGE_AUTH ;
else
current | = PUBKEY_USAGE_AUTH ;
}
else
tty_printf ( _ ( " Invalid selection. \n " ) ) ;
}
xfree ( answer ) ;
return current ;
}
2009-05-17 13:08:18 +00:00
/* Ask for an algorithm. The function returns the algorithm id to
* create . If ADDMODE is false the function won ' t show an option to
* create the primary and subkey combined and won ' t set R_USAGE
* either . If a combined algorithm has been selected , the subkey
* algorithm is stored at R_SUBKEY_ALGO . */
2003-06-05 07:14:21 +00:00
static int
2009-05-17 13:08:18 +00:00
ask_algo ( int addmode , int * r_subkey_algo , unsigned int * r_usage )
2003-06-05 07:14:21 +00:00
{
2009-05-17 13:08:18 +00:00
char * answer ;
int algo ;
int dummy_algo ;
2003-06-05 07:14:21 +00:00
2009-05-17 13:08:18 +00:00
if ( ! r_subkey_algo )
r_subkey_algo = & dummy_algo ;
tty_printf ( _ ( " Please select what kind of key you want: \n " ) ) ;
if ( ! addmode )
tty_printf ( _ ( " (%d) RSA and RSA (default) \n " ) , 1 ) ;
if ( ! addmode )
tty_printf ( _ ( " (%d) DSA and Elgamal \n " ) , 2 ) ;
tty_printf ( _ ( " (%d) DSA (sign only) \n " ) , 3 ) ;
tty_printf ( _ ( " (%d) RSA (sign only) \n " ) , 4 ) ;
if ( addmode )
{
tty_printf ( _ ( " (%d) Elgamal (encrypt only) \n " ) , 5 ) ;
tty_printf ( _ ( " (%d) RSA (encrypt only) \n " ) , 6 ) ;
}
if ( opt . expert )
{
tty_printf ( _ ( " (%d) DSA (set your own capabilities) \n " ) , 7 ) ;
tty_printf ( _ ( " (%d) RSA (set your own capabilities) \n " ) , 8 ) ;
}
2011-01-05 17:33:17 -08:00
tty_printf ( _ ( " (%d) ECDSA and ECDH \n " ) , 9 ) ;
2009-05-17 13:08:18 +00:00
for ( ; ; )
{
* r_usage = 0 ;
* r_subkey_algo = 0 ;
answer = cpr_get ( " keygen.algo " , _ ( " Your selection? " ) ) ;
cpr_kill_prompt ( ) ;
algo = * answer ? atoi ( answer ) : 1 ;
xfree ( answer ) ;
if ( algo = = 1 & & ! addmode )
{
algo = PUBKEY_ALGO_RSA ;
* r_subkey_algo = PUBKEY_ALGO_RSA ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 2 & & ! addmode )
{
algo = PUBKEY_ALGO_DSA ;
* r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 3 )
{
algo = PUBKEY_ALGO_DSA ;
* r_usage = PUBKEY_USAGE_SIG ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 4 )
{
algo = PUBKEY_ALGO_RSA ;
* r_usage = PUBKEY_USAGE_SIG ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 5 & & addmode )
{
algo = PUBKEY_ALGO_ELGAMAL_E ;
* r_usage = PUBKEY_USAGE_ENC ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 6 & & addmode )
{
algo = PUBKEY_ALGO_RSA ;
* r_usage = PUBKEY_USAGE_ENC ;
break ;
2006-04-19 11:26:11 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 7 & & opt . expert )
{
algo = PUBKEY_ALGO_DSA ;
* r_usage = ask_key_flags ( algo , addmode ) ;
break ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
else if ( algo = = 8 & & opt . expert )
{
algo = PUBKEY_ALGO_RSA ;
* r_usage = ask_key_flags ( algo , addmode ) ;
break ;
}
2011-01-05 17:33:17 -08:00
else if ( algo = = 9 )
{
algo = PUBKEY_ALGO_ECDSA ;
* r_subkey_algo = PUBKEY_ALGO_ECDH ;
break ;
}
2009-05-17 13:08:18 +00:00
else
tty_printf ( _ ( " Invalid selection. \n " ) ) ;
2003-06-05 07:14:21 +00:00
}
2009-05-17 13:08:18 +00:00
return algo ;
2003-06-05 07:14:21 +00:00
}
2009-07-23 15:18:58 +00:00
/* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE
2009-05-17 13:08:18 +00:00
is not 0 , the function asks for the size of the encryption
subkey . */
2003-06-05 07:14:21 +00:00
static unsigned
2009-05-17 13:08:18 +00:00
ask_keysize ( int algo , unsigned int primary_keysize )
2003-06-05 07:14:21 +00:00
{
2009-12-04 19:47:54 +00:00
unsigned int nbits , min , def = DEFAULT_STD_KEYSIZE , max = 4096 ;
2009-05-17 13:08:18 +00:00
int for_subkey = ! ! primary_keysize ;
int autocomp = 0 ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
if ( opt . expert )
min = 512 ;
else
min = 1024 ;
2003-06-05 07:14:21 +00:00
2009-05-17 13:08:18 +00:00
if ( primary_keysize & & ! opt . expert )
{
/* Deduce the subkey size from the primary key size. */
if ( algo = = PUBKEY_ALGO_DSA & & primary_keysize > 3072 )
nbits = 3072 ; /* For performance reasons we don't support more
than 3072 bit DSA . However we won ' t see this
case anyway because DSA can ' t be used as an
encryption subkey ; - ) . */
else
nbits = primary_keysize ;
autocomp = 1 ;
goto leave ;
}
2006-04-19 11:26:11 +00:00
switch ( algo )
{
case PUBKEY_ALGO_DSA :
2009-05-20 09:57:10 +00:00
def = 2048 ;
max = 3072 ;
2006-04-19 11:26:11 +00:00
break ;
2011-01-05 17:33:17 -08:00
case PUBKEY_ALGO_ECDSA :
case PUBKEY_ALGO_ECDH :
min = 256 ;
def = 256 ;
max = 521 ;
break ;
2006-04-19 11:26:11 +00:00
case PUBKEY_ALGO_RSA :
min = 1024 ;
break ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
tty_printf ( _ ( " %s keys may be between %u and %u bits long. \n " ) ,
2011-01-05 17:33:17 -08:00
openpgp_pk_algo_name ( algo ) , min , max ) ;
2006-04-19 11:26:11 +00:00
for ( ; ; )
{
2009-05-17 13:08:18 +00:00
char * prompt , * answer ;
2006-04-19 11:26:11 +00:00
2009-05-17 13:08:18 +00:00
if ( for_subkey )
prompt = xasprintf ( _ ( " What keysize do you want "
" for the subkey? (%u) " ) , def ) ;
else
prompt = xasprintf ( _ ( " What keysize do you want? (%u) " ) , def ) ;
answer = cpr_get ( " keygen.size " , prompt ) ;
cpr_kill_prompt ( ) ;
nbits = * answer ? atoi ( answer ) : def ;
2006-04-19 11:26:11 +00:00
xfree ( prompt ) ;
xfree ( answer ) ;
if ( nbits < min | | nbits > max )
tty_printf ( _ ( " %s keysizes must be in the range %u-%u \n " ) ,
2011-01-05 17:33:17 -08:00
openpgp_pk_algo_name ( algo ) , min , max ) ;
2006-04-19 11:26:11 +00:00
else
break ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
tty_printf ( _ ( " Requested keysize is %u bits \n " ) , nbits ) ;
2009-05-17 13:08:18 +00:00
leave :
2006-04-19 11:26:11 +00:00
if ( algo = = PUBKEY_ALGO_DSA & & ( nbits % 64 ) )
{
2011-01-05 17:33:17 -08:00
if ( ! ( algo = = PUBKEY_ALGO_ECDSA & & nbits = = 521 ) ) {
nbits = ( ( nbits + 63 ) / 64 ) * 64 ;
if ( ! autocomp )
tty_printf ( _ ( " rounded up to %u bits \n " ) , nbits ) ;
}
2006-04-19 11:26:11 +00:00
}
2011-01-05 17:33:17 -08:00
else if ( algo = = PUBKEY_ALGO_ECDH | | algo = = PUBKEY_ALGO_ECDSA ) {
if ( nbits ! = 256 & & nbits ! = 384 & & nbits ! = 521 ) {
nbits = min ;
tty_printf ( _ ( " unsupported ECDH value, corrected to the minimum %u bits \n " ) , nbits ) ;
}
}
2006-04-19 11:26:11 +00:00
else if ( ( nbits % 32 ) )
{
nbits = ( ( nbits + 31 ) / 32 ) * 32 ;
2009-05-17 13:08:18 +00:00
if ( ! autocomp )
tty_printf ( _ ( " rounded up to %u bits \n " ) , nbits ) ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
return nbits ;
2003-06-05 07:14:21 +00:00
}
/****************
2006-04-19 11:26:11 +00:00
* Parse an expire string and return its value in seconds .
* Returns ( u32 ) - 1 on error .
* This isn ' t perfect since scan_isodatestr returns unix time , and
* OpenPGP actually allows a 32 - bit time * plus * a 32 - bit offset .
* Because of this , we only permit setting expirations up to 2106 , but
* OpenPGP could theoretically allow up to 2242. I think we ' ll all
* just cope for the next few years until we get a 64 - bit time_t or
* similar .
2003-06-05 07:14:21 +00:00
*/
2006-04-19 11:26:11 +00:00
u32
2003-06-05 07:14:21 +00:00
parse_expire_string ( const char * string )
{
2008-08-11 08:08:08 +00:00
int mult ;
u32 seconds ;
u32 abs_date = 0 ;
u32 curtime = make_timestamp ( ) ;
2009-05-13 11:42:34 +00:00
time_t tt ;
2008-08-11 08:08:08 +00:00
if ( ! * string )
seconds = 0 ;
else if ( ! strncmp ( string , " seconds= " , 8 ) )
seconds = atoi ( string + 8 ) ;
2009-05-13 11:42:34 +00:00
else if ( ( abs_date = scan_isodatestr ( string ) )
& & ( abs_date + 86400 / 2 ) > curtime )
seconds = ( abs_date + 86400 / 2 ) - curtime ;
else if ( ( tt = isotime2epoch ( string ) ) ! = ( time_t ) ( - 1 ) )
seconds = ( u32 ) tt - curtime ;
2008-08-11 08:08:08 +00:00
else if ( ( mult = check_valid_days ( string ) ) )
seconds = atoi ( string ) * 86400L * mult ;
else
seconds = ( u32 ) ( - 1 ) ;
return seconds ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
/* Parsean Creation-Date string which is either "1986-04-26" or
" 19860426T042640 " . Returns 0 on error . */
static u32
parse_creation_string ( const char * string )
{
u32 seconds ;
if ( ! * string )
seconds = 0 ;
else if ( ! strncmp ( string , " seconds= " , 8 ) )
seconds = atoi ( string + 8 ) ;
else if ( ! ( seconds = scan_isodatestr ( string ) ) )
{
time_t tmp = isotime2epoch ( string ) ;
seconds = ( tmp = = ( time_t ) ( - 1 ) ) ? 0 : tmp ;
}
return seconds ;
}
2003-06-05 07:14:21 +00:00
/* object == 0 for a key, and 1 for a sig */
u32
2006-04-19 11:26:11 +00:00
ask_expire_interval ( int object , const char * def_expire )
2003-06-05 07:14:21 +00:00
{
2006-04-19 11:26:11 +00:00
u32 interval ;
2003-06-05 07:14:21 +00:00
char * answer ;
switch ( object )
{
case 0 :
2006-04-19 11:26:11 +00:00
if ( def_expire )
BUG ( ) ;
2003-06-05 07:14:21 +00:00
tty_printf ( _ ( " Please specify how long the key should be valid. \n "
" 0 = key does not expire \n "
" <n> = key expires in n days \n "
" <n>w = key expires in n weeks \n "
" <n>m = key expires in n months \n "
" <n>y = key expires in n years \n " ) ) ;
break ;
case 1 :
2006-04-19 11:26:11 +00:00
if ( ! def_expire )
BUG ( ) ;
2003-06-05 07:14:21 +00:00
tty_printf ( _ ( " Please specify how long the signature should be valid. \n "
" 0 = signature does not expire \n "
" <n> = signature expires in n days \n "
" <n>w = signature expires in n weeks \n "
" <n>m = signature expires in n months \n "
" <n>y = signature expires in n years \n " ) ) ;
break ;
default :
BUG ( ) ;
}
/* Note: The elgamal subkey for DSA has no expiration date because
* it must be signed with the DSA key and this one has the expiration
* date */
answer = NULL ;
2006-04-19 11:26:11 +00:00
for ( ; ; )
{
2003-06-05 07:14:21 +00:00
u32 curtime = make_timestamp ( ) ;
2006-04-19 11:26:11 +00:00
xfree ( answer ) ;
2003-06-05 07:14:21 +00:00
if ( object = = 0 )
answer = cpr_get ( " keygen.valid " , _ ( " Key is valid for? (0) " ) ) ;
else
2006-04-19 11:26:11 +00:00
{
char * prompt ;
# define PROMPTSTRING _("Signature is valid for? (%s) ")
/* This will actually end up larger than necessary because
of the 2 bytes for ' % s ' */
prompt = xmalloc ( strlen ( PROMPTSTRING ) + strlen ( def_expire ) + 1 ) ;
sprintf ( prompt , PROMPTSTRING , def_expire ) ;
# undef PROMPTSTRING
answer = cpr_get ( " siggen.valid " , prompt ) ;
xfree ( prompt ) ;
if ( * answer = = ' \0 ' )
answer = xstrdup ( def_expire ) ;
}
2003-06-05 07:14:21 +00:00
cpr_kill_prompt ( ) ;
trim_spaces ( answer ) ;
2006-04-19 11:26:11 +00:00
interval = parse_expire_string ( answer ) ;
if ( interval = = ( u32 ) - 1 )
{
2003-06-05 07:14:21 +00:00
tty_printf ( _ ( " invalid value \n " ) ) ;
continue ;
2006-04-19 11:26:11 +00:00
}
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
if ( ! interval )
{
tty_printf ( ( object = = 0 )
? _ ( " Key does not expire at all \n " )
: _ ( " Signature does not expire at all \n " ) ) ;
}
else
{
tty_printf ( object = = 0
? _ ( " Key expires at %s \n " )
: _ ( " Signature expires at %s \n " ) ,
asctimestamp ( ( ulong ) ( curtime + interval ) ) ) ;
2010-10-27 11:26:53 +00:00
# if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T)
2006-11-21 11:00:14 +00:00
if ( ( time_t ) ( ( ulong ) ( curtime + interval ) ) < 0 )
tty_printf ( _ ( " Your system can't display dates beyond 2038. \n "
" However, it will be correctly handled up to "
" 2106. \n " ) ) ;
2008-08-11 08:08:08 +00:00
else
2006-11-21 11:00:14 +00:00
# endif /*SIZEOF_TIME_T*/
2008-08-11 08:08:08 +00:00
if ( ( time_t ) ( ( unsigned long ) ( curtime + interval ) ) < curtime )
{
tty_printf ( _ ( " invalid value \n " ) ) ;
continue ;
}
2006-04-19 11:26:11 +00:00
}
2003-06-05 07:14:21 +00:00
if ( cpr_enabled ( ) | | cpr_get_answer_is_yes ( " keygen.valid.okay " ,
2006-04-19 11:26:11 +00:00
_ ( " Is this correct? (y/N) " ) ) )
break ;
}
xfree ( answer ) ;
2003-06-05 07:14:21 +00:00
return interval ;
}
u32
ask_expiredate ( )
{
2006-04-19 11:26:11 +00:00
u32 x = ask_expire_interval ( 0 , NULL ) ;
2003-06-05 07:14:21 +00:00
return x ? make_timestamp ( ) + x : 0 ;
}
2003-06-18 19:56:13 +00:00
2009-09-03 20:51:55 +00:00
static PKT_user_id *
uid_from_string ( const char * string )
{
size_t n ;
PKT_user_id * uid ;
n = strlen ( string ) ;
uid = xmalloc_clear ( sizeof * uid + n ) ;
uid - > len = n ;
strcpy ( uid - > name , string ) ;
uid - > ref = 1 ;
return uid ;
}
/* Ask for a user ID. With a MODE of 1 an extra help prompt is
printed for use during a new key creation . If KEYBLOCK is not NULL
the function prevents the creation of an already existing user
ID . */
2003-06-05 07:14:21 +00:00
static char *
2009-09-03 20:51:55 +00:00
ask_user_id ( int mode , KBNODE keyblock )
2003-06-05 07:14:21 +00:00
{
char * answer ;
char * aname , * acomment , * amail , * uid ;
2008-06-01 19:44:05 +00:00
if ( ! mode )
{
2009-01-08 15:48:51 +00:00
/* TRANSLATORS: This is the new string telling the user what
gpg is now going to do ( i . e . ask for the parts of the user
ID ) . Note that if you do not tyranslated this string , a
different string will be used used , which might still have
a correct transaltion . */
2008-06-01 19:44:05 +00:00
const char * s1 =
N_ ( " \n "
" GnuPG needs to construct a user ID to identify your key. \n "
" \n " ) ;
const char * s2 = _ ( s1 ) ;
if ( ! strcmp ( s1 , s2 ) )
{
/* There is no translation for the string thus we to use
the old info text . gettext has no way to tell whether
a translation is actually available , thus we need to
to compare again . */
2009-01-08 15:48:51 +00:00
/* TRANSLATORS: This string is in general not anymore used
but you should keep your existing translation . In case
the new string is not translated this old string will
be used . */
2008-06-01 19:44:05 +00:00
const char * s3 = N_ ( " \n "
2006-04-19 11:26:11 +00:00
" You need a user ID to identify your key; "
" the software constructs the user ID \n "
" from the Real Name, Comment and Email Address in this form: \n "
2008-06-01 19:44:05 +00:00
" \" Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de> \" \n \n " ) ;
const char * s4 = _ ( s3 ) ;
if ( strcmp ( s3 , s4 ) )
s2 = s3 ; /* A translation exists - use it. */
}
tty_printf ( " %s " , s2 ) ;
}
2003-06-05 07:14:21 +00:00
uid = aname = acomment = amail = NULL ;
for ( ; ; ) {
char * p ;
int fail = 0 ;
if ( ! aname ) {
for ( ; ; ) {
2006-04-19 11:26:11 +00:00
xfree ( aname ) ;
2003-06-05 07:14:21 +00:00
aname = cpr_get ( " keygen.name " , _ ( " Real name: " ) ) ;
trim_spaces ( aname ) ;
cpr_kill_prompt ( ) ;
if ( opt . allow_freeform_uid )
break ;
if ( strpbrk ( aname , " <> " ) )
tty_printf ( _ ( " Invalid character in name \n " ) ) ;
2003-09-23 17:48:33 +00:00
else if ( digitp ( aname ) )
2003-06-05 07:14:21 +00:00
tty_printf ( _ ( " Name may not start with a digit \n " ) ) ;
else if ( strlen ( aname ) < 5 )
tty_printf ( _ ( " Name must be at least 5 characters long \n " ) ) ;
else
break ;
}
}
if ( ! amail ) {
for ( ; ; ) {
2006-04-19 11:26:11 +00:00
xfree ( amail ) ;
2003-06-05 07:14:21 +00:00
amail = cpr_get ( " keygen.email " , _ ( " Email address: " ) ) ;
trim_spaces ( amail ) ;
cpr_kill_prompt ( ) ;
2003-09-23 17:48:33 +00:00
if ( ! * amail | | opt . allow_freeform_uid )
2003-06-05 07:14:21 +00:00
break ; /* no email address is okay */
2006-04-19 11:26:11 +00:00
else if ( ! is_valid_mailbox ( amail ) )
tty_printf ( _ ( " Not a valid email address \n " ) ) ;
2003-06-05 07:14:21 +00:00
else
break ;
}
}
if ( ! acomment ) {
for ( ; ; ) {
2006-04-19 11:26:11 +00:00
xfree ( acomment ) ;
2003-06-05 07:14:21 +00:00
acomment = cpr_get ( " keygen.comment " , _ ( " Comment: " ) ) ;
trim_spaces ( acomment ) ;
cpr_kill_prompt ( ) ;
if ( ! * acomment )
break ; /* no comment is okay */
else if ( strpbrk ( acomment , " () " ) )
tty_printf ( _ ( " Invalid character in comment \n " ) ) ;
else
break ;
}
}
2006-04-19 11:26:11 +00:00
xfree ( uid ) ;
uid = p = xmalloc ( strlen ( aname ) + strlen ( amail ) + strlen ( acomment ) + 12 + 10 ) ;
2003-06-05 07:14:21 +00:00
p = stpcpy ( p , aname ) ;
if ( * acomment )
p = stpcpy ( stpcpy ( stpcpy ( p , " ( " ) , acomment ) , " ) " ) ;
if ( * amail )
p = stpcpy ( stpcpy ( stpcpy ( p , " < " ) , amail ) , " > " ) ;
2006-08-21 20:20:23 +00:00
/* Append a warning if the RNG is switched into fake mode. */
if ( random_is_faked ( ) )
strcpy ( p , " (insecure!) " ) ;
2006-04-19 11:26:11 +00:00
2003-06-05 07:14:21 +00:00
/* print a note in case that UTF8 mapping has to be done */
for ( p = uid ; * p ; p + + ) {
if ( * p & 0x80 ) {
tty_printf ( _ ( " You are using the `%s' character set. \n " ) ,
get_native_charset ( ) ) ;
break ;
}
}
tty_printf ( _ ( " You selected this USER-ID: \n \" %s \" \n \n " ) , uid ) ;
2009-09-03 20:51:55 +00:00
2003-09-23 17:48:33 +00:00
if ( ! * amail & & ! opt . allow_freeform_uid
2006-04-19 11:26:11 +00:00
& & ( strchr ( aname , ' @ ' ) | | strchr ( acomment , ' @ ' ) ) ) {
2003-06-05 07:14:21 +00:00
fail = 1 ;
2009-09-03 20:51:55 +00:00
tty_printf ( _ ( " Please don't put the email address "
" into the real name or the comment \n " ) ) ;
2003-06-05 07:14:21 +00:00
}
2009-09-03 20:51:55 +00:00
if ( ! fail & & keyblock )
{
PKT_user_id * uidpkt = uid_from_string ( uid ) ;
KBNODE node ;
for ( node = keyblock ; node & & ! fail ; node = node - > next )
if ( ! is_deleted_kbnode ( node )
& & node - > pkt - > pkttype = = PKT_USER_ID
& & ! cmp_user_ids ( uidpkt , node - > pkt - > pkt . user_id ) )
fail = 1 ;
if ( fail )
tty_printf ( _ ( " Such a user ID already exists on this key! \n " ) ) ;
free_user_id ( uidpkt ) ;
}
2003-06-05 07:14:21 +00:00
for ( ; ; ) {
2006-04-19 11:26:11 +00:00
/* TRANSLATORS: These are the allowed answers in
lower and uppercase . Below you will find the matching
string which should be translated accordingly and the
letter changed to match the one in the answer string .
n = Change name
c = Change comment
e = Change email
o = Okay ( ready , continue )
q = Quit
*/
2003-06-05 07:14:21 +00:00
const char * ansstr = _ ( " NnCcEeOoQq " ) ;
if ( strlen ( ansstr ) ! = 10 )
BUG ( ) ;
if ( cpr_enabled ( ) ) {
2010-02-17 10:23:42 +00:00
answer = xstrdup ( ansstr + ( fail ? 8 : 6 ) ) ;
2003-06-05 07:14:21 +00:00
answer [ 1 ] = 0 ;
}
else {
answer = cpr_get ( " keygen.userid.cmd " , fail ?
_ ( " Change (N)ame, (C)omment, (E)mail or (Q)uit? " ) :
_ ( " Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? " ) ) ;
cpr_kill_prompt ( ) ;
}
if ( strlen ( answer ) > 1 )
;
else if ( * answer = = ansstr [ 0 ] | | * answer = = ansstr [ 1 ] ) {
2006-04-19 11:26:11 +00:00
xfree ( aname ) ; aname = NULL ;
2003-06-05 07:14:21 +00:00
break ;
}
else if ( * answer = = ansstr [ 2 ] | | * answer = = ansstr [ 3 ] ) {
2006-04-19 11:26:11 +00:00
xfree ( acomment ) ; acomment = NULL ;
2003-06-05 07:14:21 +00:00
break ;
}
else if ( * answer = = ansstr [ 4 ] | | * answer = = ansstr [ 5 ] ) {
2006-04-19 11:26:11 +00:00
xfree ( amail ) ; amail = NULL ;
2003-06-05 07:14:21 +00:00
break ;
}
else if ( * answer = = ansstr [ 6 ] | | * answer = = ansstr [ 7 ] ) {
if ( fail ) {
tty_printf ( _ ( " Please correct the error first \n " ) ) ;
}
else {
2006-04-19 11:26:11 +00:00
xfree ( aname ) ; aname = NULL ;
xfree ( acomment ) ; acomment = NULL ;
xfree ( amail ) ; amail = NULL ;
2003-06-05 07:14:21 +00:00
break ;
}
}
else if ( * answer = = ansstr [ 8 ] | | * answer = = ansstr [ 9 ] ) {
2006-04-19 11:26:11 +00:00
xfree ( aname ) ; aname = NULL ;
xfree ( acomment ) ; acomment = NULL ;
xfree ( amail ) ; amail = NULL ;
xfree ( uid ) ; uid = NULL ;
2003-06-05 07:14:21 +00:00
break ;
}
2006-04-19 11:26:11 +00:00
xfree ( answer ) ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
xfree ( answer ) ;
2003-06-05 07:14:21 +00:00
if ( ! amail & & ! acomment & & ! amail )
2006-04-19 11:26:11 +00:00
break ;
xfree ( uid ) ; uid = NULL ;
2003-06-05 07:14:21 +00:00
}
if ( uid ) {
char * p = native_to_utf8 ( uid ) ;
2006-04-19 11:26:11 +00:00
xfree ( uid ) ;
2003-06-05 07:14:21 +00:00
uid = p ;
}
return uid ;
}
2009-05-15 19:26:46 +00:00
/* MODE 0 - standard
1 - Ask for passphrase of the card backup key . */
2003-06-05 07:14:21 +00:00
static DEK *
2009-05-15 19:26:46 +00:00
do_ask_passphrase ( STRING2KEY * * ret_s2k , int mode , int * r_canceled )
2003-06-05 07:14:21 +00:00
{
DEK * dek = NULL ;
STRING2KEY * s2k ;
const char * errtext = NULL ;
2009-05-15 19:26:46 +00:00
const char * custdesc = NULL ;
2003-06-05 07:14:21 +00:00
tty_printf ( _ ( " You need a Passphrase to protect your secret key. \n \n " ) ) ;
2009-05-15 19:26:46 +00:00
if ( mode = = 1 )
custdesc = _ ( " Please enter a passphrase to protect the off-card "
" backup of the new encryption key. " ) ;
2006-04-19 11:26:11 +00:00
s2k = xmalloc_secure ( sizeof * s2k ) ;
2003-06-05 07:14:21 +00:00
for ( ; ; ) {
s2k - > mode = opt . s2k_mode ;
2006-04-19 11:26:11 +00:00
s2k - > hash_algo = S2K_DIGEST_ALGO ;
2009-05-15 19:26:46 +00:00
dek = passphrase_to_dek_ext ( NULL , 0 , opt . s2k_cipher_algo , s2k , 2 ,
errtext , custdesc , NULL , r_canceled ) ;
2006-12-06 10:16:50 +00:00
if ( ! dek & & * r_canceled ) {
xfree ( dek ) ; dek = NULL ;
xfree ( s2k ) ; s2k = NULL ;
break ;
}
else if ( ! dek ) {
2003-06-05 07:14:21 +00:00
errtext = N_ ( " passphrase not correctly repeated; try again " ) ;
tty_printf ( _ ( " %s. \n " ) , _ ( errtext ) ) ;
}
else if ( ! dek - > keylen ) {
2006-04-19 11:26:11 +00:00
xfree ( dek ) ; dek = NULL ;
xfree ( s2k ) ; s2k = NULL ;
2003-06-05 07:14:21 +00:00
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 \" --edit-key \" . \n \n " ) ) ;
break ;
}
else
break ; /* okay */
}
* ret_s2k = s2k ;
return dek ;
}
2007-07-05 16:58:19 +00:00
/* Basic key generation. Here we divert to the actual generation
routines based on the requested algorithm . */
2003-06-05 07:14:21 +00:00
static int
2010-04-20 17:57:50 +00:00
do_create ( int algo , unsigned int nbits , KBNODE pub_root ,
2010-09-01 09:48:35 +00:00
u32 timestamp , u32 expiredate , int is_subkey ,
2010-10-14 16:34:31 +00:00
int keygen_flags , char * * cache_nonce_addr )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
/* Fixme: The entropy collecting message should be moved to a
libgcrypt progress handler . */
if ( ! opt . batch )
tty_printf ( _ (
2003-06-05 07:14:21 +00:00
" We need to generate a lot of random bytes. It is a good idea to perform \n "
" some other action (type on the keyboard, move the mouse, utilize the \n "
" disks) during the prime generation; this gives the random number \n "
" generator a better chance to gain enough entropy. \n " ) ) ;
2010-04-20 17:57:50 +00:00
if ( algo = = PUBKEY_ALGO_ELGAMAL_E )
2010-09-01 09:48:35 +00:00
err = gen_elg ( algo , nbits , pub_root , timestamp , expiredate , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2010-04-20 17:57:50 +00:00
else if ( algo = = PUBKEY_ALGO_DSA )
2010-09-01 09:48:35 +00:00
err = gen_dsa ( nbits , pub_root , timestamp , expiredate , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2011-01-05 17:33:17 -08:00
else if ( algo = = PUBKEY_ALGO_ECDSA | | algo = = PUBKEY_ALGO_ECDH )
err = gen_ecc ( algo , nbits , pub_root , timestamp , expiredate , is_subkey ,
keygen_flags , cache_nonce_addr ) ;
2010-04-20 17:57:50 +00:00
else if ( algo = = PUBKEY_ALGO_RSA )
2010-09-01 09:48:35 +00:00
err = gen_rsa ( algo , nbits , pub_root , timestamp , expiredate , is_subkey ,
2010-10-14 16:34:31 +00:00
keygen_flags , cache_nonce_addr ) ;
2006-04-19 11:26:11 +00:00
else
BUG ( ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
return err ;
2003-06-05 07:14:21 +00:00
}
2009-09-03 20:51:55 +00:00
/* Generate a new user id packet or return NULL if canceled. If
KEYBLOCK is not NULL the function prevents the creation of an
already existing user ID . */
2003-06-05 07:14:21 +00:00
PKT_user_id *
2009-09-03 20:51:55 +00:00
generate_user_id ( KBNODE keyblock )
2003-06-05 07:14:21 +00:00
{
2009-09-03 20:51:55 +00:00
char * p ;
p = ask_user_id ( 1 , keyblock ) ;
if ( ! p )
return NULL ; /* Canceled. */
return uid_from_string ( p ) ;
2003-06-05 07:14:21 +00:00
}
static void
2010-11-17 13:21:24 +00:00
release_parameter_list ( struct para_data_s * r )
2003-06-05 07:14:21 +00:00
{
2010-11-17 13:21:24 +00:00
struct para_data_s * r2 ;
for ( ; r ; r = r2 )
{
r2 = r - > next ;
if ( r - > key = = pPASSPHRASE_DEK )
xfree ( r - > u . dek ) ;
else if ( r - > key = = pPASSPHRASE_S2K )
xfree ( r - > u . s2k ) ;
xfree ( r ) ;
2003-06-05 07:14:21 +00:00
}
}
static struct para_data_s *
get_parameter ( struct para_data_s * para , enum para_name key )
{
struct para_data_s * r ;
for ( r = para ; r & & r - > key ! = key ; r = r - > next )
;
return r ;
}
static const char *
get_parameter_value ( struct para_data_s * para , enum para_name key )
{
struct para_data_s * r = get_parameter ( para , key ) ;
return ( r & & * r - > u . value ) ? r - > u . value : NULL ;
}
static int
2009-12-04 19:47:54 +00:00
get_parameter_algo ( struct para_data_s * para , enum para_name key ,
int * r_default )
2003-06-05 07:14:21 +00:00
{
2009-12-04 19:47:54 +00:00
int i ;
struct para_data_s * r = get_parameter ( para , key ) ;
if ( r_default )
* r_default = 0 ;
if ( ! r )
return - 1 ;
if ( ! ascii_strcasecmp ( r - > u . value , " default " ) )
{
/* Note: If you change this default algo, remember to change it
also in gpg . c : gpgconf_list . */
i = DEFAULT_STD_ALGO ;
if ( r_default )
* r_default = 1 ;
}
else if ( digitp ( r - > u . value ) )
i = atoi ( r - > u . value ) ;
else if ( ! strcmp ( r - > u . value , " ELG-E " )
| | ! strcmp ( r - > u . value , " ELG " ) )
i = GCRY_PK_ELG_E ;
else
i = gcry_pk_map_name ( r - > u . value ) ;
if ( i = = PUBKEY_ALGO_RSA_E | | i = = PUBKEY_ALGO_RSA_S )
i = 0 ; /* we don't want to allow generation of these algorithms */
return i ;
2003-06-05 07:14:21 +00:00
}
/*
2008-12-09 10:46:29 +00:00
* Parse the usage parameter and set the keyflags . Returns - 1 on
* error , 0 for no usage given or 1 for usage available .
2003-06-05 07:14:21 +00:00
*/
static int
parse_parameter_usage ( const char * fname ,
struct para_data_s * para , enum para_name key )
{
struct para_data_s * r = get_parameter ( para , key ) ;
char * p , * pn ;
unsigned int use ;
if ( ! r )
return 0 ; /* none (this is an optional parameter)*/
use = 0 ;
pn = r - > u . value ;
while ( ( p = strsep ( & pn , " \t , " ) ) ) {
if ( ! * p )
;
else if ( ! ascii_strcasecmp ( p , " sign " ) )
use | = PUBKEY_USAGE_SIG ;
else if ( ! ascii_strcasecmp ( p , " encrypt " ) )
use | = PUBKEY_USAGE_ENC ;
2003-09-05 07:40:18 +00:00
else if ( ! ascii_strcasecmp ( p , " auth " ) )
use | = PUBKEY_USAGE_AUTH ;
2003-06-05 07:14:21 +00:00
else {
log_error ( " %s:%d: invalid usage list \n " , fname , r - > lnr ) ;
return - 1 ; /* error */
}
}
r - > u . usage = use ;
2006-04-19 11:26:11 +00:00
return 1 ;
2003-06-05 07:14:21 +00:00
}
static int
parse_revocation_key ( const char * fname ,
struct para_data_s * para , enum para_name key )
{
struct para_data_s * r = get_parameter ( para , key ) ;
struct revocation_key revkey ;
char * pn ;
int i ;
if ( ! r )
return 0 ; /* none (this is an optional parameter) */
pn = r - > u . value ;
revkey . class = 0x80 ;
revkey . algid = atoi ( pn ) ;
if ( ! revkey . algid )
goto fail ;
/* Skip to the fpr */
while ( * pn & & * pn ! = ' : ' )
pn + + ;
if ( * pn ! = ' : ' )
goto fail ;
pn + + ;
for ( i = 0 ; i < MAX_FINGERPRINT_LEN & & * pn ; i + + , pn + = 2 )
{
int c = hextobyte ( pn ) ;
if ( c = = - 1 )
goto fail ;
revkey . fpr [ i ] = c ;
}
/* skip to the tag */
while ( * pn & & * pn ! = ' s ' & & * pn ! = ' S ' )
pn + + ;
if ( ascii_strcasecmp ( pn , " sensitive " ) = = 0 )
revkey . class | = 0x40 ;
memcpy ( & r - > u . revkey , & revkey , sizeof ( struct revocation_key ) ) ;
return 0 ;
fail :
log_error ( " %s:%d: invalid revocation key \n " , fname , r - > lnr ) ;
return - 1 ; /* error */
}
static u32
get_parameter_u32 ( struct para_data_s * para , enum para_name key )
{
2007-07-05 16:58:19 +00:00
struct para_data_s * r = get_parameter ( para , key ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
if ( ! r )
return 0 ;
if ( r - > key = = pKEYCREATIONDATE )
return r - > u . creation ;
if ( r - > key = = pKEYEXPIRE | | r - > key = = pSUBKEYEXPIRE )
return r - > u . expire ;
if ( r - > key = = pKEYUSAGE | | r - > key = = pSUBKEYUSAGE )
return r - > u . usage ;
return ( unsigned int ) strtoul ( r - > u . value , NULL , 10 ) ;
2003-06-05 07:14:21 +00:00
}
static unsigned int
get_parameter_uint ( struct para_data_s * para , enum para_name key )
{
return get_parameter_u32 ( para , key ) ;
}
static struct revocation_key *
get_parameter_revkey ( struct para_data_s * para , enum para_name key )
{
struct para_data_s * r = get_parameter ( para , key ) ;
return r ? & r - > u . revkey : NULL ;
}
static int
proc_parameter_file ( struct para_data_s * para , const char * fname ,
2003-06-27 20:53:09 +00:00
struct output_control_s * outctrl , int card )
2003-06-05 07:14:21 +00:00
{
2006-04-19 11:26:11 +00:00
struct para_data_s * r ;
const char * s1 , * s2 , * s3 ;
size_t n ;
char * p ;
2009-12-04 19:47:54 +00:00
int is_default = 0 ;
int have_user_id = 0 ;
int err , algo ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
/* Check that we have all required parameters. */
r = get_parameter ( para , pKEYTYPE ) ;
if ( r )
{
2009-12-04 19:47:54 +00:00
algo = get_parameter_algo ( para , pKEYTYPE , & is_default ) ;
2006-04-28 14:31:29 +00:00
if ( openpgp_pk_test_algo2 ( algo , PUBKEY_USAGE_SIG ) )
2006-04-19 11:26:11 +00:00
{
2008-12-09 10:46:29 +00:00
log_error ( " %s:%d: invalid algorithm \n " , fname , r - > lnr ) ;
2006-04-19 11:26:11 +00:00
return - 1 ;
}
}
else
{
2008-12-09 10:46:29 +00:00
log_error ( " %s: no Key-Type specified \n " , fname ) ;
2006-04-19 11:26:11 +00:00
return - 1 ;
2003-06-05 07:14:21 +00:00
}
2008-12-09 10:46:29 +00:00
err = parse_parameter_usage ( fname , para , pKEYUSAGE ) ;
if ( ! err )
2006-04-19 11:26:11 +00:00
{
2009-12-04 19:47:54 +00:00
/* Default to algo capabilities if key-usage is not provided and
no default algorithm has been requested . */
2008-12-09 10:46:29 +00:00
r = xmalloc_clear ( sizeof ( * r ) ) ;
r - > key = pKEYUSAGE ;
2009-12-04 19:47:54 +00:00
r - > u . usage = ( is_default
? ( PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG )
: openpgp_pk_algo_usage ( algo ) ) ;
2008-12-09 10:46:29 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
}
2008-12-09 10:46:29 +00:00
else if ( err = = - 1 )
2006-04-19 11:26:11 +00:00
return - 1 ;
2008-12-09 10:46:29 +00:00
else
{
r = get_parameter ( para , pKEYUSAGE ) ;
if ( r & & ( r - > u . usage & ~ openpgp_pk_algo_usage ( algo ) ) )
{
log_error ( " %s:%d: specified Key-Usage not allowed for algo %d \n " ,
fname , r - > lnr , algo ) ;
return - 1 ;
}
}
2006-04-19 11:26:11 +00:00
2009-12-04 19:47:54 +00:00
is_default = 0 ;
2006-04-19 11:26:11 +00:00
r = get_parameter ( para , pSUBKEYTYPE ) ;
if ( r )
{
2009-12-04 19:47:54 +00:00
algo = get_parameter_algo ( para , pSUBKEYTYPE , & is_default ) ;
2006-04-19 13:24:36 +00:00
if ( openpgp_pk_test_algo ( algo ) )
2006-04-19 11:26:11 +00:00
{
2008-12-09 10:46:29 +00:00
log_error ( " %s:%d: invalid algorithm \n " , fname , r - > lnr ) ;
2006-04-19 11:26:11 +00:00
return - 1 ;
}
2003-06-05 07:14:21 +00:00
2008-12-09 10:46:29 +00:00
err = parse_parameter_usage ( fname , para , pSUBKEYUSAGE ) ;
if ( ! err )
2006-04-19 11:26:11 +00:00
{
/* Default to algo capabilities if subkey-usage is not
provided */
2008-12-09 10:46:29 +00:00
r = xmalloc_clear ( sizeof ( * r ) ) ;
r - > key = pSUBKEYUSAGE ;
2009-12-04 19:47:54 +00:00
r - > u . usage = ( is_default
? PUBKEY_USAGE_ENC
: openpgp_pk_algo_usage ( algo ) ) ;
2008-12-09 10:46:29 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
}
2008-12-09 10:46:29 +00:00
else if ( err = = - 1 )
2003-06-05 07:14:21 +00:00
return - 1 ;
2008-12-09 10:46:29 +00:00
else
{
r = get_parameter ( para , pSUBKEYUSAGE ) ;
if ( r & & ( r - > u . usage & ~ openpgp_pk_algo_usage ( algo ) ) )
{
log_error ( " %s:%d: specified Subkey-Usage not allowed "
" for algo %d \n " , fname , r - > lnr , algo ) ;
return - 1 ;
}
}
2003-06-05 07:14:21 +00:00
}
2008-12-09 10:46:29 +00:00
2006-04-19 11:26:11 +00:00
if ( get_parameter_value ( para , pUSERID ) )
have_user_id = 1 ;
else
{
/* create the formatted user ID */
s1 = get_parameter_value ( para , pNAMEREAL ) ;
s2 = get_parameter_value ( para , pNAMECOMMENT ) ;
s3 = get_parameter_value ( para , pNAMEEMAIL ) ;
if ( s1 | | s2 | | s3 )
{
n = ( s1 ? strlen ( s1 ) : 0 ) + ( s2 ? strlen ( s2 ) : 0 ) + ( s3 ? strlen ( s3 ) : 0 ) ;
r = xmalloc_clear ( sizeof * r + n + 20 ) ;
r - > key = pUSERID ;
p = r - > u . value ;
if ( s1 )
p = stpcpy ( p , s1 ) ;
if ( s2 )
p = stpcpy ( stpcpy ( stpcpy ( p , " ( " ) , s2 ) , " ) " ) ;
if ( s3 )
p = stpcpy ( stpcpy ( stpcpy ( p , " < " ) , s3 ) , " > " ) ;
r - > next = para ;
para = r ;
have_user_id = 1 ;
2003-06-05 07:14:21 +00:00
}
}
2006-04-19 11:26:11 +00:00
if ( ! have_user_id )
{
log_error ( " %s: no User-ID specified \n " , fname ) ;
2003-06-05 07:14:21 +00:00
return - 1 ;
2006-04-19 11:26:11 +00:00
}
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
/* Set preferences, if any. */
keygen_set_std_prefs ( get_parameter_value ( para , pPREFERENCES ) , 0 ) ;
2003-06-05 07:14:21 +00:00
2006-06-27 14:30:59 +00:00
/* Set keyserver, if any. */
s1 = get_parameter_value ( para , pKEYSERVER ) ;
if ( s1 )
{
struct keyserver_spec * spec ;
spec = parse_keyserver_uri ( s1 , 1 , NULL , 0 ) ;
if ( spec )
{
free_keyserver_spec ( spec ) ;
opt . def_keyserver_url = s1 ;
}
else
{
log_error ( " %s:%d: invalid keyserver url \n " , fname , r - > lnr ) ;
return - 1 ;
}
}
2006-04-19 11:26:11 +00:00
/* Set revoker, if any. */
if ( parse_revocation_key ( fname , para , pREVOKER ) )
return - 1 ;
2008-06-16 15:48:33 +00:00
/* Make DEK and S2K from the Passphrase. */
if ( outctrl - > ask_passphrase )
{
/* %ask-passphrase is active - ignore pPASSPRASE and ask. This
feature is required so that GUIs are able to do a key
creation but have gpg - agent ask for the passphrase . */
int canceled = 0 ;
STRING2KEY * s2k ;
DEK * dek ;
2009-05-15 19:26:46 +00:00
dek = do_ask_passphrase ( & s2k , 0 , & canceled ) ;
2008-06-16 15:48:33 +00:00
if ( dek )
{
r = xmalloc_clear ( sizeof * r ) ;
r - > key = pPASSPHRASE_DEK ;
r - > u . dek = dek ;
r - > next = para ;
para = r ;
r = xmalloc_clear ( sizeof * r ) ;
r - > key = pPASSPHRASE_S2K ;
r - > u . s2k = s2k ;
r - > next = para ;
para = r ;
}
2006-04-19 11:26:11 +00:00
2008-06-16 15:48:33 +00:00
if ( canceled )
{
log_error ( " %s:%d: key generation canceled \n " , fname , r - > lnr ) ;
return - 1 ;
}
}
else
{
r = get_parameter ( para , pPASSPHRASE ) ;
if ( r & & * r - > u . value )
{
/* We have a plain text passphrase - create a DEK from it.
* It is a little bit ridiculous to keep it in secure memory
* but because we do this always , why not here . */
STRING2KEY * s2k ;
DEK * dek ;
s2k = xmalloc_secure ( sizeof * s2k ) ;
s2k - > mode = opt . s2k_mode ;
s2k - > hash_algo = S2K_DIGEST_ALGO ;
set_next_passphrase ( r - > u . value ) ;
dek = passphrase_to_dek ( NULL , 0 , opt . s2k_cipher_algo , s2k , 2 ,
NULL , NULL ) ;
set_next_passphrase ( NULL ) ;
assert ( dek ) ;
memset ( r - > u . value , 0 , strlen ( r - > u . value ) ) ;
r = xmalloc_clear ( sizeof * r ) ;
r - > key = pPASSPHRASE_S2K ;
r - > u . s2k = s2k ;
r - > next = para ;
para = r ;
r = xmalloc_clear ( sizeof * r ) ;
r - > key = pPASSPHRASE_DEK ;
r - > u . dek = dek ;
r - > next = para ;
para = r ;
}
}
2006-04-19 11:26:11 +00:00
2007-07-05 16:58:19 +00:00
/* Make KEYCREATIONDATE from Creation-Date. */
r = get_parameter ( para , pCREATIONDATE ) ;
if ( r & & * r - > u . value )
{
u32 seconds ;
seconds = parse_creation_string ( r - > u . value ) ;
if ( ! seconds )
{
log_error ( " %s:%d: invalid creation date \n " , fname , r - > lnr ) ;
return - 1 ;
}
r - > u . creation = seconds ;
r - > key = pKEYCREATIONDATE ; /* Change that entry. */
}
/* Make KEYEXPIRE from Expire-Date. */
2006-04-19 11:26:11 +00:00
r = get_parameter ( para , pEXPIREDATE ) ;
if ( r & & * r - > u . value )
{
u32 seconds ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
seconds = parse_expire_string ( r - > u . value ) ;
if ( seconds = = ( u32 ) - 1 )
{
log_error ( " %s:%d: invalid expire date \n " , fname , r - > lnr ) ;
return - 1 ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
r - > u . expire = seconds ;
r - > key = pKEYEXPIRE ; /* change hat entry */
/* also set it for the subkey */
r = xmalloc_clear ( sizeof * r + 20 ) ;
r - > key = pSUBKEYEXPIRE ;
r - > u . expire = seconds ;
r - > next = para ;
para = r ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
do_generate_keypair ( para , outctrl , card ) ;
return 0 ;
2003-06-05 07:14:21 +00:00
}
/****************
* Kludge to allow non interactive key generation controlled
2006-04-19 11:26:11 +00:00
* by a parameter file .
2003-06-05 07:14:21 +00:00
* Note , that string parameters are expected to be in UTF - 8
*/
static void
read_parameter_file ( const char * fname )
{
static struct { const char * name ;
enum para_name key ;
} keywords [ ] = {
{ " Key-Type " , pKEYTYPE } ,
{ " Key-Length " , pKEYLENGTH } ,
{ " Key-Usage " , pKEYUSAGE } ,
{ " Subkey-Type " , pSUBKEYTYPE } ,
{ " Subkey-Length " , pSUBKEYLENGTH } ,
{ " Subkey-Usage " , pSUBKEYUSAGE } ,
{ " Name-Real " , pNAMEREAL } ,
{ " Name-Email " , pNAMEEMAIL } ,
{ " Name-Comment " , pNAMECOMMENT } ,
{ " Expire-Date " , pEXPIREDATE } ,
2007-07-05 16:58:19 +00:00
{ " Creation-Date " , pCREATIONDATE } ,
2003-06-05 07:14:21 +00:00
{ " Passphrase " , pPASSPHRASE } ,
{ " Preferences " , pPREFERENCES } ,
{ " Revoker " , pREVOKER } ,
2006-04-19 11:26:11 +00:00
{ " Handle " , pHANDLE } ,
2006-06-27 14:30:59 +00:00
{ " Keyserver " , pKEYSERVER } ,
2003-06-05 07:14:21 +00:00
{ NULL , 0 }
} ;
2006-04-19 11:26:11 +00:00
IOBUF fp ;
byte * line ;
unsigned int maxlen , nline ;
char * p ;
2003-06-05 07:14:21 +00:00
int lnr ;
const char * err = NULL ;
struct para_data_s * para , * r ;
int i ;
struct output_control_s outctrl ;
memset ( & outctrl , 0 , sizeof ( outctrl ) ) ;
2006-12-06 10:16:50 +00:00
outctrl . pub . afx = new_armor_context ( ) ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
if ( ! fname | | ! * fname )
fname = " - " ;
fp = iobuf_open ( fname ) ;
if ( fp & & is_secured_file ( iobuf_get_fd ( fp ) ) )
{
iobuf_close ( fp ) ;
fp = NULL ;
2010-04-01 13:24:55 +00:00
gpg_err_set_errno ( EPERM ) ;
2006-04-19 11:26:11 +00:00
}
if ( ! fp ) {
log_error ( _ ( " can't open `%s': %s \n " ) , fname , strerror ( errno ) ) ;
return ;
2003-06-05 07:14:21 +00:00
}
2010-03-08 17:05:37 +00:00
iobuf_ioctl ( fp , IOBUF_IOCTL_NO_CACHE , 1 , NULL ) ;
2003-06-05 07:14:21 +00:00
lnr = 0 ;
err = NULL ;
para = NULL ;
2006-04-19 11:26:11 +00:00
maxlen = 1024 ;
line = NULL ;
while ( iobuf_read_line ( fp , & line , & nline , & maxlen ) ) {
2003-06-05 07:14:21 +00:00
char * keyword , * value ;
lnr + + ;
2006-04-19 11:26:11 +00:00
if ( ! maxlen ) {
2003-06-05 07:14:21 +00:00
err = " line too long " ;
break ;
}
for ( p = line ; isspace ( * ( byte * ) p ) ; p + + )
;
if ( ! * p | | * p = = ' # ' )
continue ;
keyword = p ;
if ( * keyword = = ' % ' ) {
for ( ; ! isspace ( * ( byte * ) p ) ; p + + )
;
if ( * p )
* p + + = 0 ;
for ( ; isspace ( * ( byte * ) p ) ; p + + )
;
value = p ;
trim_trailing_ws ( value , strlen ( value ) ) ;
if ( ! ascii_strcasecmp ( keyword , " %echo " ) )
log_info ( " %s \n " , value ) ;
else if ( ! ascii_strcasecmp ( keyword , " %dry-run " ) )
outctrl . dryrun = 1 ;
2008-06-16 15:48:33 +00:00
else if ( ! ascii_strcasecmp ( keyword , " %ask-passphrase " ) )
outctrl . ask_passphrase = 1 ;
else if ( ! ascii_strcasecmp ( keyword , " %no-ask-passphrase " ) )
outctrl . ask_passphrase = 0 ;
2010-10-14 16:34:31 +00:00
else if ( ! ascii_strcasecmp ( keyword , " %no-protection " ) )
outctrl . keygen_flags | = KEYGEN_FLAG_NO_PROTECTION ;
else if ( ! ascii_strcasecmp ( keyword , " %transient-key " ) )
outctrl . keygen_flags | = KEYGEN_FLAG_TRANSIENT_KEY ;
2003-06-05 07:14:21 +00:00
else if ( ! ascii_strcasecmp ( keyword , " %commit " ) ) {
outctrl . lnr = lnr ;
2006-04-19 11:26:11 +00:00
if ( proc_parameter_file ( para , fname , & outctrl , 0 ) )
print_status_key_not_created
( get_parameter_value ( para , pHANDLE ) ) ;
2003-06-05 07:14:21 +00:00
release_parameter_list ( para ) ;
para = NULL ;
}
else if ( ! ascii_strcasecmp ( keyword , " %pubring " ) ) {
if ( outctrl . pub . fname & & ! strcmp ( outctrl . pub . fname , value ) )
; /* still the same file - ignore it */
else {
2006-04-19 11:26:11 +00:00
xfree ( outctrl . pub . newfname ) ;
outctrl . pub . newfname = xstrdup ( value ) ;
2003-06-05 07:14:21 +00:00
outctrl . use_files = 1 ;
}
}
else if ( ! ascii_strcasecmp ( keyword , " %secring " ) ) {
2010-11-17 13:21:24 +00:00
/* Ignore this command. */
2003-06-05 07:14:21 +00:00
}
else
log_info ( " skipping control `%s' (%s) \n " , keyword , value ) ;
continue ;
}
if ( ! ( p = strchr ( p , ' : ' ) ) | | p = = keyword ) {
err = " missing colon " ;
break ;
}
if ( * p )
* p + + = 0 ;
for ( ; isspace ( * ( byte * ) p ) ; p + + )
;
if ( ! * p ) {
err = " missing argument " ;
break ;
}
value = p ;
trim_trailing_ws ( value , strlen ( value ) ) ;
for ( i = 0 ; keywords [ i ] . name ; i + + ) {
if ( ! ascii_strcasecmp ( keywords [ i ] . name , keyword ) )
break ;
}
if ( ! keywords [ i ] . name ) {
err = " unknown keyword " ;
break ;
}
if ( keywords [ i ] . key ! = pKEYTYPE & & ! para ) {
err = " parameter block does not start with \" Key-Type \" " ;
break ;
}
if ( keywords [ i ] . key = = pKEYTYPE & & para ) {
outctrl . lnr = lnr ;
2006-04-19 11:26:11 +00:00
if ( proc_parameter_file ( para , fname , & outctrl , 0 ) )
print_status_key_not_created
( get_parameter_value ( para , pHANDLE ) ) ;
2003-06-05 07:14:21 +00:00
release_parameter_list ( para ) ;
para = NULL ;
}
else {
for ( r = para ; r ; r = r - > next ) {
if ( r - > key = = keywords [ i ] . key )
break ;
}
if ( r ) {
err = " duplicate keyword " ;
break ;
}
}
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + strlen ( value ) ) ;
2003-06-05 07:14:21 +00:00
r - > lnr = lnr ;
r - > key = keywords [ i ] . key ;
strcpy ( r - > u . value , value ) ;
r - > next = para ;
para = r ;
}
if ( err )
log_error ( " %s:%d: %s \n " , fname , lnr , err ) ;
2006-04-19 11:26:11 +00:00
else if ( iobuf_error ( fp ) ) {
log_error ( " %s:%d: read error \n " , fname , lnr ) ;
2003-06-05 07:14:21 +00:00
}
else if ( para ) {
outctrl . lnr = lnr ;
2006-04-19 11:26:11 +00:00
if ( proc_parameter_file ( para , fname , & outctrl , 0 ) )
print_status_key_not_created ( get_parameter_value ( para , pHANDLE ) ) ;
2003-06-05 07:14:21 +00:00
}
if ( outctrl . use_files ) { /* close open streams */
iobuf_close ( outctrl . pub . stream ) ;
2006-04-19 11:26:11 +00:00
/* Must invalidate that ugly cache to actually close it. */
if ( outctrl . pub . fname )
2010-03-08 17:05:37 +00:00
iobuf_ioctl ( NULL , IOBUF_IOCTL_INVALIDATE_CACHE ,
0 , ( char * ) outctrl . pub . fname ) ;
2006-04-19 11:26:11 +00:00
xfree ( outctrl . pub . fname ) ;
xfree ( outctrl . pub . newfname ) ;
2003-06-05 07:14:21 +00:00
}
release_parameter_list ( para ) ;
2006-04-19 11:26:11 +00:00
iobuf_close ( fp ) ;
2006-12-06 10:16:50 +00:00
release_armor_context ( outctrl . pub . afx ) ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
/*
2003-10-08 10:46:58 +00:00
* Generate a keypair ( fname is only used in batch mode ) If
2006-05-23 16:19:43 +00:00
* CARD_SERIALNO is not NULL the function will create the keys on an
2010-11-17 13:21:24 +00:00
* OpenPGP Card . If CARD_BACKUP_KEY has been set and CARD_SERIALNO is
* NOT NULL , the encryption key for the card is generated on the host ,
* imported to the card and a backup file created by gpg - agent .
2003-06-05 07:14:21 +00:00
*/
void
2006-04-19 11:26:11 +00:00
generate_keypair ( const char * fname , const char * card_serialno ,
2010-11-17 13:21:24 +00:00
int card_backup_key )
2003-06-05 07:14:21 +00:00
{
2003-06-27 20:53:09 +00:00
unsigned int nbits ;
char * uid = NULL ;
int algo ;
unsigned int use ;
int both = 0 ;
u32 expire ;
struct para_data_s * para = NULL ;
struct para_data_s * r ;
struct output_control_s outctrl ;
2006-04-19 11:26:11 +00:00
memset ( & outctrl , 0 , sizeof ( outctrl ) ) ;
2003-10-08 10:46:58 +00:00
if ( opt . batch & & card_serialno )
2003-06-27 20:53:09 +00:00
{
2003-10-08 10:46:58 +00:00
/* We don't yet support unattended key generation. */
2006-04-19 11:26:11 +00:00
log_error ( _ ( " can't do this in batch mode \n " ) ) ;
2003-06-27 20:53:09 +00:00
return ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
2003-10-08 10:46:58 +00:00
if ( opt . batch )
2003-06-27 20:53:09 +00:00
{
2003-10-08 10:46:58 +00:00
read_parameter_file ( fname ) ;
return ;
2003-06-05 07:14:21 +00:00
}
2003-10-08 10:46:58 +00:00
if ( card_serialno )
2003-07-01 08:34:45 +00:00
{
2006-04-19 11:26:11 +00:00
# ifdef ENABLE_CARD_SUPPORT
2003-10-08 10:46:58 +00:00
r = xcalloc ( 1 , sizeof * r + strlen ( card_serialno ) ) ;
2003-07-01 08:34:45 +00:00
r - > key = pSERIALNO ;
2003-10-08 10:46:58 +00:00
strcpy ( r - > u . value , card_serialno ) ;
2003-07-01 08:34:45 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2003-06-27 20:53:09 +00:00
algo = PUBKEY_ALGO_RSA ;
2006-04-19 11:26:11 +00:00
2003-06-27 20:53:09 +00:00
r = xcalloc ( 1 , sizeof * r + 20 ) ;
r - > key = pKEYTYPE ;
2003-07-03 18:08:16 +00:00
sprintf ( r - > u . value , " %d " , algo ) ;
2003-06-27 20:53:09 +00:00
r - > next = para ;
para = r ;
r = xcalloc ( 1 , sizeof * r + 20 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pKEYUSAGE ;
strcpy ( r - > u . value , " sign " ) ;
2003-06-27 20:53:09 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2003-06-27 20:53:09 +00:00
r = xcalloc ( 1 , sizeof * r + 20 ) ;
r - > key = pSUBKEYTYPE ;
sprintf ( r - > u . value , " %d " , algo ) ;
r - > next = para ;
para = r ;
r = xcalloc ( 1 , sizeof * r + 20 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pSUBKEYUSAGE ;
strcpy ( r - > u . value , " encrypt " ) ;
2003-06-27 20:53:09 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2003-07-23 07:11:06 +00:00
r = xcalloc ( 1 , sizeof * r + 20 ) ;
r - > key = pAUTHKEYTYPE ;
sprintf ( r - > u . value , " %d " , algo ) ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2010-11-17 13:21:24 +00:00
if ( card_backup_key )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
r = xcalloc ( 1 , sizeof * r + 1 ) ;
r - > key = pCARDBACKUPKEY ;
strcpy ( r - > u . value , " 1 " ) ;
2006-04-19 11:26:11 +00:00
r - > next = para ;
para = r ;
}
# endif /*ENABLE_CARD_SUPPORT*/
2003-07-03 18:08:16 +00:00
}
else
{
2009-05-17 13:08:18 +00:00
int subkey_algo ;
algo = ask_algo ( 0 , & subkey_algo , & use ) ;
if ( subkey_algo )
{
/* Create primary and subkey at once. */
2003-07-03 18:08:16 +00:00
both = 1 ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pKEYTYPE ;
2009-05-17 13:08:18 +00:00
sprintf ( r - > u . value , " %d " , algo ) ;
2003-07-03 18:08:16 +00:00
r - > next = para ;
para = r ;
2009-05-17 13:08:18 +00:00
nbits = ask_keysize ( algo , 0 ) ;
2006-06-27 14:30:59 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
r - > key = pKEYLENGTH ;
sprintf ( r - > u . value , " %u " , nbits ) ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-09-23 17:48:33 +00:00
r - > key = pKEYUSAGE ;
strcpy ( r - > u . value , " sign " ) ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pSUBKEYTYPE ;
2009-05-17 13:08:18 +00:00
sprintf ( r - > u . value , " %d " , subkey_algo ) ;
2003-07-03 18:08:16 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-09-23 17:48:33 +00:00
r - > key = pSUBKEYUSAGE ;
strcpy ( r - > u . value , " encrypt " ) ;
r - > next = para ;
para = r ;
2003-07-03 18:08:16 +00:00
}
else
2003-06-27 20:53:09 +00:00
{
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pKEYTYPE ;
sprintf ( r - > u . value , " %d " , algo ) ;
2003-06-27 20:53:09 +00:00
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2003-07-03 18:08:16 +00:00
if ( use )
{
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 25 ) ;
2003-07-03 18:08:16 +00:00
r - > key = pKEYUSAGE ;
2006-04-19 11:26:11 +00:00
sprintf ( r - > u . value , " %s%s%s " ,
2003-07-03 18:08:16 +00:00
( use & PUBKEY_USAGE_SIG ) ? " sign " : " " ,
2006-04-19 11:26:11 +00:00
( use & PUBKEY_USAGE_ENC ) ? " encrypt " : " " ,
( use & PUBKEY_USAGE_AUTH ) ? " auth " : " " ) ;
2003-07-03 18:08:16 +00:00
r - > next = para ;
para = r ;
}
2009-05-17 13:08:18 +00:00
nbits = 0 ;
2003-06-05 07:14:21 +00:00
}
2006-06-27 14:30:59 +00:00
2009-07-20 11:02:20 +00:00
nbits = ask_keysize ( both ? subkey_algo : algo , nbits ) ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-06-27 20:53:09 +00:00
r - > key = both ? pSUBKEYLENGTH : pKEYLENGTH ;
sprintf ( r - > u . value , " %u " , nbits ) ;
r - > next = para ;
para = r ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
expire = ask_expire_interval ( 0 , NULL ) ;
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-06-27 20:53:09 +00:00
r - > key = pKEYEXPIRE ;
r - > u . expire = expire ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + 20 ) ;
2003-06-27 20:53:09 +00:00
r - > key = pSUBKEYEXPIRE ;
r - > u . expire = expire ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2009-09-03 20:51:55 +00:00
uid = ask_user_id ( 0 , NULL ) ;
2006-04-19 11:26:11 +00:00
if ( ! uid )
2003-06-27 20:53:09 +00:00
{
log_error ( _ ( " Key generation canceled. \n " ) ) ;
release_parameter_list ( para ) ;
return ;
}
2006-04-19 11:26:11 +00:00
r = xmalloc_clear ( sizeof * r + strlen ( uid ) ) ;
2003-06-27 20:53:09 +00:00
r - > key = pUSERID ;
strcpy ( r - > u . value , uid ) ;
r - > next = para ;
para = r ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
proc_parameter_file ( para , " [internal] " , & outctrl , ! ! card_serialno ) ;
2006-04-19 11:26:11 +00:00
release_parameter_list ( para ) ;
2003-06-05 07:14:21 +00:00
}
2010-11-17 13:21:24 +00:00
#if 0 /* not required */
2006-04-19 11:26:11 +00:00
/* Generate a raw key and return it as a secret key packet. The
function will ask for the passphrase and return a protected as well
as an unprotected copy of a new secret key packet . 0 is returned
on success and the caller must then free the returned values . */
static int
generate_raw_key ( int algo , unsigned int nbits , u32 created_at ,
PKT_secret_key * * r_sk_unprotected ,
PKT_secret_key * * r_sk_protected )
2003-06-05 07:14:21 +00:00
{
2006-04-19 11:26:11 +00:00
int rc ;
DEK * dek = NULL ;
STRING2KEY * s2k = NULL ;
PKT_secret_key * sk = NULL ;
int i ;
size_t nskey , npkey ;
2006-08-16 10:47:53 +00:00
gcry_sexp_t s_parms , s_key ;
2006-12-06 10:16:50 +00:00
int canceled ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
npkey = pubkey_get_npkey ( algo ) ;
nskey = pubkey_get_nskey ( algo ) ;
assert ( nskey < = PUBKEY_MAX_NSKEY & & npkey < nskey ) ;
2003-06-27 20:53:09 +00:00
2006-04-19 11:26:11 +00:00
if ( nbits < 512 )
{
nbits = 512 ;
log_info ( _ ( " keysize invalid; using %u bits \n " ) , nbits ) ;
}
2003-06-27 20:53:09 +00:00
2006-04-19 11:26:11 +00:00
if ( ( nbits % 32 ) )
{
nbits = ( ( nbits + 31 ) / 32 ) * 32 ;
log_info ( _ ( " keysize rounded up to %u bits \n " ) , nbits ) ;
}
2009-05-15 19:26:46 +00:00
dek = do_ask_passphrase ( & s2k , 1 , & canceled ) ;
2006-12-06 10:16:50 +00:00
if ( canceled )
{
rc = gpg_error ( GPG_ERR_CANCELED ) ;
goto leave ;
}
2006-04-19 11:26:11 +00:00
sk = xmalloc_clear ( sizeof * sk ) ;
sk - > timestamp = created_at ;
sk - > version = 4 ;
sk - > pubkey_algo = algo ;
2003-06-27 20:53:09 +00:00
2006-04-19 11:26:11 +00:00
if ( ! is_RSA ( algo ) )
2003-06-27 20:53:09 +00:00
{
2006-04-19 11:26:11 +00:00
log_error ( " only RSA is supported for offline generated keys \n " ) ;
rc = gpg_error ( GPG_ERR_NOT_IMPLEMENTED ) ;
goto leave ;
}
rc = gcry_sexp_build ( & s_parms , NULL ,
" (genkey(rsa(nbits %d))) " ,
( int ) nbits ) ;
if ( rc )
log_bug ( " gcry_sexp_build failed: %s \n " , gpg_strerror ( rc ) ) ;
rc = gcry_pk_genkey ( & s_key , s_parms ) ;
gcry_sexp_release ( s_parms ) ;
if ( rc )
{
log_error ( " gcry_pk_genkey failed: %s \n " , gpg_strerror ( rc ) ) ;
goto leave ;
}
rc = key_from_sexp ( sk - > skey , s_key , " private-key " , " nedpqu " ) ;
gcry_sexp_release ( s_key ) ;
if ( rc )
{
log_error ( " key_from_sexp failed: %s \n " , gpg_strerror ( rc ) ) ;
goto leave ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
for ( i = npkey ; i < nskey ; i + + )
sk - > csum + = checksum_mpi ( sk - > skey [ i ] ) ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
if ( r_sk_unprotected )
* r_sk_unprotected = copy_secret_key ( NULL , sk ) ;
2003-06-05 07:14:21 +00:00
2006-04-19 11:26:11 +00:00
rc = genhelp_protect ( dek , s2k , sk ) ;
if ( rc )
goto leave ;
if ( r_sk_protected )
2003-06-27 20:53:09 +00:00
{
2006-04-19 11:26:11 +00:00
* r_sk_protected = sk ;
sk = NULL ;
}
leave :
if ( sk )
free_secret_key ( sk ) ;
xfree ( dek ) ;
xfree ( s2k ) ;
return rc ;
}
# endif /* ENABLE_CARD_SUPPORT */
/* Create and delete a dummy packet to start off a list of kbnodes. */
static void
start_tree ( KBNODE * tree )
{
PACKET * pkt ;
pkt = xmalloc_clear ( sizeof ( * pkt ) ) ;
pkt - > pkttype = PKT_NONE ;
* tree = new_kbnode ( pkt ) ;
delete_kbnode ( * tree ) ;
}
2007-07-05 16:58:19 +00:00
2006-04-19 11:26:11 +00:00
static void
2007-07-05 16:58:19 +00:00
do_generate_keypair ( struct para_data_s * para ,
struct output_control_s * outctrl , int card )
2006-04-19 11:26:11 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err ;
2007-07-05 16:58:19 +00:00
KBNODE pub_root = NULL ;
const char * s ;
2010-04-20 17:57:50 +00:00
PKT_public_key * pri_psk = NULL ;
PKT_public_key * sub_psk = NULL ;
2007-07-05 16:58:19 +00:00
struct revocation_key * revkey ;
int did_sub = 0 ;
u32 timestamp ;
2010-09-01 09:48:35 +00:00
char * cache_nonce = NULL ;
2006-04-19 11:26:11 +00:00
2010-04-20 17:57:50 +00:00
if ( outctrl - > dryrun )
2007-07-05 16:58:19 +00:00
{
log_info ( " dry-run mode - key generation skipped \n " ) ;
return ;
}
if ( outctrl - > use_files )
{
if ( outctrl - > pub . newfname )
{
iobuf_close ( outctrl - > pub . stream ) ;
outctrl - > pub . stream = NULL ;
if ( outctrl - > pub . fname )
2010-03-08 17:05:37 +00:00
iobuf_ioctl ( NULL , IOBUF_IOCTL_INVALIDATE_CACHE ,
0 , ( char * ) outctrl - > pub . fname ) ;
2007-07-05 16:58:19 +00:00
xfree ( outctrl - > pub . fname ) ;
outctrl - > pub . fname = outctrl - > pub . newfname ;
outctrl - > pub . newfname = NULL ;
if ( is_secured_filename ( outctrl - > pub . fname ) )
{
outctrl - > pub . stream = NULL ;
2010-04-01 13:24:55 +00:00
gpg_err_set_errno ( EPERM ) ;
2006-04-19 11:26:11 +00:00
}
2007-07-05 16:58:19 +00:00
else
outctrl - > pub . stream = iobuf_create ( outctrl - > pub . fname ) ;
if ( ! outctrl - > pub . stream )
{
log_error ( _ ( " can't create `%s': %s \n " ) , outctrl - > pub . newfname ,
strerror ( errno ) ) ;
return ;
2006-04-19 11:26:11 +00:00
}
2007-07-05 16:58:19 +00:00
if ( opt . armor )
{
outctrl - > pub . afx - > what = 1 ;
push_armor_filter ( outctrl - > pub . afx , outctrl - > pub . stream ) ;
}
}
assert ( outctrl - > pub . stream ) ;
if ( opt . verbose )
2010-04-20 17:57:50 +00:00
log_info ( _ ( " writing public key to `%s' \n " ) , outctrl - > pub . fname ) ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
/* We create the packets as a tree of kbnodes. Because the
structure we create is known in advance we simply generate a
linked list . The first packet is a dummy packet which we flag as
deleted . The very first packet must always be a KEY packet . */
2006-04-19 11:26:11 +00:00
2007-07-05 16:58:19 +00:00
start_tree ( & pub_root ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
timestamp = get_parameter_u32 ( para , pKEYCREATIONDATE ) ;
if ( ! timestamp )
timestamp = make_timestamp ( ) ;
2003-06-05 07:14:21 +00:00
2009-07-20 11:02:20 +00:00
/* Note that, depending on the backend (i.e. the used scdaemon
version ) , the card key generation may update TIMESTAMP for each
key . Thus we need to pass TIMESTAMP to all signing function to
make sure that the binding signature is done using the timestamp
of the corresponding ( sub ) key and not that of the primary key .
An alternative implementation could tell the signing function the
node of the subkey but that is more work than just to pass the
current timestamp . */
2007-07-05 16:58:19 +00:00
if ( ! card )
2010-04-20 17:57:50 +00:00
err = do_create ( get_parameter_algo ( para , pKEYTYPE , NULL ) ,
get_parameter_uint ( para , pKEYLENGTH ) ,
pub_root ,
timestamp ,
2010-10-14 16:34:31 +00:00
get_parameter_u32 ( para , pKEYEXPIRE ) , 0 ,
outctrl - > keygen_flags , & cache_nonce ) ;
2007-07-05 16:58:19 +00:00
else
2010-04-20 17:57:50 +00:00
err = gen_card_key ( PUBKEY_ALGO_RSA , 1 , 1 , pub_root ,
& timestamp ,
2010-11-17 13:21:24 +00:00
get_parameter_u32 ( para , pKEYEXPIRE ) ) ;
2003-06-27 20:53:09 +00:00
2010-04-20 17:57:50 +00:00
/* Get the pointer to the generated public key packet. */
if ( ! err )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
pri_psk = pub_root - > next - > pkt - > pkt . public_key ;
assert ( pri_psk ) ;
2007-07-05 16:58:19 +00:00
}
2003-07-03 18:08:16 +00:00
2010-04-20 17:57:50 +00:00
if ( ! err & & ( revkey = get_parameter_revkey ( para , pREVOKER ) ) )
2010-09-01 12:49:05 +00:00
err = write_direct_sig ( pub_root , pri_psk , revkey , timestamp , cache_nonce ) ;
2010-04-20 17:57:50 +00:00
if ( ! err & & ( s = get_parameter_value ( para , pUSERID ) ) )
2007-07-05 16:58:19 +00:00
{
write_uid ( pub_root , s ) ;
2010-04-20 17:57:50 +00:00
err = write_selfsigs ( pub_root , pri_psk ,
2010-09-01 12:49:05 +00:00
get_parameter_uint ( para , pKEYUSAGE ) , timestamp ,
cache_nonce ) ;
2007-07-05 16:58:19 +00:00
}
2003-07-23 07:11:06 +00:00
2007-07-05 16:58:19 +00:00
/* Write the auth key to the card before the encryption key. This
is a partial workaround for a PGP bug ( as of this writing , all
versions including 8.1 ) , that causes it to try and encrypt to
the most recent subkey regardless of whether that subkey is
actually an encryption type . In this case , the auth key is an
RSA key so it succeeds . */
2010-04-20 17:57:50 +00:00
if ( ! err & & card & & get_parameter ( para , pAUTHKEYTYPE ) )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = gen_card_key ( PUBKEY_ALGO_RSA , 3 , 0 , pub_root ,
& timestamp ,
2010-11-17 13:21:24 +00:00
get_parameter_u32 ( para , pKEYEXPIRE ) ) ;
2010-04-20 17:57:50 +00:00
if ( ! err )
err = write_keybinding ( pub_root , pri_psk , NULL ,
2010-09-01 12:49:05 +00:00
PUBKEY_USAGE_AUTH , timestamp , cache_nonce ) ;
2007-07-05 16:58:19 +00:00
}
2003-07-23 07:11:06 +00:00
2010-04-20 17:57:50 +00:00
if ( ! err & & get_parameter ( para , pSUBKEYTYPE ) )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
sub_psk = NULL ;
2007-07-05 16:58:19 +00:00
if ( ! card )
{
2010-04-20 17:57:50 +00:00
err = do_create ( get_parameter_algo ( para , pSUBKEYTYPE , NULL ) ,
get_parameter_uint ( para , pSUBKEYLENGTH ) ,
pub_root ,
timestamp ,
2010-09-01 09:48:35 +00:00
get_parameter_u32 ( para , pSUBKEYEXPIRE ) , 1 ,
2010-10-14 16:34:31 +00:00
outctrl - > keygen_flags , & cache_nonce ) ;
2010-04-20 17:57:50 +00:00
/* Get the pointer to the generated public subkey packet. */
if ( ! err )
{
kbnode_t node ;
for ( node = pub_root ; node ; node = node - > next )
if ( node - > pkt - > pkttype = = PKT_PUBLIC_SUBKEY )
sub_psk = node - > pkt - > pkt . public_key ;
assert ( sub_psk ) ;
}
2007-07-05 16:58:19 +00:00
}
else
{
2010-11-17 13:21:24 +00:00
if ( ( s = get_parameter_value ( para , pCARDBACKUPKEY ) ) )
2007-07-05 16:58:19 +00:00
{
/* A backup of the encryption key has been requested.
Generate the key in software and import it then to
the card . Write a backup file . */
2010-11-17 13:21:24 +00:00
err = gen_card_key_with_backup
( PUBKEY_ALGO_RSA , 2 , 0 , pub_root , timestamp ,
get_parameter_u32 ( para , pKEYEXPIRE ) , para ) ;
2007-07-05 16:58:19 +00:00
}
else
{
2010-04-20 17:57:50 +00:00
err = gen_card_key ( PUBKEY_ALGO_RSA , 2 , 0 , pub_root ,
& timestamp ,
2010-11-17 13:21:24 +00:00
get_parameter_u32 ( para , pKEYEXPIRE ) ) ;
2007-07-05 16:58:19 +00:00
}
}
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
if ( ! err )
err = write_keybinding ( pub_root , pri_psk , sub_psk ,
get_parameter_uint ( para , pSUBKEYUSAGE ) ,
2010-09-01 12:49:05 +00:00
timestamp , cache_nonce ) ;
2007-07-05 16:58:19 +00:00
did_sub = 1 ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
if ( ! err & & outctrl - > use_files ) /* Direct write to specified files. */
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = write_keyblock ( outctrl - > pub . stream , pub_root ) ;
if ( err )
log_error ( " can't write public key: %s \n " , g10_errstr ( err ) ) ;
2007-07-05 16:58:19 +00:00
}
2010-04-20 17:57:50 +00:00
else if ( ! err ) /* Write to the standard keyrings. */
2007-07-05 16:58:19 +00:00
{
2010-04-21 16:26:17 +00:00
KEYDB_HANDLE pub_hd = keydb_new ( ) ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
err = keydb_locate_writable ( pub_hd , NULL ) ;
if ( err )
2007-07-05 16:58:19 +00:00
log_error ( _ ( " no writable public keyring found: %s \n " ) ,
2010-04-20 17:57:50 +00:00
g10_errstr ( err ) ) ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
if ( ! err & & opt . verbose )
2007-07-05 16:58:19 +00:00
{
log_info ( _ ( " writing public key to `%s' \n " ) ,
keydb_get_resource_name ( pub_hd ) ) ;
2006-04-19 11:26:11 +00:00
}
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
if ( ! err )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
err = keydb_insert_keyblock ( pub_hd , pub_root ) ;
if ( err )
2007-07-05 16:58:19 +00:00
log_error ( _ ( " error writing public keyring `%s': %s \n " ) ,
2010-04-20 17:57:50 +00:00
keydb_get_resource_name ( pub_hd ) , g10_errstr ( err ) ) ;
2006-04-19 11:26:11 +00:00
}
2007-07-05 16:58:19 +00:00
keydb_release ( pub_hd ) ;
2010-04-20 17:57:50 +00:00
if ( ! err )
2007-07-05 16:58:19 +00:00
{
int no_enc_rsa ;
PKT_public_key * pk ;
2009-12-04 19:47:54 +00:00
no_enc_rsa = ( ( get_parameter_algo ( para , pKEYTYPE , NULL )
= = PUBKEY_ALGO_RSA )
2007-07-05 16:58:19 +00:00
& & get_parameter_uint ( para , pKEYUSAGE )
& & ! ( ( get_parameter_uint ( para , pKEYUSAGE )
& PUBKEY_USAGE_ENC ) ) ) ;
2003-06-27 20:53:09 +00:00
2007-07-05 16:58:19 +00:00
pk = find_kbnode ( pub_root , PKT_PUBLIC_KEY ) - > pkt - > pkt . public_key ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
keyid_from_pk ( pk , pk - > main_keyid ) ;
register_trusted_keyid ( pk - > main_keyid ) ;
2003-06-05 07:14:21 +00:00
2007-07-05 16:58:19 +00:00
update_ownertrust ( pk , ( ( get_ownertrust ( pk ) & ~ TRUST_MASK )
| TRUST_ULTIMATE ) ) ;
2003-09-02 19:06:34 +00:00
2007-07-05 16:58:19 +00:00
if ( ! opt . batch )
{
tty_printf ( _ ( " public and secret key created and signed. \n " ) ) ;
tty_printf ( " \n " ) ;
2010-04-20 17:57:50 +00:00
list_keyblock ( pub_root , 0 , 1 , NULL ) ;
2003-09-02 19:06:34 +00:00
}
2006-04-19 11:26:11 +00:00
2007-07-05 16:58:19 +00:00
if ( ! opt . batch
2009-12-04 19:47:54 +00:00
& & ( get_parameter_algo ( para , pKEYTYPE , NULL ) = = PUBKEY_ALGO_DSA
2007-07-05 16:58:19 +00:00
| | no_enc_rsa )
& & ! get_parameter ( para , pSUBKEYTYPE ) )
{
tty_printf ( _ ( " Note that this key cannot be used for "
" encryption. You may want to use \n "
" the command \" --edit-key \" to generate a "
" subkey for this purpose. \n " ) ) ;
}
}
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
if ( err )
2007-07-05 16:58:19 +00:00
{
if ( opt . batch )
2010-04-20 17:57:50 +00:00
log_error ( " key generation failed: %s \n " , g10_errstr ( err ) ) ;
2007-07-05 16:58:19 +00:00
else
2010-04-20 17:57:50 +00:00
tty_printf ( _ ( " Key generation failed: %s \n " ) , g10_errstr ( err ) ) ;
write_status_error ( card ? " card_key_generate " : " key_generate " , err ) ;
2007-07-05 16:58:19 +00:00
print_status_key_not_created ( get_parameter_value ( para , pHANDLE ) ) ;
2003-06-05 07:14:21 +00:00
}
2007-07-05 16:58:19 +00:00
else
{
PKT_public_key * pk = find_kbnode ( pub_root ,
PKT_PUBLIC_KEY ) - > pkt - > pkt . public_key ;
print_status_key_created ( did_sub ? ' B ' : ' P ' , pk ,
get_parameter_value ( para , pHANDLE ) ) ;
}
2010-04-20 17:57:50 +00:00
release_kbnode ( pub_root ) ;
2010-09-01 09:48:35 +00:00
xfree ( cache_nonce ) ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
/* Add a new subkey to an existing key. Returns 0 if a new key has
2007-07-05 16:58:19 +00:00
been generated and put into the keyblocks . */
2010-04-20 17:57:50 +00:00
gpg_error_t
generate_subkeypair ( KBNODE keyblock )
2003-06-05 07:14:21 +00:00
{
2010-04-20 17:57:50 +00:00
gpg_error_t err = 0 ;
kbnode_t node ;
PKT_public_key * pri_psk = NULL ;
PKT_public_key * sub_psk = NULL ;
2007-07-05 16:58:19 +00:00
int algo ;
unsigned int use ;
u32 expire ;
2010-04-20 17:57:50 +00:00
unsigned int nbits ;
2007-07-05 16:58:19 +00:00
u32 cur_time ;
2010-10-13 15:57:08 +00:00
char * hexgrip = NULL ;
char * serialno = NULL ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
/* Break out the primary key. */
node = find_kbnode ( keyblock , PKT_PUBLIC_KEY ) ;
if ( ! node )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
log_error ( " Oops; primary key missing in keyblock! \n " ) ;
err = gpg_error ( GPG_ERR_BUG ) ;
2007-07-05 16:58:19 +00:00
goto leave ;
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
pri_psk = node - > pkt - > pkt . public_key ;
2007-07-05 16:58:19 +00:00
2010-04-20 17:57:50 +00:00
cur_time = make_timestamp ( ) ;
2003-06-05 07:14:21 +00:00
2010-04-20 17:57:50 +00:00
if ( pri_psk - > timestamp > cur_time )
2007-07-05 16:58:19 +00:00
{
2010-04-20 17:57:50 +00:00
ulong d = pri_psk - > timestamp - cur_time ;
2007-07-05 16:58:19 +00:00
log_info ( d = = 1 ? _ ( " key has been created %lu second "
" in future (time warp or clock problem) \n " )
: _ ( " key has been created %lu seconds "
" in future (time warp or clock problem) \n " ) , d ) ;
if ( ! opt . ignore_time_conflict )
{
2010-04-20 17:57:50 +00:00
err = gpg_error ( GPG_ERR_TIME_CONFLICT ) ;
2007-07-05 16:58:19 +00:00
goto leave ;
}
2003-06-05 07:14:21 +00:00
}
2010-04-20 17:57:50 +00:00
if ( pri_psk - > version < 4 )
2007-07-05 16:58:19 +00:00
{
log_info ( _ ( " NOTE: creating subkeys for v3 keys "
" is not OpenPGP compliant \n " ) ) ;
2010-04-20 17:57:50 +00:00
err = gpg_error ( GPG_ERR_CONFLICT ) ;
2007-07-05 16:58:19 +00:00
goto leave ;
2006-04-19 11:26:11 +00:00
}
2010-10-13 15:57:08 +00:00
err = hexkeygrip_from_pk ( pri_psk , & hexgrip ) ;
if ( err )
goto leave ;
if ( agent_get_keyinfo ( NULL , hexgrip , & serialno ) )
{
tty_printf ( _ ( " Secret parts of primary key are not available. \n " ) ) ;
goto leave ;
}
if ( serialno )
tty_printf ( _ ( " Secret parts of primary key are stored on-card. \n " ) ) ;
2003-06-05 07:14:21 +00:00
2009-05-17 13:08:18 +00:00
algo = ask_algo ( 1 , NULL , & use ) ;
2007-07-05 16:58:19 +00:00
assert ( algo ) ;
2009-05-17 13:08:18 +00:00
nbits = ask_keysize ( algo , 0 ) ;
2007-07-05 16:58:19 +00:00
expire = ask_expire_interval ( 0 , NULL ) ;
if ( ! cpr_enabled ( ) & & ! cpr_get_answer_is_yes ( " keygen.sub.okay " ,
_ ( " Really create? (y/N) " ) ) )
{
2010-04-20 17:57:50 +00:00
err = gpg_error ( GPG_ERR_CANCELED ) ;
goto leave ;
}
2010-10-14 16:34:31 +00:00
err = do_create ( algo , nbits , keyblock , cur_time , expire , 1 , 0 , NULL ) ;
2010-04-20 17:57:50 +00:00
if ( err )
goto leave ;
/* Get the pointer to the generated public subkey packet. */
for ( node = keyblock ; node ; node = node - > next )
if ( node - > pkt - > pkttype = = PKT_PUBLIC_SUBKEY )
sub_psk = node - > pkt - > pkt . public_key ;
/* Write the binding signature. */
2010-09-01 12:49:05 +00:00
err = write_keybinding ( keyblock , pri_psk , sub_psk , use , cur_time , NULL ) ;
2010-04-20 17:57:50 +00:00
if ( err )
goto leave ;
write_status_text ( STATUS_KEY_CREATED , " S " ) ;
2007-07-05 16:58:19 +00:00
leave :
2010-10-13 15:57:08 +00:00
xfree ( hexgrip ) ;
xfree ( serialno ) ;
2010-04-20 17:57:50 +00:00
if ( err )
log_error ( _ ( " Key generation failed: %s \n " ) , g10_errstr ( err ) ) ;
return err ;
2003-06-05 07:14:21 +00:00
}
2006-04-19 11:26:11 +00:00
# ifdef ENABLE_CARD_SUPPORT
/* Generate a subkey on a card. */
2010-11-17 13:21:24 +00:00
gpg_error_t
generate_card_subkeypair ( kbnode_t pub_keyblock ,
2006-04-19 11:26:11 +00:00
int keyno , const char * serialno )
{
2010-04-20 17:57:50 +00:00
gpg_error_t err = 0 ;
kbnode_t node ;
2010-11-17 13:21:24 +00:00
PKT_public_key * pri_pk = NULL ;
2006-04-19 11:26:11 +00:00
int algo ;
unsigned int use ;
u32 expire ;
u32 cur_time ;
struct para_data_s * para = NULL ;
assert ( keyno > = 1 & & keyno < = 3 ) ;
2010-11-17 13:21:24 +00:00
para = xtrycalloc ( 1 , sizeof * para + strlen ( serialno ) ) ;
if ( ! para )
{
err = gpg_error_from_syserror ( ) ;
goto leave ;
}
2006-04-19 11:26:11 +00:00
para - > key = pSERIALNO ;
strcpy ( para - > u . value , serialno ) ;
/* Break out the primary secret key */
2010-11-17 13:21:24 +00:00
node = find_kbnode ( pub_keyblock , PKT_PUBLIC_KEY ) ;
2007-07-05 16:58:19 +00:00
if ( ! node )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
log_error ( " Oops; publkic key lost! \n " ) ;
err = gpg_error ( GPG_ERR_INTERNAL ) ;
2006-04-19 11:26:11 +00:00
goto leave ;
}
2010-11-17 13:21:24 +00:00
pri_pk = node - > pkt - > pkt . public_key ;
2006-04-19 11:26:11 +00:00
cur_time = make_timestamp ( ) ;
2010-11-17 13:21:24 +00:00
if ( pri_pk - > timestamp > cur_time )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
ulong d = pri_pk - > timestamp - cur_time ;
2006-04-19 11:26:11 +00:00
log_info ( d = = 1 ? _ ( " key has been created %lu second "
" in future (time warp or clock problem) \n " )
: _ ( " key has been created %lu seconds "
" in future (time warp or clock problem) \n " ) , d ) ;
if ( ! opt . ignore_time_conflict )
{
2010-11-17 13:21:24 +00:00
err = gpg_error ( GPG_ERR_TIME_CONFLICT ) ;
2006-04-19 11:26:11 +00:00
goto leave ;
}
}
2010-11-17 13:21:24 +00:00
if ( pri_pk - > version < 4 )
2006-04-19 11:26:11 +00:00
{
log_info ( _ ( " NOTE: creating subkeys for v3 keys "
" is not OpenPGP compliant \n " ) ) ;
2010-11-17 13:21:24 +00:00
err = gpg_error ( GPG_ERR_NOT_SUPPORTED ) ;
2006-04-19 11:26:11 +00:00
goto leave ;
}
algo = PUBKEY_ALGO_RSA ;
2010-11-17 13:21:24 +00:00
expire = ask_expire_interval ( 0 , NULL ) ;
2006-04-19 11:26:11 +00:00
if ( keyno = = 1 )
use = PUBKEY_USAGE_SIG ;
else if ( keyno = = 2 )
use = PUBKEY_USAGE_ENC ;
else
use = PUBKEY_USAGE_AUTH ;
if ( ! cpr_enabled ( ) & & ! cpr_get_answer_is_yes ( " keygen.cardsub.okay " ,
_ ( " Really create? (y/N) " ) ) )
2010-11-17 13:21:24 +00:00
{
err = gpg_error ( GPG_ERR_CANCELED ) ;
goto leave ;
}
2007-07-05 16:58:19 +00:00
/* Note, that depending on the backend, the card key generation may
update CUR_TIME . */
2010-11-17 13:21:24 +00:00
err = gen_card_key ( algo , keyno , 0 , pub_keyblock , & cur_time , expire ) ;
/* Get the pointer to the generated public subkey packet. */
2010-04-20 17:57:50 +00:00
if ( ! err )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
PKT_public_key * sub_pk = NULL ;
for ( node = pub_keyblock ; node ; node = node - > next )
if ( node - > pkt - > pkttype = = PKT_PUBLIC_SUBKEY )
sub_pk = node - > pkt - > pkt . public_key ;
assert ( sub_pk ) ;
err = write_keybinding ( pub_keyblock , pri_pk , sub_pk ,
use , cur_time , NULL ) ;
2006-04-19 11:26:11 +00:00
}
leave :
2010-04-20 17:57:50 +00:00
if ( err )
log_error ( _ ( " Key generation failed: %s \n " ) , g10_errstr ( err ) ) ;
2010-11-17 13:21:24 +00:00
else
write_status_text ( STATUS_KEY_CREATED , " S " ) ;
2006-04-19 11:26:11 +00:00
release_parameter_list ( para ) ;
2010-11-17 13:21:24 +00:00
return err ;
2006-04-19 11:26:11 +00:00
}
# endif /* !ENABLE_CARD_SUPPORT */
2007-07-05 16:58:19 +00:00
/*
2003-06-05 07:14:21 +00:00
* Write a keyblock to an output stream
*/
static int
2006-04-19 11:26:11 +00:00
write_keyblock ( IOBUF out , KBNODE node )
2003-06-05 07:14:21 +00:00
{
2006-04-19 11:26:11 +00:00
for ( ; node ; node = node - > next )
{
if ( ! is_deleted_kbnode ( node ) )
{
int rc = build_packet ( out , node - > pkt ) ;
if ( rc )
{
log_error ( " build_packet(%d) failed: %s \n " ,
node - > pkt - > pkttype , g10_errstr ( rc ) ) ;
2006-04-19 13:24:36 +00:00
return rc ;
2006-04-19 11:26:11 +00:00
}
2003-06-05 07:14:21 +00:00
}
}
2006-04-19 11:26:11 +00:00
return 0 ;
2003-06-05 07:14:21 +00:00
}
2003-06-27 20:53:09 +00:00
2007-07-05 16:58:19 +00:00
/* Note that timestamp is an in/out arg. */
2010-11-17 13:21:24 +00:00
static gpg_error_t
gen_card_key ( int algo , int keyno , int is_primary , kbnode_t pub_root ,
u32 * timestamp , u32 expireval )
2003-06-27 20:53:09 +00:00
{
2006-04-19 11:26:11 +00:00
# ifdef ENABLE_CARD_SUPPORT
2010-11-17 13:21:24 +00:00
gpg_error_t err ;
2003-06-27 20:53:09 +00:00
struct agent_card_genkey_s info ;
PACKET * pkt ;
PKT_public_key * pk ;
2010-11-17 13:21:24 +00:00
if ( algo ! = PUBKEY_ALGO_RSA )
return gpg_error ( GPG_ERR_PUBKEY_ALGO ) ;
2003-06-27 20:53:09 +00:00
2010-11-17 13:21:24 +00:00
pk = xtrycalloc ( 1 , sizeof * pk ) ;
if ( ! pk )
return gpg_error_from_syserror ( ) ;
pkt = xtrycalloc ( 1 , sizeof * pkt ) ;
if ( ! pkt )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
xfree ( pk ) ;
return gpg_error_from_syserror ( ) ;
2006-04-19 11:26:11 +00:00
}
2010-11-17 13:21:24 +00:00
/* Note: SCD knows the serialnumber, thus there is no point in passing it. */
err = agent_scd_genkey ( & info , keyno , 1 , NULL , * timestamp ) ;
/* The code below is not used because we force creation of
* the a card key ( 3 rd arg ) .
* if ( gpg_err_code ( rc ) = = GPG_ERR_EEXIST )
* {
* tty_printf ( " \n " ) ;
* log_error ( " WARNING: key does already exists! \n " ) ;
* tty_printf ( " \n " ) ;
* if ( cpr_get_answer_is_yes ( " keygen.card.replace_key " ,
* _ ( " Replace existing key? " ) ) )
* rc = agent_scd_genkey ( & info , keyno , 1 ) ;
* }
*/
if ( ! err & & ( ! info . n | | ! info . e ) )
2003-06-27 20:53:09 +00:00
{
log_error ( " communication error with SCD \n " ) ;
2006-08-16 10:47:53 +00:00
gcry_mpi_release ( info . n ) ;
gcry_mpi_release ( info . e ) ;
2010-11-17 13:21:24 +00:00
err = gpg_error ( GPG_ERR_GENERAL ) ;
}
if ( err )
{
log_error ( " key generation failed: %s \n " , gpg_strerror ( err ) ) ;
xfree ( pkt ) ;
xfree ( pk ) ;
return err ;
2003-06-27 20:53:09 +00:00
}
2007-07-05 16:58:19 +00:00
if ( * timestamp ! = info . created_at )
2010-11-17 13:21:24 +00:00
log_info ( " NOTE: the key does not use the suggested creation date \n " ) ;
2007-07-05 16:58:19 +00:00
* timestamp = info . created_at ;
2003-06-27 20:53:09 +00:00
2010-11-17 13:21:24 +00:00
pk - > timestamp = info . created_at ;
pk - > version = 4 ;
2003-06-27 20:53:09 +00:00
if ( expireval )
2010-11-17 13:21:24 +00:00
pk - > expiredate = pk - > timestamp + expireval ;
pk - > pubkey_algo = algo ;
2003-06-27 20:53:09 +00:00
pk - > pkey [ 0 ] = info . n ;
pk - > pkey [ 1 ] = info . e ;
2006-06-27 14:30:59 +00:00
2006-04-19 11:26:11 +00:00
pkt - > pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY ;
2003-06-27 20:53:09 +00:00
pkt - > pkt . public_key = pk ;
2010-11-17 13:21:24 +00:00
add_kbnode ( pub_root , new_kbnode ( pkt ) ) ;
2003-06-27 20:53:09 +00:00
return 0 ;
2006-04-19 11:26:11 +00:00
# else
2010-04-20 17:57:50 +00:00
return gpg_error ( GPG_ERR_NOT_SUPPORTED ) ;
2006-04-19 11:26:11 +00:00
# endif /*!ENABLE_CARD_SUPPORT*/
2003-06-27 20:53:09 +00:00
}
2003-07-16 13:45:15 +00:00
2006-04-19 11:26:11 +00:00
static int
gen_card_key_with_backup ( int algo , int keyno , int is_primary ,
2010-04-20 17:57:50 +00:00
KBNODE pub_root , u32 timestamp ,
2010-11-17 13:21:24 +00:00
u32 expireval , struct para_data_s * para )
2006-04-19 11:26:11 +00:00
{
2010-11-17 13:21:24 +00:00
#if 0 /* FIXME: Move this to gpg-agent. */
2006-04-19 11:26:11 +00:00
int rc ;
const char * s ;
PACKET * pkt ;
2006-08-16 10:47:53 +00:00
PKT_secret_key * sk , * sk_unprotected = NULL , * sk_protected = NULL ;
2006-04-19 11:26:11 +00:00
PKT_public_key * pk ;
size_t n ;
int i ;
2009-05-15 19:26:46 +00:00
unsigned int nbits ;
/* Get the size of the key directly from the card. */
{
struct agent_card_info_s info ;
memset ( & info , 0 , sizeof info ) ;
if ( ! agent_scd_getattr ( " KEY-ATTR " , & info )
& & info . key_attr [ 1 ] . algo )
nbits = info . key_attr [ 1 ] . nbits ;
else
nbits = 1024 ; /* All pre-v2.0 cards. */
agent_release_card_info ( & info ) ;
}
2006-04-19 11:26:11 +00:00
2009-05-15 19:26:46 +00:00
/* Create a key of this size in memory. */
rc = generate_raw_key ( algo , nbits , timestamp ,
2006-04-19 11:26:11 +00:00
& sk_unprotected , & sk_protected ) ;
if ( rc )
return rc ;
2009-05-15 19:26:46 +00:00
/* Store the key to the card. */
2006-04-19 11:26:11 +00:00
rc = save_unprotected_key_to_card ( sk_unprotected , keyno ) ;
if ( rc )
{
log_error ( _ ( " storing key onto card failed: %s \n " ) , g10_errstr ( rc ) ) ;
free_secret_key ( sk_unprotected ) ;
free_secret_key ( sk_protected ) ;
2010-01-08 19:18:49 +00:00
write_status_errcode ( " save_key_to_card " , rc ) ;
2006-04-19 11:26:11 +00:00
return rc ;
}
/* Get rid of the secret key parameters and store the serial numer. */
sk = sk_unprotected ;
n = pubkey_get_nskey ( sk - > pubkey_algo ) ;
for ( i = pubkey_get_npkey ( sk - > pubkey_algo ) ; i < n ; i + + )
{
2006-08-16 10:47:53 +00:00
gcry_mpi_release ( sk - > skey [ i ] ) ;
2006-04-19 11:26:11 +00:00
sk - > skey [ i ] = NULL ;
}
i = pubkey_get_npkey ( sk - > pubkey_algo ) ;
2006-06-30 09:42:08 +00:00
sk - > skey [ i ] = gcry_mpi_set_opaque ( NULL , xstrdup ( " dummydata " ) , 10 * 8 ) ;
2006-04-19 11:26:11 +00:00
sk - > is_protected = 1 ;
sk - > protect . s2k . mode = 1002 ;
s = get_parameter_value ( para , pSERIALNO ) ;
assert ( s ) ;
for ( sk - > protect . ivlen = 0 ; sk - > protect . ivlen < 16 & & * s & & s [ 1 ] ;
sk - > protect . ivlen + + , s + = 2 )
sk - > protect . iv [ sk - > protect . ivlen ] = xtoi_2 ( s ) ;
/* Now write the *protected* secret key to the file. */
{
char name_buffer [ 50 ] ;
char * fname ;
IOBUF fp ;
mode_t oldmask ;
keyid_from_sk ( sk , NULL ) ;
2009-05-17 13:08:18 +00:00
snprintf ( name_buffer , sizeof name_buffer , " sk_%08lX%08lX.gpg " ,
( ulong ) sk - > keyid [ 0 ] , ( ulong ) sk - > keyid [ 1 ] ) ;
2006-04-19 11:26:11 +00:00
fname = make_filename ( backup_dir , name_buffer , NULL ) ;
oldmask = umask ( 077 ) ;
if ( is_secured_filename ( fname ) )
{
fp = NULL ;
2010-04-01 13:24:55 +00:00
gpg_err_set_errno ( EPERM ) ;
2006-04-19 11:26:11 +00:00
}
else
fp = iobuf_create ( fname ) ;
umask ( oldmask ) ;
if ( ! fp )
{
2006-09-14 16:50:33 +00:00
rc = gpg_error_from_syserror ( ) ;
2006-04-19 11:26:11 +00:00
log_error ( _ ( " can't create backup file `%s': %s \n " ) ,
fname , strerror ( errno ) ) ;
xfree ( fname ) ;
free_secret_key ( sk_unprotected ) ;
free_secret_key ( sk_protected ) ;
2006-08-16 10:47:53 +00:00
return rc ;
2006-04-19 11:26:11 +00:00
}
pkt = xcalloc ( 1 , sizeof * pkt ) ;
pkt - > pkttype = PKT_SECRET_KEY ;
pkt - > pkt . secret_key = sk_protected ;
sk_protected = NULL ;
rc = build_packet ( fp , pkt ) ;
if ( rc )
{
log_error ( " build packet failed: %s \n " , g10_errstr ( rc ) ) ;
iobuf_cancel ( fp ) ;
}
else
{
2006-08-16 10:47:53 +00:00
unsigned char array [ MAX_FINGERPRINT_LEN ] ;
2006-04-19 11:26:11 +00:00
char * fprbuf , * p ;
iobuf_close ( fp ) ;
2010-03-08 17:05:37 +00:00
iobuf_ioctl ( NULL , IOBUF_IOCTL_INVALIDATE_CACHE , 0 , ( char * ) fname ) ;
2006-04-19 11:26:11 +00:00
log_info ( _ ( " NOTE: backup of card key saved to `%s' \n " ) , fname ) ;
fingerprint_from_sk ( sk , array , & n ) ;
p = fprbuf = xmalloc ( MAX_FINGERPRINT_LEN * 2 + 1 + 1 ) ;
for ( i = 0 ; i < n ; i + + , p + = 2 )
sprintf ( p , " %02X " , array [ i ] ) ;
* p + + = ' ' ;
* p = 0 ;
write_status_text_and_buffer ( STATUS_BACKUP_KEY_CREATED ,
fprbuf ,
fname , strlen ( fname ) ,
0 ) ;
xfree ( fprbuf ) ;
}
free_packet ( pkt ) ;
xfree ( pkt ) ;
xfree ( fname ) ;
if ( rc )
{
free_secret_key ( sk_unprotected ) ;
return rc ;
}
}
/* Create the public key from the secret key. */
pk = xcalloc ( 1 , sizeof * pk ) ;
pk - > timestamp = sk - > timestamp ;
pk - > version = sk - > version ;
if ( expireval )
pk - > expiredate = sk - > expiredate = sk - > timestamp + expireval ;
pk - > pubkey_algo = sk - > pubkey_algo ;
n = pubkey_get_npkey ( sk - > pubkey_algo ) ;
for ( i = 0 ; i < n ; i + + )
pk - > pkey [ i ] = mpi_copy ( sk - > skey [ i ] ) ;
/* Build packets and add them to the node lists. */
pkt = xcalloc ( 1 , sizeof * pkt ) ;
pkt - > pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY ;
pkt - > pkt . public_key = pk ;
add_kbnode ( pub_root , new_kbnode ( pkt ) ) ;
pkt = xcalloc ( 1 , sizeof * pkt ) ;
pkt - > pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY ;
pkt - > pkt . secret_key = sk ;
add_kbnode ( sec_root , new_kbnode ( pkt ) ) ;
return 0 ;
# else
2010-04-20 17:57:50 +00:00
return gpg_error ( GPG_ERR_NOT_SUPPORTED ) ;
2006-04-19 11:26:11 +00:00
# endif /*!ENABLE_CARD_SUPPORT*/
}
2010-11-17 13:21:24 +00:00
#if 0
2006-04-19 11:26:11 +00:00
int
2010-11-17 13:21:24 +00:00
save_unprotected_key_to_card ( PKT_public_key * sk , int keyno )
2006-04-19 11:26:11 +00:00
{
int rc ;
unsigned char * rsa_n = NULL ;
unsigned char * rsa_e = NULL ;
unsigned char * rsa_p = NULL ;
unsigned char * rsa_q = NULL ;
2006-11-21 11:00:14 +00:00
size_t rsa_n_len , rsa_e_len , rsa_p_len , rsa_q_len ;
2006-04-19 11:26:11 +00:00
unsigned char * sexp = NULL ;
unsigned char * p ;
char numbuf [ 55 ] , numbuf2 [ 50 ] ;
assert ( is_RSA ( sk - > pubkey_algo ) ) ;
assert ( ! sk - > is_protected ) ;
/* Copy the parameters into straight buffers. */
2006-08-16 10:47:53 +00:00
gcry_mpi_aprint ( GCRYMPI_FMT_USG , & rsa_n , & rsa_n_len , sk - > skey [ 0 ] ) ;
gcry_mpi_aprint ( GCRYMPI_FMT_USG , & rsa_e , & rsa_e_len , sk - > skey [ 1 ] ) ;
2007-07-05 16:58:19 +00:00
gcry_mpi_aprint ( GCRYMPI_FMT_USG , & rsa_p , & rsa_p_len , sk - > skey [ 3 ] ) ;
gcry_mpi_aprint ( GCRYMPI_FMT_USG , & rsa_q , & rsa_q_len , sk - > skey [ 4 ] ) ;
if ( ! rsa_n | | ! rsa_e | | ! rsa_p | | ! rsa_q )
2006-04-19 11:26:11 +00:00
{
rc = G10ERR_INV_ARG ;
goto leave ;
}
2007-07-05 16:58:19 +00:00
/* Put the key into an S-expression. */
2006-04-19 11:26:11 +00:00
sexp = p = xmalloc_secure ( 30
+ rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
+ 4 * sizeof ( numbuf ) + 25 + sizeof ( numbuf ) + 20 ) ;
p = stpcpy ( p , " (11:private-key(3:rsa(1:n " ) ;
2006-11-21 11:00:14 +00:00
sprintf ( numbuf , " %u: " , ( unsigned int ) rsa_n_len ) ;
2006-04-19 11:26:11 +00:00
p = stpcpy ( p , numbuf ) ;
memcpy ( p , rsa_n , rsa_n_len ) ;
p + = rsa_n_len ;
2006-11-21 11:00:14 +00:00
sprintf ( numbuf , " )(1:e%u: " , ( unsigned int ) rsa_e_len ) ;
2006-04-19 11:26:11 +00:00
p = stpcpy ( p , numbuf ) ;
memcpy ( p , rsa_e , rsa_e_len ) ;
p + = rsa_e_len ;
2006-11-21 11:00:14 +00:00
sprintf ( numbuf , " )(1:p%u: " , ( unsigned int ) rsa_p_len ) ;
2006-04-19 11:26:11 +00:00
p = stpcpy ( p , numbuf ) ;
memcpy ( p , rsa_p , rsa_p_len ) ;
p + = rsa_p_len ;
2006-11-21 11:00:14 +00:00
sprintf ( numbuf , " )(1:q%u: " , ( unsigned int ) rsa_q_len ) ;
2006-04-19 11:26:11 +00:00
p = stpcpy ( p , numbuf ) ;
memcpy ( p , rsa_q , rsa_q_len ) ;
p + = rsa_q_len ;
p = stpcpy ( p , " ))(10:created-at " ) ;
sprintf ( numbuf2 , " %lu " , ( unsigned long ) sk - > timestamp ) ;
sprintf ( numbuf , " %lu: " , ( unsigned long ) strlen ( numbuf2 ) ) ;
p = stpcpy ( stpcpy ( stpcpy ( p , numbuf ) , numbuf2 ) , " )) " ) ;
/* Fixme: Unfortunately we don't have the serialnumber available -
thus we can ' t pass it down to the agent . */
rc = agent_scd_writekey ( keyno , NULL , sexp , p - sexp ) ;
leave :
xfree ( sexp ) ;
xfree ( rsa_n ) ;
xfree ( rsa_e ) ;
xfree ( rsa_p ) ;
xfree ( rsa_q ) ;
return rc ;
}
# endif /*ENABLE_CARD_SUPPORT*/