~ubuntu-branches/ubuntu/hardy/gnutls13/hardy-updates

« back to all changes in this revision

Viewing changes to libextra/opencdk/keygen.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2007-09-29 11:29:22 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070929112922-abqj0gl08kstu27v
Tags: 2.0.1-1
* New upstream version.
* Remove doc/*.info* on clean to allow building thrice in a row.
  (Closes: #441740)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; c-file-style: "bsd" -*-
2
 
 * keygen.c - OpenPGP key generation
3
 
 *        Copyright (C) 2002, 2003 Timo Schulz
4
 
 *
5
 
 * This file is part of OpenCDK.
6
 
 *
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.
11
 
 *
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.
16
 
 *
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
20
 
 */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
# include <config.h>
24
 
#endif
25
 
#include <stdio.h>
26
 
 
27
 
#include "opencdk.h"
28
 
#include "main.h"
29
 
#include "packet.h"
30
 
#include "cipher.h"
31
 
#include "types.h"
32
 
 
33
 
struct key_ctx_s {
34
 
    u32 expire_date;
35
 
    int algo;
36
 
    int len;
37
 
    gcry_mpi_t resarr[6];
38
 
    size_t n;
39
 
    cdk_pkt_pubkey_t pk;
40
 
    cdk_pkt_seckey_t sk;
41
 
};
42
 
 
43
 
 
44
 
struct cdk_keygen_ctx_s {
45
 
    char * user_id;
46
 
    cdk_pkt_userid_t id;
47
 
    byte * sym_prefs;
48
 
    size_t sym_len;
49
 
    byte * hash_prefs;
50
 
    size_t hash_len;
51
 
    byte * zip_prefs;
52
 
    size_t zip_len;
53
 
    unsigned mdc_feature:1;
54
 
    unsigned ks_no_modify:1;
55
 
    char * ks_pref_url;
56
 
    cdk_pkt_signature_t sig;
57
 
    unsigned protect:1;
58
 
    struct key_ctx_s key[2];
59
 
    char * pass;
60
 
    size_t pass_len;
61
 
};
62
 
 
63
 
 
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,
68
 
                               CDK_CIPHER_BLOWFISH};
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};
71
 
 
72
 
 
73
 
static int
74
 
check_pref_array( const byte * p, size_t n, int type )
75
 
{
76
 
    int i;
77
 
 
78
 
    if( !p )
79
 
        return 0;
80
 
    
81
 
    if( type == CDK_PREFTYPE_SYM ) {
82
 
        for( i = 0; i < n; i++ ) {
83
 
            if( cdk_cipher_test_algo( p[i] ) )
84
 
                return -1;
85
 
        }
86
 
    }
87
 
    else if( type == CDK_PREFTYPE_HASH ) {
88
 
        for( i = 0; i < n; i++ ) {
89
 
            if( cdk_md_test_algo( p[i] ) )
90
 
                return -1;
91
 
        }
92
 
    }
93
 
    else if( type == CDK_PREFTYPE_ZIP ) {
94
 
        if( n > 2 )
95
 
            return -1;
96
 
        if( p[0] > 2 || p[1] > 2 )
97
 
            return -1;
98
 
    }
99
 
    else
100
 
        return -1;
101
 
    return 0;
102
 
}
103
 
 
104
 
 
105
 
/**
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
110
 
 *
111
 
 **/
112
 
cdk_error_t
113
 
cdk_keygen_set_prefs( cdk_keygen_ctx_t hd, enum cdk_pref_type_t type,
114
 
                      const byte * array, size_t n )
115
 
{
116
 
    int rc;
117
 
    
118
 
    if( !hd )
119
 
        return CDK_Inv_Value;
120
 
 
121
 
    rc = check_pref_array( array, n, type );
122
 
    if( rc )
123
 
        return CDK_Inv_Value;
124
 
    
125
 
    switch( type) {
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 );
129
 
        if( hd->sym_prefs )
130
 
            memcpy( hd->sym_prefs, array? array : def_sym_prefs, hd->sym_len );
131
 
        break;
132
 
      
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 );
136
 
        if( hd->hash_prefs )
