cdk_error_t _cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx) { cdk_packet_t pkt; cdk_error_t rc; rc = cdk_pkt_new (&pkt); if (rc) return rc; switch (pkttype) { case CDK_PKT_PUBLIC_KEY: case CDK_PKT_PUBLIC_SUBKEY: pkt->pkt.public_key = pktctx; break; case CDK_PKT_SIGNATURE: pkt->pkt.signature = pktctx; break; case CDK_PKT_SECRET_KEY: case CDK_PKT_SECRET_SUBKEY: pkt->pkt.secret_key = pktctx; break; case CDK_PKT_USER_ID: pkt->pkt.user_id = pktctx; break; } pkt->pkttype = pkttype; rc = cdk_pkt_write (out, pkt); cdk_free (pkt); return rc; }
/** * cdk_sklist_write: * @skl: secret keylist * @outp: the stream to write in the data * @hash: opaque handle for the message digest operations * @sigclass: the class of the sig * @sigver: version of the sig * * Complete the sig based on @hash and write all signatures to @outp. **/ cdk_error_t cdk_sklist_write( cdk_keylist_t skl, cdk_stream_t outp, cdk_md_hd_t hash, int sigclass, int sigver ) { cdk_keylist_t r = NULL; cdk_pkt_signature_t sig = NULL; cdk_packet_t pkt; cdk_md_hd_t md = NULL; byte * mdbuf; int rc = 0, digest_algo; if( !skl || !outp || !hash ) return CDK_Inv_Value; if( skl->type != CDK_PKT_SECRET_KEY ) return CDK_Inv_Mode; pkt = cdk_calloc( 1, sizeof *pkt ); if( !pkt ) return CDK_Out_Of_Core; digest_algo = cdk_md_get_algo( hash ); for( r = skl; r; r = r->next ) { sig = cdk_calloc( 1, sizeof *sig ); if( !sig ) return CDK_Out_Of_Core; sig->version = sigver; _cdk_sig_create( r->key.sk->pk, sig ); if( sig->digest_algo != digest_algo ) sig->digest_algo = digest_algo; sig->sig_class = sigclass; md = cdk_md_copy( hash ); _cdk_hash_sig_data( sig, md ); cdk_md_final( md ); mdbuf = cdk_md_read( md, sig->digest_algo ); rc = cdk_pk_sign( r->key.sk, sig, mdbuf ); if( rc ) break; cdk_pkt_init( pkt ); pkt->old_ctb = sig->version == 3? 1 : 0; pkt->pkttype = CDK_PKT_SIGNATURE; pkt->pkt.signature = sig; rc = cdk_pkt_write( outp, pkt ); cdk_pkt_free( pkt ); if( rc ) break; cdk_md_close( md ); md = NULL; } cdk_free( pkt ); cdk_md_close( md ); return rc; }
/** * cdk_kbnode_write_to_mem_alloc: * @node: the key node * @r_buf: buffer to hold the raw data * @r_buflen: buffer length of the allocated raw data. * * The function acts similar to cdk_kbnode_write_to_mem but * it allocates the buffer to avoid the lengthy second run. */ cdk_error_t cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node, byte ** r_buf, size_t * r_buflen) { cdk_kbnode_t n; cdk_stream_t s; cdk_error_t rc; size_t len; if (!node || !r_buf || !r_buflen) { gnutls_assert (); return CDK_Inv_Value; } *r_buf = NULL; *r_buflen = 0; rc = cdk_stream_tmp_new (&s); if (rc) { gnutls_assert (); return rc; } for (n = node; n; n = n->next) { /* Skip all packets which cannot occur in a key composition. */ if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY && n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY && n->pkt->pkttype != CDK_PKT_SECRET_KEY && n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY && n->pkt->pkttype != CDK_PKT_SIGNATURE && n->pkt->pkttype != CDK_PKT_USER_ID && n->pkt->pkttype != CDK_PKT_ATTRIBUTE) continue; rc = cdk_pkt_write (s, n->pkt); if (rc) { cdk_stream_close (s); gnutls_assert (); return rc; } } cdk_stream_seek (s, 0); len = cdk_stream_get_length (s); *r_buf = cdk_calloc (1, len); *r_buflen = cdk_stream_read (s, *r_buf, len); cdk_stream_close (s); return 0; }
cdk_error_t _cdk_pkt_write_fp (FILE * out, cdk_packet_t pkt) { cdk_stream_t so; cdk_error_t rc; rc = _cdk_stream_fpopen (out, 1, &so); if (rc) return rc; rc = cdk_pkt_write (so, pkt); cdk_stream_close (so); return rc; }
/** * cdk_sklist_write_onepass: * @skl: secret keylist * @outp: the stream to write in the data * @sigclass: the class of the sig to create * @mdalgo: the message digest algorithm * * Write a one-pass signature for each key in the list into @outp. **/ cdk_error_t cdk_sklist_write_onepass( cdk_keylist_t skl, cdk_stream_t outp, int sigclass, int mdalgo ) { cdk_pkt_onepass_sig_t ops; cdk_keylist_t r; cdk_packet_t pkt; int i, skcount = 0; int rc = 0; if( !skl || !outp ) return CDK_Inv_Value; if( skl->type != CDK_PKT_SECRET_KEY ) return CDK_Inv_Mode; pkt = cdk_calloc( 1, sizeof * pkt ); if( !pkt ) return CDK_Out_Of_Core; for( skcount = 0, r = skl; r; r = r->next ) skcount++; for( ; skcount; skcount-- ) { for( i = 0, r = skl; r; r = r->next ) { if( ++i == skcount ) break; } ops = cdk_calloc( 1, sizeof *ops ); if( !ops ) return CDK_Out_Of_Core; ops->version = 3; cdk_sk_get_keyid( r->key.sk, ops->keyid ); ops->sig_class = sigclass; if( !mdalgo ) mdalgo = _cdk_sig_hash_for( r->key.sk->pubkey_algo, r->key.sk->version ); ops->digest_algo = mdalgo; ops->pubkey_algo = r->key.sk->pubkey_algo; ops->last = (skcount == 1); cdk_pkt_init( pkt ); pkt->pkttype = CDK_PKT_ONEPASS_SIG; pkt->pkt.onepass_sig = ops; rc = cdk_pkt_write( outp, pkt ); cdk_pkt_free( pkt ); if( rc ) break; } cdk_free( pkt ); return rc; }
/** * cdk_pklist_encrypt: * @pkl: the keylist * @dek: the data encryption key * @outp: the stream to write in the data * * Encrypt the session key with each key of the list and wrap it * into a PUBKEY_ENC packet and write it to @outp. */ cdk_error_t cdk_pklist_encrypt( cdk_keylist_t pk_list, cdk_dek_t dek, cdk_stream_t outp ) { cdk_pkt_pubkey_t pk = NULL; cdk_pkt_pubkey_enc_t enc = NULL; cdk_packet_t pkt; cdk_sesskey_t frame = NULL; int nbits = 0; int rc = 0; if( !pk_list || !dek || !outp ) return CDK_Inv_Value; if( pk_list->type != CDK_PKT_PUBLIC_KEY ) return CDK_Inv_Mode; pkt = cdk_calloc( 1, sizeof * pkt ); if( !pkt ) return CDK_Out_Of_Core; for( ; pk_list; pk_list = pk_list->next ) { pk = pk_list->key.pk; cdk_free( enc ); enc = cdk_calloc( 1, sizeof *enc ); if( !enc ) return CDK_Out_Of_Core; enc->version = 3; enc->pubkey_algo = pk->pubkey_algo; cdk_pk_get_keyid( pk, enc->keyid ); nbits = cdk_pk_get_nbits( pk ); rc = cdk_dek_encode_pkcs1( dek, nbits, &frame ); if( rc ) break; rc = cdk_pk_encrypt( pk, enc, frame ); cdk_sesskey_free( frame ); if( rc ) break; else { cdk_pkt_init( pkt ); pkt->old_ctb = dek->rfc1991? 1 : 0; pkt->pkttype = CDK_PKT_PUBKEY_ENC; pkt->pkt.pubkey_enc = enc; rc = cdk_pkt_write( outp, pkt ); cdk_pkt_free( pkt ); if( rc ) break; } } cdk_free( pkt ); cdk_free( enc ); return rc; }
cdk_error_t cdk_keydb_import( cdk_keydb_hd_t hd, cdk_kbnode_t knode, int *result ) { cdk_kbnode_t node, chk = NULL; cdk_packet_t pkt; cdk_stream_t out; u32 keyid[2]; int rc = 0, is_sk = 0; if( !hd || !knode ) return CDK_Inv_Value; memset( result, 0, 4 * sizeof (int) ); pkt = find_key_packet( knode, &is_sk ); if( !pkt ) return CDK_Inv_Packet; result[is_sk] = 1; _cdk_pkt_get_keyid( pkt, keyid ); cdk_keydb_get_bykeyid( hd, keyid, &chk ); if( chk ) { /* fixme: search for new signatures */ cdk_kbnode_release( chk ); return 0; } if( hd->buf ) { cdk_stream_close( hd->buf ); hd->buf = NULL; } rc = _cdk_stream_append( hd->name, &out ); if( rc ) return rc; for( node = knode; node; node = node->next ) { if( node->pkt->pkttype == CDK_PKT_RING_TRUST ) continue; /* No uniformed syntax for this packet */ rc = cdk_pkt_write( out, node->pkt ); if( rc ) break; } if( !rc ) result[is_sk? 3 : 2] = 1; cdk_stream_close( out ); if( !hd->no_cache ) cdk_keydb_idx_rebuild( hd ); return rc; }
cdk_error_t cdk_keydb_export( cdk_keydb_hd_t hd, cdk_stream_t out, cdk_strlist_t remusr ) { cdk_kbnode_t knode, node; cdk_strlist_t r; int old_ctb = 0; int rc = 0; for( r = remusr; r; r = r->next ) { rc = cdk_keydb_search_start( hd, CDK_DBSEARCH_AUTO, r->d ); if( !rc ) rc = cdk_keydb_search( hd, &knode ); if( rc ) break; for( node = knode; node; node = node->next ) { /* those packets are not intended for the real wolrd */ if( node->pkt->pkttype == CDK_PKT_RING_TRUST ) continue; /* we never export local signed signatures */ if( node->pkt->pkttype == CDK_PKT_SIGNATURE && !node->pkt->pkt.signature->flags.exportable ) continue; /* filter out invalid signatures */ if( node->pkt->pkttype == CDK_PKT_SIGNATURE && !KEY_CAN_SIGN (node->pkt->pkt.signature->pubkey_algo) ) continue; if( node->pkt->pkttype == CDK_PKT_PUBLIC_KEY && node->pkt->pkt.public_key->version == 3 ) old_ctb = 1; node->pkt->old_ctb = old_ctb; rc = cdk_pkt_write( out, node->pkt ); if( rc ) break; } cdk_kbnode_release( knode ); knode = NULL; } return rc; }
/** * 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_kbnode_write_to_mem: * @node: the key node * @buf: the buffer to store the node data * @r_nbytes: the new length of the buffer. * * Tries to write the contents of the key node to the buffer @buf and * return the length of it in @r_nbytes. If buf is zero, only the * length of the node is calculated and returned in @r_nbytes. * Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used. **/ cdk_error_t cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes) { cdk_kbnode_t n; cdk_stream_t s; cdk_error_t rc; size_t len; if (!node || !r_nbytes) { gnutls_assert (); return CDK_Inv_Value; } rc = cdk_stream_tmp_new (&s); if (rc) { gnutls_assert (); return rc; } for (n = node; n; n = n->next) { /* Skip all packets which cannot occur in a key composition. */ if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY && n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY && n->pkt->pkttype != CDK_PKT_SECRET_KEY && n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY && n->pkt->pkttype != CDK_PKT_SIGNATURE && n->pkt->pkttype != CDK_PKT_USER_ID && n->pkt->pkttype != CDK_PKT_ATTRIBUTE) continue; rc = cdk_pkt_write (s, n->pkt); if (rc) { cdk_stream_close (s); gnutls_assert (); return rc; } } cdk_stream_seek (s, 0); len = cdk_stream_get_length (s); if (!buf) { *r_nbytes = len; /* Only return the length of the buffer */ cdk_stream_close (s); return 0; } if (*r_nbytes < len) { *r_nbytes = len; rc = CDK_Too_Short; } if (!rc) *r_nbytes = cdk_stream_read (s, buf, len); else gnutls_assert (); cdk_stream_close (s); return rc; }