1
/* -*- Mode: C; c-file-style: "bsd" -*-
2
* keygen.c - OpenPGP key generation
3
* Copyright (C) 2002, 2003 Timo Schulz
5
* This file is part of OpenCDK.
7
* OpenCDK is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* OpenCDK is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with OpenCDK; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
44
struct cdk_keygen_ctx_s {
53
unsigned mdc_feature:1;
54
unsigned ks_no_modify:1;
56
cdk_pkt_signature_t sig;
58
struct key_ctx_s key[2];
64
/* default preferences */
65
static byte def_sym_prefs[] = {CDK_CIPHER_AES, CDK_CIPHER_CAST5,
66
CDK_CIPHER_TWOFISH, CDK_CIPHER_AES192,
67
CDK_CIPHER_AES256, CDK_CIPHER_3DES,
69
static byte def_hash_prefs[] = {CDK_MD_SHA1, CDK_MD_RMD160, CDK_MD_MD5};
70
static byte def_zip_prefs[] = {CDK_COMPRESS_ZIP, CDK_COMPRESS_ZLIB};
74
check_pref_array( const byte * p, size_t n, int type )
81
if( type == CDK_PREFTYPE_SYM ) {
82
for( i = 0; i < n; i++ ) {
83
if( cdk_cipher_test_algo( p[i] ) )
87
else if( type == CDK_PREFTYPE_HASH ) {
88
for( i = 0; i < n; i++ ) {
89
if( cdk_md_test_algo( p[i] ) )
93
else if( type == CDK_PREFTYPE_ZIP ) {
96
if( p[0] > 2 || p[1] > 2 )
106
* cdk_keygen_set_prefs: Set the preferences for the userID
107
* @hd: the keygen object
108
* @hd: the preference type
109
* @array: one-octet array with algorithm numers
113
cdk_keygen_set_prefs( cdk_keygen_ctx_t hd, enum cdk_pref_type_t type,
114
const byte * array, size_t n )
119
return CDK_Inv_Value;
121
rc = check_pref_array( array, n, type );
123
return CDK_Inv_Value;
126
case CDK_PREFTYPE_SYM:
127
hd->sym_len = array? n : DIM( def_sym_prefs );
128
hd->sym_prefs = cdk_calloc( 1, hd->sym_len );
130
memcpy( hd->sym_prefs, array? array : def_sym_prefs, hd->sym_len );
133
case CDK_PREFTYPE_HASH:
134
hd->hash_len = array? n : DIM( def_hash_prefs );
135
hd->hash_prefs = cdk_calloc( 1, hd->hash_len );
137
memcpy( hd->hash_prefs, array? array : def_hash_prefs,
141
case CDK_PREFTYPE_ZIP:
142
hd->zip_len = array? n : DIM( def_zip_prefs );
143
hd->zip_prefs = cdk_calloc( 1, hd->zip_len );
145
memcpy( hd->zip_prefs, array? array : def_zip_prefs, hd->zip_len );
157
* cdk_keygen_set_name: set the userid name for the key
158
* @hd: the keygen object
161
* The name will be encoded in UTF8 to avoid problems.
164
cdk_keygen_set_name( cdk_keygen_ctx_t hd, const char * name )
167
cdk_free( hd->user_id );
168
hd->user_id = cdk_utf8_encode( name );
174
check_bits( int bits, int algo )
178
if( algo == CDK_PK_DSA && bits > 1024 )
187
* cdk_keygen_set_algo_info: set the length and type of the key
188
* @hd: the keygen object.
189
* @type: key type (primary=0, subkey=1)
190
* @algo: algorithm compliant with rfc2440
191
* @bits: lengt of the key in bits
195
cdk_keygen_set_algo_info( cdk_keygen_ctx_t hd, int type,
196
enum cdk_pk_algo_t algo, int bits )
199
int usage = type? PK_USAGE_ENCR : PK_USAGE_SIGN;
202
return CDK_Inv_Value;
203
if( type < 0 || type > 1 )
204
return CDK_Inv_Value;
206
if( bits % 128 != 0 )
207
bits = bits + ( bits % 128 );
209
rc = _cdk_pk_test_algo( algo, usage );
213
/* type=0 primary type=1 sub */
214
hd->key[type].algo = algo;
215
hd->key[type].len = check_bits( bits, algo );
222
* cdk_keygen_set_mdc_feature: set the mdc feature for the key
224
* @val: boolean( yes=1, no=0)
226
* if you want a RFC2440 compliant key, you've to disable this feature
227
* until the rfc2440-bis8 becomes the next standard.
230
cdk_keygen_set_mdc_feature( cdk_keygen_ctx_t hd, int val )
233
hd->mdc_feature = val;
239
cdk_keygen_set_keyserver_flags( cdk_keygen_ctx_t hd, int no_modify,
240
const char *pref_url )
243
hd->ks_no_modify = 1;
245
hd->ks_pref_url = cdk_strdup( pref_url );
246
} /* cdk_keygen_set_keyserver_flags */
250
* cdk_keygen_set_expire_date: set the expire date of the primary key
252
* @type: key type( 0=primary, 1=seconardy)
253
* @timestamp: the date the key should expire
257
cdk_keygen_set_expire_date( cdk_keygen_ctx_t hd, int type, long timestamp )
261
if( type < 0 || type > 1 )
263
if( timestamp < 0 || timestamp < _cdk_timestamp( ) )
265
hd->key[type].expire_date = timestamp;
270
cdk_keygen_set_passphrase( cdk_keygen_ctx_t hd, const char * pass )
275
size_t n = strlen( pass );
276
_cdk_sec_free( hd->pass, hd->pass_len );
277
hd->pass = cdk_salloc( n + 1, 1 );
279
memcpy( hd->pass, pass, n );
289
read_single_mpi( gcry_sexp_t s_key, const char * val, gcry_mpi_t * r_resarr )
294
return CDK_Inv_Value;
295
list = gcry_sexp_find_token( s_key, val, 0 );
297
*r_resarr = gcry_sexp_nth_mpi( list, 1, 0 );
298
gcry_sexp_release( list );
299
return list? 0 : CDK_Gcry_Error;
304
read_dsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
306
int rc = read_single_mpi( s_key, "p", &resarr[0] );
308
rc = read_single_mpi( s_key, "q", &resarr[1] );
310
rc = read_single_mpi( s_key, "g", &resarr[2] );
312
rc = read_single_mpi( s_key, "y", &resarr[3] );
314
rc = read_single_mpi( s_key, "x", &resarr[4] );
320
read_elg_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
322
int rc = read_single_mpi( s_key, "p", &resarr[0] );
324
rc = read_single_mpi( s_key, "g", &resarr[1] );
326
rc = read_single_mpi( s_key, "y", &resarr[2] );
328
rc = read_single_mpi( s_key, "x", &resarr[3] );
334
read_rsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
336
int rc = read_single_mpi( s_key, "n", &resarr[0] );
338
rc =read_single_mpi( s_key, "e", &resarr[1] );
340
rc = read_single_mpi( s_key, "d", &resarr[2] );
342
rc = read_single_mpi( s_key, "p", &resarr[3] );
344
rc = read_single_mpi( s_key, "q", &resarr[4] );
346
rc = read_single_mpi( s_key, "u", &resarr[5] );
352
generate_subkey( cdk_keygen_ctx_t hd )
354
gcry_sexp_t s_params = NULL, s_key;
355
size_t n = hd->key[1].len;
359
return CDK_Inv_Value;
361
if( is_DSA( hd->key[1].algo) )
362
rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n );
363
else if( is_ELG( hd->key[1].algo) )
364
rc = gcry_sexp_build( &s_params, NULL, "(genkey(elg(nbits %d)))", n );
365
else if( is_RSA( hd->key[1].algo) )
366
rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n );
370
rc = gcry_pk_genkey( &s_key, s_params );
371
gcry_sexp_release( s_params );
373
if( is_DSA( hd->key[1].algo) )
374
rc = read_dsa_key( s_key, hd->key[1].resarr );
375
else if( is_ELG( hd->key[1].algo) )
376
rc = read_elg_key( s_key, hd->key[1].resarr );
377
else if( is_RSA( hd->key[1].algo) )
378
rc = read_rsa_key( s_key, hd->key[1].resarr );
380
hd->key[1].n = cdk_pk_get_npkey( hd->key[1].algo );
381
gcry_sexp_release( s_key );
387
* cdk_keygen_start: kick off the key generation
388
* @hd: the keygen object
392
cdk_keygen_start( cdk_keygen_ctx_t hd )
394
gcry_sexp_t s_params = NULL, s_key = NULL;
398
if( !hd || !hd->user_id )
399
return CDK_Inv_Value;
400
if( is_ELG( hd->key[0].algo ) )
402
if( !hd->key[0].len )
403
hd->key[0].len = 1024;
407
cdk_keygen_set_prefs( hd, CDK_PREFTYPE_SYM, NULL, 0 );
408
if( !hd->hash_prefs )
409
cdk_keygen_set_prefs( hd, CDK_PREFTYPE_HASH, NULL, 0 );
411
cdk_keygen_set_prefs( hd, CDK_PREFTYPE_ZIP, NULL, 0 );
413
if( is_DSA( hd->key[0].algo ) )
414
rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n );
415
else if( is_RSA( hd->key[0].algo ) )
416
rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n );
420
rc = gcry_pk_genkey( &s_key, s_params );
421
gcry_sexp_release( s_params );
423
if( is_DSA( hd->key[0].algo ) )
424
rc = read_dsa_key( s_key, hd->key[0].resarr );
425
else if( is_RSA( hd->key[0].algo ) )
426
rc = read_rsa_key( s_key, hd->key[0].resarr );
427
hd->key[0].n = cdk_pk_get_npkey( hd->key[0].algo );
429
gcry_sexp_release( s_key );
431
if( hd->key[1].algo && hd->key[1].len )
432
rc = generate_subkey( hd );
439
gcry_mpi_to_native( cdk_keygen_ctx_t hd, size_t nkey, int type,
440
cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk )
445
int i = 0, j = 0, nbits;
449
return CDK_Inv_Value;
451
return CDK_Inv_Value;
452
if( type < 0 || type > 1 )
453
return CDK_Inv_Value;
455
resarr = hd->key[type].resarr;
457
i += cdk_pk_get_npkey( sk->pubkey_algo );
459
nbits = gcry_mpi_get_nbits( resarr[i] );
461
a = cdk_calloc( 1, sizeof * a + (nbits + 7) / 8 + 2 + 1 );
463
a = cdk_salloc( sizeof * a + (nbits + 7) / 8 + 2 + 1, 1 );
465
a->bytes = ( nbits + 7 ) / 8;
467
a->data[0] = nbits >> 8;
469
rc = gcry_mpi_print( GCRYMPI_FMT_USG, a->data+2, nbytes, &nbytes, resarr[i] );
482
static cdk_pkt_pubkey_t
483
pk_create( cdk_keygen_ctx_t hd, int type )
486
int rc = 0, npkey = 0;
488
if( type < 0 || type > 1 )
490
pk = cdk_calloc( 1, sizeof * pk );
494
pk->pubkey_algo = hd->key[type].algo;
495
pk->timestamp = _cdk_timestamp( );
496
if( hd->key[type].expire_date )
497
pk->expiredate = pk->timestamp + hd->key[type].expire_date;
498
npkey = cdk_pk_get_npkey( pk->pubkey_algo );
499
rc = gcry_mpi_to_native( hd, npkey, type, pk, NULL );
508
static cdk_pkt_seckey_t
509
sk_create( cdk_keygen_ctx_t hd, int type )
514
if( type < 0 || type > 1 )
516
sk = cdk_calloc( 1, sizeof * sk );
519
_cdk_copy_pubkey( &sk->pk, hd->key[type].pk );
521
sk->pubkey_algo = hd->key[type].algo;
523
sk->is_protected = 0;
524
nskey = cdk_pk_get_nskey( sk->pubkey_algo );
525
rc = gcry_mpi_to_native( hd, nskey, type, NULL, sk );
534
static cdk_pkt_userid_t
535
uid_create( cdk_keygen_ctx_t hd )
541
id = cdk_calloc( 1, sizeof * id + strlen( hd->user_id ) + 1 );
544
strcpy( id->name, hd->user_id );
545
id->len = strlen( hd->user_id );
550
static cdk_pkt_signature_t
551
sig_subkey_create( cdk_keygen_ctx_t hd )
555
cdk_pkt_signature_t sig;
556
cdk_pkt_pubkey_t pk = hd->key[0].pk;
557
cdk_pkt_pubkey_t sub_pk = hd->key[1].pk;
558
cdk_pkt_seckey_t sk = hd->key[0].sk;
562
sig = cdk_calloc( 1, sizeof * sig );
565
_cdk_sig_create( pk, sig );
566
sig->sig_class = 0x18;
567
sig->digest_algo = CDK_MD_SHA1;
569
if( sub_pk->expiredate ) {
570
_cdk_u32tobuf( sub_pk->expiredate - sub_pk->timestamp, buf );
571
node = cdk_subpkt_new( 4 );
573
cdk_subpkt_init( node, CDK_SIGSUBPKT_KEY_EXPIRE, buf, 4 );
574
cdk_subpkt_add( sig->hashed, node );
578
md = cdk_md_open( sig->digest_algo, 0 );
580
_cdk_free_signature( sig );
584
_cdk_hash_pubkey( pk, md, 0 );
585
_cdk_hash_pubkey( sub_pk, md, 0 );
586
rc = _cdk_sig_complete( sig, sk, md );
589
_cdk_free_signature( sig );
596
static cdk_pkt_signature_t
597
sig_self_create( cdk_keygen_ctx_t hd )
601
cdk_pkt_signature_t sig;
602
cdk_pkt_pubkey_t pk = hd->key[0].pk;
603
cdk_pkt_userid_t id = hd->id;
604
cdk_pkt_seckey_t sk = hd->key[0].sk;
609
sig = cdk_calloc( 1, sizeof * sig );
613
sig->timestamp = _cdk_timestamp( );
614
sig->sig_class = 0x13;
615
sig->pubkey_algo = hd->key[0].algo;
616
sig->digest_algo = CDK_MD_SHA1;
618
_cdk_u32tobuf( sig->timestamp, buf );
619
sig->hashed = node = cdk_subpkt_new( 4 );
621
cdk_subpkt_init( node, CDK_SIGSUBPKT_SIG_CREATED, buf, 4 );
624
node = cdk_subpkt_new( hd->sym_len + 1 );
626
cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_SYM, p, hd->sym_len );
627
cdk_subpkt_add( sig->hashed, node );
631
node = cdk_subpkt_new( hd->hash_len + 1 );
633
cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_HASH, p, hd->hash_len );
634
cdk_subpkt_add( sig->hashed, node );
638
node = cdk_subpkt_new( hd->zip_len + 1 );
640
cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_ZIP, p, hd->zip_len );
641
cdk_subpkt_add( sig->hashed, node );
644
if( hd->mdc_feature ) {
646
node = cdk_subpkt_new( 1 );
648
cdk_subpkt_init( node, CDK_SIGSUBPKT_FEATURES, buf, 1 );
649
cdk_subpkt_add( sig->hashed, node );
653
if( hd->ks_no_modify ) {
655
node = cdk_subpkt_new( 1 );
657
cdk_subpkt_init( node, CDK_SIGSUBPKT_KS_FLAGS, buf, 1 );
658
cdk_subpkt_add( sig->hashed, node );
662
if( hd->ks_pref_url ) {
663
node = cdk_subpkt_new( strlen( hd->ks_pref_url ) + 1 );
665
cdk_subpkt_init( node, CDK_SIGSUBPKT_PREF_KS,
666
hd->ks_pref_url, strlen( hd->ks_pref_url ) );
667
cdk_subpkt_add( sig->hashed, node );
671
if( pk->expiredate ) {
672
node = cdk_subpkt_new( 4 );
674
_cdk_u32tobuf( pk->expiredate - pk->timestamp, buf );
675
cdk_subpkt_init( node, CDK_SIGSUBPKT_KEY_EXPIRE, buf, 4 );
676
cdk_subpkt_add( sig->hashed, node );
680
sig->unhashed = node = cdk_subpkt_new( 8 );
682
cdk_pk_get_keyid( pk, keyid );
683
_cdk_u32tobuf( keyid[0], buf );
684
_cdk_u32tobuf( keyid[1], buf + 4 );
685
cdk_subpkt_init( node, CDK_SIGSUBPKT_ISSUER, buf, 8 );
688
md = cdk_md_open( sig->digest_algo, 0 );
690
_cdk_free_signature( sig );
694
_cdk_hash_pubkey( pk, md, 0 );
695
_cdk_hash_userid( id, sig->version == 4, md );
696
rc = _cdk_sig_complete( sig, sk, md );
699
_cdk_free_signature( sig );
707
* cdk_keygen_save: save the generated keys to disk
708
* @hd: the keygen object
709
* @pub: name of the file to store the public key
710
* @sec: name of the file to store the secret key
714
cdk_keygen_save( cdk_keygen_ctx_t hd, const char * pubf, const char * secf )
716
cdk_stream_t out = NULL;
720
hd->key[0].pk = pk_create( hd, 0 );
722
return CDK_Inv_Packet;
723
hd->key[0].sk = sk_create( hd, 0 );
725
return CDK_Inv_Packet;
726
hd->id = uid_create( hd );
728
return CDK_Inv_Packet;
729
hd->sig = sig_self_create( hd );
731
return CDK_Inv_Packet;
733
rc = cdk_stream_create( pubf, &out );
737
cdk_pkt_init( &pkt );
738
pkt.pkttype = CDK_PKT_PUBLIC_KEY;
739
pkt.pkt.public_key = hd->key[0].pk;
740
rc = cdk_pkt_write( out, &pkt );
744
cdk_pkt_init( &pkt );
745
pkt.pkttype = CDK_PKT_USER_ID;
746
pkt.pkt.user_id = hd->id;
747
rc = cdk_pkt_write( out, &pkt );
751
cdk_pkt_init( &pkt );
752
pkt.pkttype = CDK_PKT_SIGNATURE;
753
pkt.pkt.signature = hd->sig;
754
rc = cdk_pkt_write( out, &pkt );
758
if( hd->key[1].algo ) {
759
cdk_pkt_init( &pkt );
760
pkt.pkttype = CDK_PKT_PUBLIC_SUBKEY;
761
pkt.pkt.public_key = hd->key[1].pk = pk_create( hd, 1 );
762
rc = cdk_pkt_write( out, &pkt );
766
cdk_pkt_init( &pkt );
767
pkt.pkttype = CDK_PKT_SIGNATURE;
768
pkt.pkt.signature = sig_subkey_create( hd );
769
rc = cdk_pkt_write( out, &pkt );
770
cdk_pkt_free( &pkt );
775
cdk_stream_close( out );
778
rc = cdk_stream_create( secf, &out );
783
rc = cdk_sk_protect( hd->key[0].sk, hd->pass );
788
cdk_pkt_init( &pkt );
789
pkt.pkttype = CDK_PKT_SECRET_KEY;
790
pkt.pkt.secret_key = hd->key[0].sk;
791
rc = cdk_pkt_write( out, &pkt );
795
cdk_pkt_init( &pkt );
796
pkt.pkttype = CDK_PKT_USER_ID;
797
pkt.pkt.user_id = hd->id;
798
rc = cdk_pkt_write( out, &pkt );
802
cdk_pkt_init( &pkt );
803
pkt.pkttype = CDK_PKT_SIGNATURE;
804
pkt.pkt.signature = hd->sig;
805
rc = cdk_pkt_write( out, &pkt );
809
if( hd->key[1].algo ) {
810
hd->key[1].sk = sk_create( hd, 1 );
811
if( hd->protect && (rc = cdk_sk_protect( hd->key[1].sk, hd->pass )) )
813
cdk_pkt_init( &pkt );
814
pkt.pkttype = CDK_PKT_SECRET_SUBKEY;
815
pkt.pkt.secret_key = hd->key[1].sk;
816
rc = cdk_pkt_write( out, &pkt );
822
cdk_stream_close( out );
828
* cdk_keygen_free: free the keygen object
829
* @hd: the keygen object
833
cdk_keygen_free( cdk_keygen_ctx_t hd )
836
_cdk_free_pubkey( hd->key[0].pk );
837
_cdk_free_pubkey( hd->key[1].pk );
838
_cdk_free_seckey( hd->key[0].sk );
839
_cdk_free_seckey( hd->key[1].sk );
840
_cdk_free_userid( hd->id );
841
_cdk_free_signature( hd->sig );
842
cdk_free( hd->sym_prefs );
843
cdk_free( hd->hash_prefs );
844
cdk_free( hd->zip_prefs );
845
_cdk_sec_free( hd->pass, hd->pass_len );
846
_cdk_free_mpibuf( hd->key[0].n, hd->key[0].resarr );
847
_cdk_free_mpibuf( hd->key[1].n, hd->key[1].resarr );
855
* @r_hd: the new object
859
cdk_keygen_new( cdk_keygen_ctx_t * r_hd )
864
return CDK_Inv_Value;
865
hd = cdk_calloc( 1, sizeof * hd );
867
return CDK_Out_Of_Core;