137
 
            memcpy( hd->hash_prefs, array? array : def_hash_prefs,
138
 
                    hd->hash_len );
139
 
        break;
140
 
      
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 );
144
 
        if( hd->zip_prefs )
145
 
            memcpy( hd->zip_prefs, array? array : def_zip_prefs, hd->zip_len );
146
 
        break;
147
 
      
148
 
    default:
149
 
        return CDK_Inv_Mode;
150
 
    }
151
 
  
152
 
    return 0;
153
 
}
154
 
 
155
 
 
156
 
/**
157
 
 * cdk_keygen_set_name: set the userid name for the key
158
 
 * @hd: the keygen object
159
 
 * @name: name
160
 
 *
161
 
 * The name will be encoded in UTF8 to avoid problems.
162
 
 **/
163
 
void
164
 
cdk_keygen_set_name( cdk_keygen_ctx_t hd, const char * name )
165
 
{
166
 
    if( hd ) {
167
 
        cdk_free( hd->user_id );
168
 
        hd->user_id = cdk_utf8_encode( name );
169
 
    }
170
 
}
171
 
 
172
 
 
173
 
static int
174
 
check_bits( int bits, int algo )
175
 
{
176
 
    if( bits < 768 )
177
 
        return 768;
178
 
    if( algo == CDK_PK_DSA && bits > 1024 )
179
 
        return 1024;
180
 
    if( bits > 4096 )
181
 
        return 4096;
182
 
    return bits;
183
 
}
184
 
 
185
 
 
186
 
/**
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
192
 
 *
193
 
 **/
194
 
cdk_error_t
195
 
cdk_keygen_set_algo_info( cdk_keygen_ctx_t hd, int type,
196
 
                          enum cdk_pk_algo_t algo, int bits )
197
 
{
198
 
    int rc;
199
 
    int usage = type? PK_USAGE_ENCR : PK_USAGE_SIGN;
200
 
  
201
 
    if( !hd )
202
 
        return CDK_Inv_Value;
203
 
    if( type < 0 || type > 1 )
204
 
        return CDK_Inv_Value;
205
 
 
206
 
    if( bits % 128 != 0 )
207
 
        bits = bits + ( bits % 128 );
208
 
  
209
 
    rc = _cdk_pk_test_algo( algo, usage );
210
 
    if( rc )
211
 
        return rc;
212
 
 
213
 
    /* type=0 primary type=1 sub */
214
 
    hd->key[type].algo = algo;
215
 
    hd->key[type].len = check_bits( bits, algo );
216
 
 
217
 
    return 0;
218
 
}
219
 
 
220
 
 
221
 
/**
222
 
 * cdk_keygen_set_mdc_feature: set the mdc feature for the key
223
 
 * @hd: keygen object
224
 
 * @val: boolean( yes=1, no=0)
225
 
 *
226
 
 * if you want a RFC2440 compliant key, you've to disable this feature
227
 
 * until the rfc2440-bis8 becomes the next standard.
228
 
 **/
229
 
void
230
 
cdk_keygen_set_mdc_feature( cdk_keygen_ctx_t hd, int val )
231
 
{
232
 
    if( hd )
233
 
        hd->mdc_feature = val;
234
 
}
235
 
 
236
 
 
237
 
 
238
 
void
239
 
cdk_keygen_set_keyserver_flags( cdk_keygen_ctx_t hd, int no_modify,
240
 
                                const char *pref_url )
241
 
{
242
 
    if( no_modify )
243
 
        hd->ks_no_modify = 1;
244
 
    if( pref_url )
245
 
        hd->ks_pref_url = cdk_strdup( pref_url );
246
 
} /* cdk_keygen_set_keyserver_flags */
247
 
 
248
 
    
249
 
/**
250
 
 * cdk_keygen_set_expire_date: set the expire date of the primary key
251
 
 * @hd: keygen object
252
 
 * @type: key type( 0=primary, 1=seconardy)
253
 
 * @timestamp: the date the key should expire
254
 
 *
255
 
 **/
