diff options
Diffstat (limited to 'libextra/opencdk/keygen.c')
-rw-r--r-- | libextra/opencdk/keygen.c | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/libextra/opencdk/keygen.c b/libextra/opencdk/keygen.c new file mode 100644 index 0000000000..c1f0ad1773 --- /dev/null +++ b/libextra/opencdk/keygen.c @@ -0,0 +1,870 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- + * keygen.c - OpenPGP key generation + * Copyright (C) 2002, 2003 Timo Schulz + * + * This file is part of OpenCDK. + * + * OpenCDK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * OpenCDK 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 + * along with OpenCDK; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdio.h> + +#include "opencdk.h" +#include "main.h" +#include "packet.h" +#include "cipher.h" +#include "types.h" + +struct key_ctx_s { + u32 expire_date; + int algo; + int len; + gcry_mpi_t resarr[6]; + size_t n; + cdk_pkt_pubkey_t pk; + cdk_pkt_seckey_t sk; +}; + + +struct cdk_keygen_ctx_s { + char * user_id; + cdk_pkt_userid_t id; + byte * sym_prefs; + size_t sym_len; + byte * hash_prefs; + size_t hash_len; + byte * zip_prefs; + size_t zip_len; + unsigned mdc_feature:1; + unsigned ks_no_modify:1; + char * ks_pref_url; + cdk_pkt_signature_t sig; + unsigned protect:1; + struct key_ctx_s key[2]; + char * pass; + size_t pass_len; +}; + + +/* default preferences */ +static byte def_sym_prefs[] = {CDK_CIPHER_AES, CDK_CIPHER_CAST5, + CDK_CIPHER_TWOFISH, CDK_CIPHER_AES192, + CDK_CIPHER_AES256, CDK_CIPHER_3DES, + CDK_CIPHER_BLOWFISH}; +static byte def_hash_prefs[] = {CDK_MD_SHA1, CDK_MD_RMD160, CDK_MD_MD5}; +static byte def_zip_prefs[] = {CDK_COMPRESS_ZIP, CDK_COMPRESS_ZLIB}; + + +static int +check_pref_array( const byte * p, size_t n, int type ) +{ + int i; + + if( !p ) + return 0; + + if( type == CDK_PREFTYPE_SYM ) { + for( i = 0; i < n; i++ ) { + if( cdk_cipher_test_algo( p[i] ) ) + return -1; + } + } + else if( type == CDK_PREFTYPE_HASH ) { + for( i = 0; i < n; i++ ) { + if( cdk_md_test_algo( p[i] ) ) + return -1; + } + } + else if( type == CDK_PREFTYPE_ZIP ) { + if( n > 2 ) + return -1; + if( p[0] > 2 || p[1] > 2 ) + return -1; + } + else + return -1; + return 0; +} + + +/** + * cdk_keygen_set_prefs: Set the preferences for the userID + * @hd: the keygen object + * @hd: the preference type + * @array: one-octet array with algorithm numers + * + **/ +cdk_error_t +cdk_keygen_set_prefs( cdk_keygen_ctx_t hd, enum cdk_pref_type_t type, + const byte * array, size_t n ) +{ + int rc; + + if( !hd ) + return CDK_Inv_Value; + + rc = check_pref_array( array, n, type ); + if( rc ) + return CDK_Inv_Value; + + switch( type) { + case CDK_PREFTYPE_SYM: + hd->sym_len = array? n : DIM( def_sym_prefs ); + hd->sym_prefs = cdk_calloc( 1, hd->sym_len ); + if( hd->sym_prefs ) + memcpy( hd->sym_prefs, array? array : def_sym_prefs, hd->sym_len ); + break; + + case CDK_PREFTYPE_HASH: + hd->hash_len = array? n : DIM( def_hash_prefs ); + hd->hash_prefs = cdk_calloc( 1, hd->hash_len ); + if( hd->hash_prefs ) + memcpy( hd->hash_prefs, array? array : def_hash_prefs, + hd->hash_len ); + break; + + case CDK_PREFTYPE_ZIP: + hd->zip_len = array? n : DIM( def_zip_prefs ); + hd->zip_prefs = cdk_calloc( 1, hd->zip_len ); + if( hd->zip_prefs ) + memcpy( hd->zip_prefs, array? array : def_zip_prefs, hd->zip_len ); + break; + + default: + return CDK_Inv_Mode; + } + + return 0; +} + + +/** + * cdk_keygen_set_name: set the userid name for the key + * @hd: the keygen object + * @name: name + * + * The name will be encoded in UTF8 to avoid problems. + **/ +void +cdk_keygen_set_name( cdk_keygen_ctx_t hd, const char * name ) +{ + if( hd ) { + cdk_free( hd->user_id ); + hd->user_id = cdk_utf8_encode( name ); + } +} + + +static int +check_bits( int bits, int algo ) +{ + if( bits < 768 ) + return 768; + if( algo == CDK_PK_DSA && bits > 1024 ) + return 1024; + if( bits > 4096 ) + return 4096; + return bits; +} + + +/** + * cdk_keygen_set_algo_info: set the length and type of the key + * @hd: the keygen object. + * @type: key type (primary=0, subkey=1) + * @algo: algorithm compliant with rfc2440 + * @bits: lengt of the key in bits + * + **/ +cdk_error_t +cdk_keygen_set_algo_info( cdk_keygen_ctx_t hd, int type, + enum cdk_pk_algo_t algo, int bits ) +{ + int rc; + int usage = type? PK_USAGE_ENCR : PK_USAGE_SIGN; + + if( !hd ) + return CDK_Inv_Value; + if( type < 0 || type > 1 ) + return CDK_Inv_Value; + + if( bits % 128 != 0 ) + bits = bits + ( bits % 128 ); + + rc = _cdk_pk_test_algo( algo, usage ); + if( rc ) + return rc; + + /* type=0 primary type=1 sub */ + hd->key[type].algo = algo; + hd->key[type].len = check_bits( bits, algo ); + + return 0; +} + + +/** + * cdk_keygen_set_mdc_feature: set the mdc feature for the key + * @hd: keygen object + * @val: boolean( yes=1, no=0) + * + * if you want a RFC2440 compliant key, you've to disable this feature + * until the rfc2440-bis8 becomes the next standard. + **/ +void +cdk_keygen_set_mdc_feature( cdk_keygen_ctx_t hd, int val ) +{ + if( hd ) + hd->mdc_feature = val; +} + + + +void +cdk_keygen_set_keyserver_flags( cdk_keygen_ctx_t hd, int no_modify, + const char *pref_url ) +{ + if( no_modify ) + hd->ks_no_modify = 1; + if( pref_url ) + hd->ks_pref_url = cdk_strdup( pref_url ); +} /* cdk_keygen_set_keyserver_flags */ + + +/** + * cdk_keygen_set_expire_date: set the expire date of the primary key + * @hd: keygen object + * @type: key type( 0=primary, 1=seconardy) + * @timestamp: the date the key should expire + * + **/ +void +cdk_keygen_set_expire_date( cdk_keygen_ctx_t hd, int type, long timestamp ) +{ + if( !hd ) + return; + if( type < 0 || type > 1 ) + return; + if( timestamp < 0 || timestamp < _cdk_timestamp( ) ) + timestamp = 0; + hd->key[type].expire_date = timestamp; +} + + +void +cdk_keygen_set_passphrase( cdk_keygen_ctx_t hd, const char * pass ) +{ + if( !hd ) + return; + if( pass ) { + size_t n = strlen( pass ); + _cdk_sec_free( hd->pass, hd->pass_len ); + hd->pass = cdk_salloc( n + 1, 1 ); + if( hd->pass ) { + memcpy( hd->pass, pass, n ); + hd->pass[n] = '\0'; + hd->pass_len = n; + hd->protect = 1; + } + } +} + + +static int +read_single_mpi( gcry_sexp_t s_key, const char * val, gcry_mpi_t * r_resarr ) +{ + gcry_sexp_t list; + + if( !r_resarr ) + return CDK_Inv_Value; + list = gcry_sexp_find_token( s_key, val, 0 ); + if( list ) + *r_resarr = gcry_sexp_nth_mpi( list, 1, 0 ); + gcry_sexp_release( list ); + return list? 0 : CDK_Gcry_Error; +} + + +static int +read_dsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr ) +{ + int rc = read_single_mpi( s_key, "p", &resarr[0] ); + if( !rc ) + rc = read_single_mpi( s_key, "q", &resarr[1] ); + if( !rc ) + rc = read_single_mpi( s_key, "g", &resarr[2] ); + if( !rc ) + rc = read_single_mpi( s_key, "y", &resarr[3] ); + if( !rc ) + rc = read_single_mpi( s_key, "x", &resarr[4] ); + return rc; +} + + +static int +read_elg_key( gcry_sexp_t s_key, gcry_mpi_t * resarr ) +{ + int rc = read_single_mpi( s_key, "p", &resarr[0] ); + if( !rc ) + rc = read_single_mpi( s_key, "g", &resarr[1] ); + if( !rc ) + rc = read_single_mpi( s_key, "y", &resarr[2] ); + if( !rc ) + rc = read_single_mpi( s_key, "x", &resarr[3] ); + return rc; +} + + +static int +read_rsa_key( gcry_sexp_t s_key, gcry_mpi_t * resarr ) +{ + int rc = read_single_mpi( s_key, "n", &resarr[0] ); + if( !rc ) + rc =read_single_mpi( s_key, "e", &resarr[1] ); + if( !rc ) + rc = read_single_mpi( s_key, "d", &resarr[2] ); + if( !rc ) + rc = read_single_mpi( s_key, "p", &resarr[3] ); + if( !rc ) + rc = read_single_mpi( s_key, "q", &resarr[4] ); + if( !rc ) + rc = read_single_mpi( s_key, "u", &resarr[5] ); + return rc; +} + + +static int +generate_subkey( cdk_keygen_ctx_t hd ) +{ + gcry_sexp_t s_params = NULL, s_key; + size_t n = hd->key[1].len; + int rc; + + if( !hd ) + return CDK_Inv_Value; + + if( is_DSA( hd->key[1].algo) ) + rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n ); + else if( is_ELG( hd->key[1].algo) ) + rc = gcry_sexp_build( &s_params, NULL, "(genkey(elg(nbits %d)))", n ); + else if( is_RSA( hd->key[1].algo) ) + rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n ); + else + rc = CDK_Inv_Algo; + if( !rc ) + rc = gcry_pk_genkey( &s_key, s_params ); + gcry_sexp_release( s_params ); + if( !rc ) { + if( is_DSA( hd->key[1].algo) ) + rc = read_dsa_key( s_key, hd->key[1].resarr ); + else if( is_ELG( hd->key[1].algo) ) + rc = read_elg_key( s_key, hd->key[1].resarr ); + else if( is_RSA( hd->key[1].algo) ) + rc = read_rsa_key( s_key, hd->key[1].resarr ); + } + hd->key[1].n = cdk_pk_get_npkey( hd->key[1].algo ); + gcry_sexp_release( s_key ); + return rc; +} + + +/** + * cdk_keygen_start: kick off the key generation + * @hd: the keygen object + * + **/ +cdk_error_t +cdk_keygen_start( cdk_keygen_ctx_t hd ) +{ + gcry_sexp_t s_params = NULL, s_key = NULL; + size_t n; + int rc = 0; + + if( !hd || !hd->user_id ) + return CDK_Inv_Value; + if( is_ELG( hd->key[0].algo ) ) + return CDK_Inv_Mode; + if( !hd->key[0].len ) + hd->key[0].len = 1024; + n = hd->key[0].len; + + if( !hd->sym_prefs ) + cdk_keygen_set_prefs( hd, CDK_PREFTYPE_SYM, NULL, 0 ); + if( !hd->hash_prefs ) + cdk_keygen_set_prefs( hd, CDK_PREFTYPE_HASH, NULL, 0 ); + if( !hd->zip_prefs ) + cdk_keygen_set_prefs( hd, CDK_PREFTYPE_ZIP, NULL, 0 ); + + if( is_DSA( hd->key[0].algo ) ) + rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n ); + else if( is_RSA( hd->key[0].algo ) ) + rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n ); + else + rc = CDK_Inv_Algo; + if( !rc ) + rc = gcry_pk_genkey( &s_key, s_params ); + gcry_sexp_release( s_params ); + if( !rc ) { + if( is_DSA( hd->key[0].algo ) ) + rc = read_dsa_key( s_key, hd->key[0].resarr ); + else if( is_RSA( hd->key[0].algo ) ) + rc = read_rsa_key( s_key, hd->key[0].resarr ); + hd->key[0].n = cdk_pk_get_npkey( hd->key[0].algo ); + } + gcry_sexp_release( s_key ); + if( !rc ) { + if( hd->key[1].algo && hd->key[1].len ) + rc = generate_subkey( hd ); + } + return rc; +} + + +static int +gcry_mpi_to_native( cdk_keygen_ctx_t hd, size_t nkey, int type, + cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk ) +{ + gcry_mpi_t * resarr; + cdk_mpi_t a = NULL; + size_t nbytes; + int i = 0, j = 0, nbits; + int rc = 0; + + if( !hd ) + return CDK_Inv_Value; + if( !pk && !sk ) + return CDK_Inv_Value; + if( type < 0 || type > 1 ) + return CDK_Inv_Value; + + resarr = hd->key[type].resarr; + if( sk ) + i += cdk_pk_get_npkey( sk->pubkey_algo ); + while( j != nkey ) { + nbits = gcry_mpi_get_nbits( resarr[i] ); + if( pk ) + a = cdk_calloc( 1, sizeof * a + (nbits + 7) / 8 + 2 + 1 ); + else if( sk ) + a = cdk_salloc( sizeof * a + (nbits + 7) / 8 + 2 + 1, 1 ); + a->bits = nbits; + a->bytes = ( nbits + 7 ) / 8; + nbytes = a->bytes; + a->data[0] = nbits >> 8; + a->data[1] = nbits; + rc = gcry_mpi_print( GCRYMPI_FMT_USG, a->data+2, nbytes, &nbytes, resarr[i] ); + if( rc ) + break; + if( pk ) + pk->mpi[j++] = a; + else if( sk ) + sk->mpi[j++] = a; + i++; + } + return rc; +} + + +static cdk_pkt_pubkey_t +pk_create( cdk_keygen_ctx_t hd, int type ) +{ + cdk_pkt_pubkey_t pk; + int rc = 0, npkey = 0; + + if( type < 0 || type > 1 ) + return NULL; + pk = cdk_calloc( 1, sizeof * pk ); + if( !pk ) + return NULL; + pk->version = 4; + pk->pubkey_algo = hd->key[type].algo; + pk->timestamp = _cdk_timestamp( ); + if( hd->key[type].expire_date ) + pk->expiredate = pk->timestamp + hd->key[type].expire_date; + npkey = cdk_pk_get_npkey( pk->pubkey_algo ); + rc = gcry_mpi_to_native( hd, npkey, type, pk, NULL ); + if( rc ) { + cdk_free( pk ); + pk = NULL; + } + return pk; +} + + +static cdk_pkt_seckey_t +sk_create( cdk_keygen_ctx_t hd, int type ) +{ + cdk_pkt_seckey_t sk; + int nskey, rc = 0; + + if( type < 0 || type > 1 ) + return NULL; + sk = cdk_calloc( 1, sizeof * sk ); + if( !sk ) + return NULL; + _cdk_copy_pubkey( &sk->pk, hd->key[type].pk ); + sk->version = 4; + sk->pubkey_algo = hd->key[type].algo; + sk->csum = 0; + sk->is_protected = 0; + nskey = cdk_pk_get_nskey( sk->pubkey_algo ); + rc = gcry_mpi_to_native( hd, nskey, type, NULL, sk ); + if( rc ) { + cdk_free( sk ); + sk = NULL; + } + return sk; +} + + +static cdk_pkt_userid_t +uid_create( cdk_keygen_ctx_t hd ) +{ + cdk_pkt_userid_t id; + + if( !hd->user_id ) + return NULL; + id = cdk_calloc( 1, sizeof * id + strlen( hd->user_id ) + 1 ); + if( !id ) + return NULL; + strcpy( id->name, hd->user_id ); + id->len = strlen( hd->user_id ); + return id; +} + + +static cdk_pkt_signature_t +sig_subkey_create( cdk_keygen_ctx_t hd ) +{ + cdk_md_hd_t md; + cdk_subpkt_t node; + cdk_pkt_signature_t sig; + cdk_pkt_pubkey_t pk = hd->key[0].pk; + cdk_pkt_pubkey_t sub_pk = hd->key[1].pk; + cdk_pkt_seckey_t sk = hd->key[0].sk; + byte buf[4]; + int rc; + + sig = cdk_calloc( 1, sizeof * sig ); + if( !sig ) + return NULL; + _cdk_sig_create( pk, sig ); + sig->sig_class = 0x18; + sig->digest_algo = CDK_MD_SHA1; + + if( sub_pk->expiredate ) { + _cdk_u32tobuf( sub_pk->expiredate - sub_pk->timestamp, buf ); + node = cdk_subpkt_new( 4 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_KEY_EXPIRE, buf, 4 ); + cdk_subpkt_add( sig->hashed, node ); + } + } + + md = cdk_md_open( sig->digest_algo, 0 ); + if( !md ) { + _cdk_free_signature( sig ); + return NULL; + } + + _cdk_hash_pubkey( pk, md, 0 ); + _cdk_hash_pubkey( sub_pk, md, 0 ); + rc = _cdk_sig_complete( sig, sk, md ); + cdk_md_close( md ); + if( rc ) { + _cdk_free_signature( sig ); + return NULL; + } + return sig; +} + + +static cdk_pkt_signature_t +sig_self_create( cdk_keygen_ctx_t hd ) +{ + cdk_md_hd_t md; + cdk_subpkt_t node; + cdk_pkt_signature_t sig; + cdk_pkt_pubkey_t pk = hd->key[0].pk; + cdk_pkt_userid_t id = hd->id; + cdk_pkt_seckey_t sk = hd->key[0].sk; + u32 keyid[2]; + byte buf[8], * p; + int rc; + + sig = cdk_calloc( 1, sizeof * sig ); + if( !sig ) + return NULL; + sig->version = 4; + sig->timestamp = _cdk_timestamp( ); + sig->sig_class = 0x13; + sig->pubkey_algo = hd->key[0].algo; + sig->digest_algo = CDK_MD_SHA1; + + _cdk_u32tobuf( sig->timestamp, buf ); + sig->hashed = node = cdk_subpkt_new( 4 ); + if( node ) + cdk_subpkt_init( node, CDK_SIGSUBPKT_SIG_CREATED, buf, 4 ); + + p = hd->sym_prefs; + node = cdk_subpkt_new( hd->sym_len + 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_SYM, p, hd->sym_len ); + cdk_subpkt_add( sig->hashed, node ); + } + + p = hd->hash_prefs; + node = cdk_subpkt_new( hd->hash_len + 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_HASH, p, hd->hash_len ); + cdk_subpkt_add( sig->hashed, node ); + } + + p = hd->zip_prefs; + node = cdk_subpkt_new( hd->zip_len + 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_PREFS_ZIP, p, hd->zip_len ); + cdk_subpkt_add( sig->hashed, node ); + } + + if( hd->mdc_feature ) { + buf[0] = 0x01; + node = cdk_subpkt_new( 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_FEATURES, buf, 1 ); + cdk_subpkt_add( sig->hashed, node ); + } + } + + if( hd->ks_no_modify ) { + buf[0] = 0x80; + node = cdk_subpkt_new( 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_KS_FLAGS, buf, 1 ); + cdk_subpkt_add( sig->hashed, node ); + } + } + + if( hd->ks_pref_url ) { + node = cdk_subpkt_new( strlen( hd->ks_pref_url ) + 1 ); + if( node ) { + cdk_subpkt_init( node, CDK_SIGSUBPKT_PREF_KS, + hd->ks_pref_url, strlen( hd->ks_pref_url ) ); + cdk_subpkt_add( sig->hashed, node ); + } + } + + if( pk->expiredate ) { + node = cdk_subpkt_new( 4 ); + if( node ) { + _cdk_u32tobuf( pk->expiredate - pk->timestamp, buf ); + cdk_subpkt_init( node, CDK_SIGSUBPKT_KEY_EXPIRE, buf, 4 ); + cdk_subpkt_add( sig->hashed, node ); + } + } + + sig->unhashed = node = cdk_subpkt_new( 8 ); + if( node ) { + cdk_pk_get_keyid( pk, keyid ); + _cdk_u32tobuf( keyid[0], buf ); + _cdk_u32tobuf( keyid[1], buf + 4 ); + cdk_subpkt_init( node, CDK_SIGSUBPKT_ISSUER, buf, 8 ); + } + + md = cdk_md_open( sig->digest_algo, 0 ); + if( !md ) { + _cdk_free_signature( sig ); + return NULL; + } + + _cdk_hash_pubkey( pk, md, 0 ); + _cdk_hash_userid( id, sig->version == 4, md ); + rc = _cdk_sig_complete( sig, sk, md ); + cdk_md_close( md ); + if( rc ) { + _cdk_free_signature( sig ); + return NULL; + } + return sig; +} + + +/** + * cdk_keygen_save: save the generated keys to disk + * @hd: the keygen object + * @pub: name of the file to store the public key + * @sec: name of the file to store the secret key + * + **/ +cdk_error_t +cdk_keygen_save( cdk_keygen_ctx_t hd, const char * pubf, const char * secf ) +{ + cdk_stream_t out = NULL; + CDK_PACKET pkt; + int rc; + + hd->key[0].pk = pk_create( hd, 0 ); + if( !hd->key[0].pk ) + return CDK_Inv_Packet; + hd->key[0].sk = sk_create( hd, 0 ); + if( !hd->key[0].sk ) + return CDK_Inv_Packet; + hd->id = uid_create( hd ); + if( !hd->id ) + return CDK_Inv_Packet; + hd->sig = sig_self_create( hd ); + if( !hd->sig ) + return CDK_Inv_Packet; + + rc = cdk_stream_create( pubf, &out ); + if( rc ) + return rc; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_PUBLIC_KEY; + pkt.pkt.public_key = hd->key[0].pk; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_USER_ID; + pkt.pkt.user_id = hd->id; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_SIGNATURE; + pkt.pkt.signature = hd->sig; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + if( hd->key[1].algo ) { + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_PUBLIC_SUBKEY; + pkt.pkt.public_key = hd->key[1].pk = pk_create( hd, 1 ); + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_SIGNATURE; + pkt.pkt.signature = sig_subkey_create( hd ); + rc = cdk_pkt_write( out, &pkt ); + cdk_pkt_free( &pkt ); + if( rc ) + goto fail; + } + + cdk_stream_close( out ); + out = NULL; + + rc = cdk_stream_create( secf, &out ); + if( rc ) + goto fail; + + if( hd->protect ) { + rc = cdk_sk_protect( hd->key[0].sk, hd->pass ); + if( rc ) + goto fail; + } + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_SECRET_KEY; + pkt.pkt.secret_key = hd->key[0].sk; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_USER_ID; + pkt.pkt.user_id = hd->id; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_SIGNATURE; + pkt.pkt.signature = hd->sig; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + + if( hd->key[1].algo ) { + hd->key[1].sk = sk_create( hd, 1 ); + if( hd->protect && (rc = cdk_sk_protect( hd->key[1].sk, hd->pass )) ) + goto fail; + cdk_pkt_init( &pkt ); + pkt.pkttype = CDK_PKT_SECRET_SUBKEY; + pkt.pkt.secret_key = hd->key[1].sk; + rc = cdk_pkt_write( out, &pkt ); + if( rc ) + goto fail; + } + + fail: + cdk_stream_close( out ); + return rc; +} + + +/** + * cdk_keygen_free: free the keygen object + * @hd: the keygen object + * + **/ +void +cdk_keygen_free( cdk_keygen_ctx_t hd ) +{ + if( hd ) { + _cdk_free_pubkey( hd->key[0].pk ); + _cdk_free_pubkey( hd->key[1].pk ); + _cdk_free_seckey( hd->key[0].sk ); + _cdk_free_seckey( hd->key[1].sk ); + _cdk_free_userid( hd->id ); + _cdk_free_signature( hd->sig ); + cdk_free( hd->sym_prefs ); + cdk_free( hd->hash_prefs ); + cdk_free( hd->zip_prefs ); + _cdk_sec_free( hd->pass, hd->pass_len ); + _cdk_free_mpibuf( hd->key[0].n, hd->key[0].resarr ); + _cdk_free_mpibuf( hd->key[1].n, hd->key[1].resarr ); + cdk_free( hd ); + } +} + + +/** + * cdk_keygen_new: + * @r_hd: the new object + * + **/ +cdk_error_t +cdk_keygen_new( cdk_keygen_ctx_t * r_hd ) +{ + cdk_keygen_ctx_t hd; + + if( !r_hd ) + return CDK_Inv_Value; + hd = cdk_calloc( 1, sizeof * hd ); + if( !hd ) + return CDK_Out_Of_Core; + *r_hd = hd; + return 0; +} |