256
 
void
257
 
cdk_keygen_set_expire_date( cdk_keygen_ctx_t hd, int type, long timestamp )
258
 
{
259
 
    if( !hd )
260
 
        return;
261
 
    if( type < 0 || type > 1 )
262
 
        return;
263
 
    if( timestamp < 0 || timestamp < _cdk_timestamp( ) )
264
 
        timestamp = 0;
265
 
    hd->key[type].expire_date = timestamp;
266
 
}
267
 
 
268
 
 
269
 
void
270
 
cdk_keygen_set_passphrase( cdk_keygen_ctx_t hd, const char * pass )
271
 
{
272
 
    if( !hd )
273
 
        return;
274
 
    if( pass ) {
275
 
        size_t n = strlen( pass );
276
 
        _cdk_sec_free( hd->pass, hd->pass_len );
277
 
        hd->pass = cdk_salloc( n + 1, 1 );
278
 
        if( hd->pass ) {
279
 
            memcpy( hd->pass, pass, n );
280
 
            hd->pass[n] = '\0';
281
 
            hd->pass_len = n;
282
 
            hd->protect = 1;
283
 
        }
284
 
    }
285
 
}
286
 
 
287
 
 
288
 
static int
289
 
read_single_mpi( gcry_sexp_t s_key, const char * val, gcry_mpi_t * r_resarr )
290
 
{
291
 
    gcry_sexp_t list;
292
 
 
293
 
    if( !r_resarr )
294
 
        return CDK_Inv_Value;
295
 
    list = gcry_sexp_find_token( s_key, val, 0 );
296
 
    if( list )
297
 
        *r_resarr = gcry_sexp_nth_mpi( list, 1, 0 );
298
 
    gcry_sexp_release( list );
299
 
    return list? 0 : CDK_Gcry_Error;
300
 
}
301
 
 
302
 
  
303
 
static int
304
 
read_dsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
305
 
{
306
 
    int rc = read_single_mpi( s_key, "p", &resarr[0] );
307
 
    if( !rc )
308
 
        rc = read_single_mpi( s_key, "q", &resarr[1] );
309
 
    if( !rc )
310
 
        rc = read_single_mpi( s_key, "g", &resarr[2] );
311
 
    if( !rc )
312
 
        rc = read_single_mpi( s_key, "y", &resarr[3] );
313
 
    if( !rc )
314
 
        rc = read_single_mpi( s_key, "x", &resarr[4] );
315
 
    return rc;
316
 
}
317
 
 
318
 
 
319
 
static int
320
 
read_elg_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
321
 
{
322
 
    int rc = read_single_mpi( s_key, "p", &resarr[0] );
323
 
    if( !rc )
324
 
        rc = read_single_mpi( s_key, "g", &resarr[1] );
325
 
    if( !rc )
326
 
        rc = read_single_mpi( s_key, "y", &resarr[2] );
327
 
    if( !rc )
328
 
        rc = read_single_mpi( s_key, "x", &resarr[3] );
329
 
    return rc;  
330
 
}
331
 
 
332
 
 
333
 
static int
334
 
read_rsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr )
335
 
{
336
 
    int rc = read_single_mpi( s_key, "n", &resarr[0] );
337
 
    if( !rc )
338
 
        rc =read_single_mpi( s_key, "e", &resarr[1] );
339
 
    if( !rc )
340
 
        rc = read_single_mpi( s_key, "d", &resarr[2] );
341
 
    if( !rc )
342
 
        rc = read_single_mpi( s_key, "p", &resarr[3] );
343
 
    if( !rc )
344
 
        rc = read_single_mpi( s_key, "q", &resarr[4] );
345
 
    if( !rc )
346
 
        rc = read_single_mpi( s_key, "u", &resarr[5] );
347
 
    return rc;
348
 
}
349
 
  
350
 
 
351
 
static int
352
 
generate_subkey( cdk_keygen_ctx_t hd )
353
 
{
354
 
    gcry_sexp_t s_params = NULL, s_key;
355
 
    size_t n = hd->key[1].len;
356
 
    int rc;
357
 
 
358
 
    if( !hd )
359
 
        return CDK_Inv_Value;
360
 
  
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 );
367
 
    else
368
 
        rc = CDK_Inv_Algo;
369
 
    if( !rc )
370
 
        rc = gcry_pk_genkey( &s_key, s_params );
371
 
    gcry_sexp_release( s_params );
372
 
    if( !rc ) {
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 );
379
 
    }
380
 
    hd->key[1].n = cdk_pk_get_npkey( hd->key[1].algo );
381
 
    gcry_sexp_release( s_key );
382
 
    return rc;
383
 
}
384
 
  
385
 
 
386
 
/**
387
 
 * cdk_keygen_start: kick off the key generation
388
 
 * @hd: the keygen object
389
 
 *
390
 
 **/
391
 
cdk_error_t
392
 
cdk_keygen_start( cdk_keygen_ctx_t hd )
393
 
{
394
 
    gcry_sexp_t s_params = NULL, s_key = NULL;
395
 
    size_t n;
396
 
    int rc = 0;
397
 
  
398
 
    if( !hd || !hd->user_id )
399
 
        return CDK_Inv_Value;
400
 
    if( is_ELG( hd->key[0].algo ) )
401
 
        return CDK_Inv_Mode;
402
 
    if( !hd->key[0].len )
403
 
        hd->key[0].len = 1024;
404
 
    n = hd->key[0].len;
405
 
 
406
 
    if( !hd->sym_prefs )
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 );
410
 
    if( !hd->zip_prefs )
411
 
        cdk_keygen_set_prefs( hd, CDK_PREFTYPE_ZIP, NULL, 0 );
412
 
 
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 );
417
 
    else
418
 
        rc = CDK_Inv_Algo;
419
 
    if( !rc )
420
 
        rc = gcry_pk_genkey( &s_key, s_params );
421
 
    gcry_sexp_release( s_params );
422
 
    if( !rc ) {
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 );
428
 
    }
429
 
    gcry_sexp_release( s_key );
430
 
    if( !rc ) {
431
 
        if( hd->key[1].algo && hd->key[1].len )
432
 
            rc = generate_subkey( hd );
433
 
    }
434
 
    return rc;
435
 
}
436
 
 
437
 
 
438
 
static int
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 )
441
 
{
442
 
    gcry_mpi_t * resarr;
443
 
    cdk_mpi_t a = NULL;
444
 
    size_t nbytes;
445
 
    int i = 0, j = 0, nbits;
446
 
    int rc = 0;
447
 
 
448
 
    if( !hd )
449
 
        return CDK_Inv_Value;
450
 
    if( !pk && !sk )
451
 
        return CDK_Inv_Value;
452
 
    if( type < 0 || type > 1 )
453
 
        return CDK_Inv_Value;
454
 
 
455
 
    resarr = hd->key[type].resarr;
456
 
    if( sk )
457
 
        i += cdk_pk_get_npkey( sk->pubkey_algo );
458
 
    while( j != nkey ) {
459
 
        nbits = gcry_mpi_get_nbits( resarr[i] );
460
 
        if( pk )
461
 
            a = cdk_calloc( 1, sizeof * a + (nbits + 7) / 8 + 2 + 1 );
462
 
        else if( sk )
463
 
            a = cdk_salloc( sizeof * a + (nbits + 7) / 8 + 2 + 1, 1 );
464
 
        a->bits = nbits;
465
 
        a->bytes = ( nbits + 7 ) / 8;
466
 
        nbytes = a->bytes;
467
 
        a->data[0] = nbits >> 8;
468
 
        a->data[1] = nbits;
469
 
        rc = gcry_mpi_print( GCRYMPI_FMT_USG, a->data+2, nbytes, &nbytes, resarr[i] );
470
 
        if( rc )
471
 
            break;
472
 
        if( pk )
473
 
            pk->mpi[j++] = a;
474
 
        else if( sk )
475
 
            sk->mpi[j++] = a;
476
 
        i++;
477
 
    }
478
 
    return rc;
479
 
}
480
 
 
481
 
  
482
 
static cdk_pkt_pubkey_t
483
 
pk_create( cdk_keygen_ctx_t hd, int type )
484
 
{
485
 
    cdk_pkt_pubkey_t pk;
486
 
    int rc = 0, npkey = 0;
487
 
 
488
 
    if( type < 0 || type > 1 )
489
 
        return NULL;
490
 
    pk = cdk_calloc( 1, sizeof * pk );
491
 
    if( !pk )
492
 
        return NULL;
493
 
    pk->version = 4;
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 );
500
 
    if( rc ) {
501
 
        cdk_free( pk );
502
 
        pk = NULL;
503
 
    }
504
 
    return pk;
505
 
}
506
 
 
507
 
 
508
 
static cdk_pkt_seckey_t
509
 
sk_create( cdk_keygen_ctx_t hd, int type )
510
 
{
511
 
    cdk_pkt_seckey_t sk;
512
 
    int nskey, rc = 0;
513
 
 
514
 
    if( type < 0 || type > 1 )
515
 
        return NULL;
516
 
    sk = cdk_calloc( 1, sizeof * sk );
517
 
    if( !sk )
518
 
        return NULL;
519
 
    _cdk_copy_pubkey( &sk->pk, hd->key[type].pk );
520
 
    sk->version = 4;
521
 
    sk->pubkey_algo = hd->key[type].algo;
522
 
    sk->csum = 0;
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 );
526
 
    if( rc ) {
527
 
        cdk_free( sk );
528
 
        sk = NULL;
529
 
    }
530
 
    return sk;
531
 
}
532
 
 
533
 
 
534
 
static cdk_pkt_userid_t
535
 
uid_create( cdk_keygen_ctx_t hd )
536
 
{
537
 
    cdk_pkt_userid_t id;
538
 
 
539
 
    if( !hd->user_id )
540
 
        return NULL;
541
 
    id = cdk_calloc( 1, sizeof * id + strlen( hd->user_id ) + 1 );
542
 
    if( !id )
543
 
        return NULL;
544
 
    strcpy( id->name, hd->user_id );
545
 
    id->len = strlen( hd->user_id );
546
 
    return id;
547
 
}
548
 
 
549
 
 
550
 
static cdk_pkt_signature_t
551
 
sig_subkey_create( cdk_keygen_ctx_t hd )
552
 
{
553
 
    cdk_md_hd_t md;
554
 
    cdk_subpkt_t node;
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;
559
 
    byte buf[4];
560
 
    int rc;
561
 
  
562
 
    sig = cdk_calloc( 1, sizeof * sig );
563
 
    if( !sig )
564
 
        return NULL;
565
 
    _cdk_sig_create( pk, sig );
566
 
    sig->sig_class = 0x18;
567
 
    sig->digest_algo = CDK_MD_SHA1;
568
 
 
569
 
    if( sub_pk->expiredate ) {
570
 
        _cdk_u32tobuf( sub_pk->expiredate - sub_pk->timestamp, buf );
571
 
        node = cdk_subpkt_new( 4 );
572
 
        if( node ) {
573
 
            cdk_subpkt_init( node, CDK_SIGSUBPKT_KEY_EXPIRE, buf, 4 );
574
 
            cdk_subpkt_add( sig->hashed, node );
575
 
        }
576
 
    }
577
 
  
578
 
    md = cdk_md_open( sig->digest_algo, 0 );
579
 
    if( !md ) {
580
 
        _cdk_free_signature( sig );
581
 
        return NULL;
582
 
    }
583
 
    
584
 
    _cdk_hash_pubkey( pk, md, 0 );
585
 
    _cdk_hash_pubkey( sub_pk, md, 0 );
586
 
    rc = _cdk_sig_complete( sig, sk, md );
587
 
    cdk_md_close( md );
588
 
    if( rc ) {
589
 
        _cdk_free_signature( sig );
590
 
        return NULL;
591
 
    }
592
 
    return sig;
593
 
}
594
 
 
595
 
 
596
 
static cdk_pkt_signature_t
597
 
sig_self_create( cdk_keygen_ctx_t hd )
598
 
{
599
 
    cdk_md_hd_t md;
600
 
    cdk_subpkt_t node;
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;
605
 
    u32 keyid[2];
606
 
    byte buf[8], * p;
607
 
    int rc;
608
 
 
609
 
    sig = cdk_calloc( 1, sizeof * sig );
610
 
    if( !sig )
611
 
        return NULL;
612
 
    sig->version = 4;
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;
617
 
 
618
 
    _cdk_u32tobuf( sig->timestamp, buf );
619
 
    sig->hashed = node = cdk_subpkt_new( 4 );
620
 
    if( node )
621
 
        cdk_subpkt_init( node, CDK_SIGSUBPKT_SIG_CREATED, buf, 4 );
622
 
 
623
 
    p = hd->sym_prefs;
624
 
    node = cdk_subpkt_new( hd->sym_len + 1 );
625
 
    if( node ) {
626
 
        cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_SYM, p, hd->sym_len );
627
 
        cdk_subpkt_add( sig->hashed, node );
628
 
    }
629
 
 
630
 
    p = hd->hash_prefs;
631
 
    node = cdk_subpkt_new( hd->hash_len + 1 );
632
 
    if( node ) {
633
 
        cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_HASH, p, hd->hash_len );
634
 
        cdk_subpkt_add( sig->hashed, node );
635
 
    }
636
 
 
637
 
    p = hd->zip_prefs;
638
 
    node = cdk_subpkt_new( hd->zip_len + 1 );
639
 
    if( node ) {
640
 
        cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_ZIP, p, hd->zip_len );
641
 
        cdk_subpkt_add( sig->hashed, node );
642
 
    }
643
 
 
644
 
    if( hd->mdc_feature ) {
645
 
        buf[0] = 0x01;
646
 
        node = cdk_subpkt_new( 1 );
647
 
        if( node ) {
648
 
            cdk_subpkt_init( node, CDK_SIGSUBPKT_FEATURES, buf, 1 );
649
 
            cdk_subpkt_add( sig->hashed, node );
650
 
        }
651
 
    }
652
 
 
653
 
    if( hd->ks_no_modify ) {
654
 
        buf[0] = 0x80;
655
 
        node = cdk_subpkt_new( 1 );
656
 
        if( node ) {
657
 
            cdk_subpkt_init( node, CDK_SIGSUBPKT_KS_FLAGS, buf, 1 );
658
 
            cdk_subpkt_add( sig->hashed, node );
659
 
        }
660
 
    }
661
 
 
662
 
    if( hd->ks_pref_url ) {
663
 
        node = cdk_subpkt_new( strlen( hd->ks_pref_url ) + 1 );
664
 
        if( node ) {
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 );
668
 
        }
669
 
    }
670
 
  
671
 
    if( pk->expiredate ) {
672
 
        node = cdk_subpkt_new( 4 );
673
 
        if( node ) {
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 );
677
 
        }
678
 
    }
679
 
 
680
 
    sig->unhashed = node = cdk_subpkt_new( 8 );
681
 
    if( node ) {
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 );
686
 
    }
687
 
 
688
 
    md = cdk_md_open( sig->digest_algo, 0 );
689
 
    if( !md ) {
690
 
        _cdk_free_signature( sig );
691
 
        return NULL;
692
 
    }
693
 
 
694
 
    _cdk_hash_pubkey( pk, md, 0 );
695
 
    _cdk_hash_userid( id, sig->version == 4, md );
696
 
    rc = _cdk_sig_complete( sig, sk, md );
697
 
    cdk_md_close( md );
698
 
    if( rc ) {
699
 
        _cdk_free_signature( sig );
700
 
        return NULL;
701
 
    }  
702
 
    return sig;
703
 
}
704
 
 
705
 
 
706
 
/**
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
711
 
 *
712
 
 **/
713
 
cdk_error_t
714
 
cdk_keygen_save( cdk_keygen_ctx_t hd, const char * pubf, const char * secf )
715
 
{
716
 
    cdk_stream_t out = NULL;
717
 
    CDK_PACKET pkt;
718
 
    int rc;
719
 
 
720
 
    hd->key[0].pk = pk_create( hd, 0 );
721
 
    if( !hd->key[0].pk )
722
 
        return CDK_Inv_Packet;
723
 
    hd->key[0].sk = sk_create( hd, 0 );
724
 
    if( !hd->key[0].sk )
725
 
        return CDK_Inv_Packet;
726
 
    hd->id = uid_create( hd );
727
 
    if( !hd->id )
728
 
        return CDK_Inv_Packet;
729
 
    hd->sig = sig_self_create( hd );
730
 
    if( !hd->sig )
731
 
        return CDK_Inv_Packet;
732
 
 
733
 
    rc = cdk_stream_create( pubf, &out );
734
 
    if( rc )
735
 
        return rc;
736
 
  
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 );
741
 
    if( rc )
742
 
        goto fail;
743
 
  
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 );
748
 
    if( rc )
749
 
        goto fail;
750
 
 
751
 
    cdk_pkt_init( &pkt );
752
 
    pkt.pkttype = CDK_PKT_SIGNATURE;
753
 
    pkt.pkt.signature = hd->sig;
754
 
    rc = cdk_pkt_write( out, &pkt );
755
 
    if( rc )
756
 
        goto fail;
757
 
 
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 );
763
 
        if( rc )
764
 
            goto fail;
765
 
 
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 );
771
 
        if( rc )
772
 
            goto fail;
773
 
    }
774
 
  
775
 
    cdk_stream_close( out );
776
 
    out = NULL;
777
 
 
778
 
    rc = cdk_stream_create( secf, &out );
779
 
    if( rc )
780
 
        goto fail;
781
 
 
782
 
    if( hd->protect ) {
783
 
        rc = cdk_sk_protect( hd->key[0].sk, hd->pass );
784
 
        if( rc )
785
 
            goto fail;
786
 
    }
787
 
 
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 );
792
 
    if( rc )
793
 
        goto fail;
794
 
 
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 );
799
 
    if( rc )
800
 
        goto fail;
801
 
 
802
 
    cdk_pkt_init( &pkt );
803
 
    pkt.pkttype = CDK_PKT_SIGNATURE;
804
 
    pkt.pkt.signature = hd->sig;
805
 
    rc = cdk_pkt_write( out, &pkt );
806
 
    if( rc )
807
 
        goto fail;
808
 
 
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 )) )
812
 
            goto fail;
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 );
817
 
        if( rc )
818
 
            goto fail;
819
 
    }
820
 
 
821
 
 fail:
822
 
    cdk_stream_close( out );
823
 
    return rc;
824
 
}
825
 
 
826
 
 
827
 
/**
828
 
 * cdk_keygen_free: free the keygen object
829
 
 * @hd: the keygen object
830
 
 *
831
 
 **/
832
 
void
833
 
cdk_keygen_free( cdk_keygen_ctx_t hd )
834
 
{
835
 
    if( 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 );
848
 
        cdk_free( hd );
849
 
    }
850
 
}
851
 
 
852
 
 
853
 
/**
854
 
 * cdk_keygen_new:
855
 
 * @r_hd: the new object
856
 
 *
857
 
 **/
858
 
cdk_error_t
859
 
cdk_keygen_new( cdk_keygen_ctx_t * r_hd )
860
 
{
861
 
    cdk_keygen_ctx_t hd;
862
 
 
863
 
    if( !r_hd )
864
 
        return CDK_Inv_Value;
865
 
    hd = cdk_calloc( 1, sizeof * hd );
866
 
    if( !hd )
867
 
        return CDK_Out_Of_Core;
868
 
    *r_hd = hd;
869
 
    return 0;
870
 
}