/** * gnutls_openpgp_key_get_id - Gets the keyID * @key: the structure that contains the OpenPGP public key. * @keyid: the buffer to save the keyid. * * Returns the 64-bit keyID of the OpenPGP key. **/ int gnutls_openpgp_key_get_id (gnutls_openpgp_key_t key, unsigned char keyid[8]) { cdk_packet_t pkt; cdk_pkt_pubkey_t pk = NULL; uint32_t kid[2]; if (!key || !keyid) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; pk = pkt->pkt.public_key; cdk_pk_get_keyid (pk, kid); keyid[0] = kid[0] >> 24; keyid[1] = kid[0] >> 16; keyid[2] = kid[0] >> 8; keyid[3] = kid[0]; keyid[4] = kid[1] >> 24; keyid[5] = kid[1] >> 16; keyid[6] = kid[1] >> 8; keyid[7] = kid[1]; return 0; }
/* Return the key ID from the given packet. If this is not possible, 0 is returned */ u32 _cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid) { u32 lowbits; if (!pkt) return 0; switch (pkt->pkttype) { case CDK_PKT_PUBLIC_KEY: case CDK_PKT_PUBLIC_SUBKEY: lowbits = cdk_pk_get_keyid (pkt->pkt.public_key, keyid); break; case CDK_PKT_SECRET_KEY: case CDK_PKT_SECRET_SUBKEY: lowbits = cdk_sk_get_keyid (pkt->pkt.secret_key, keyid); break; case CDK_PKT_SIGNATURE: lowbits = cdk_sig_get_keyid (pkt->pkt.signature, keyid); break; default: lowbits = 0; break; } return lowbits; }
/* This functions builds an index of the keyring into a separate file with the name keyring.ext.idx. It contains the offset of all public- and public subkeys. The format of the file is: -------- 4 octets offset of the packet 8 octets keyid 20 octets fingerprint -------- We store the keyid and the fingerprint due to the fact we can't get the keyid from a v3 fingerprint directly. */ static int keydb_idx_build( const char * file ) { cdk_packet_t pkt; cdk_stream_t inp, out = NULL; byte buf[8], fpr[20]; char * fname; u32 keyid[2]; int rc, pos; if( !file ) return CDK_Inv_Value; pkt = cdk_calloc( 1, sizeof * pkt ); if( !pkt ) return CDK_Out_Of_Core; fname = keydb_idx_mkname( file ); if( !fname ) { rc = CDK_Out_Of_Core; goto leave; } rc = cdk_stream_open( file, &inp ); if( !rc ) rc = cdk_stream_create( fname, &out ); if( rc ) goto leave; while( !cdk_stream_eof( inp ) ) { pos = cdk_stream_tell( inp ); rc = cdk_pkt_read( inp, pkt ); if( rc ) break; if( pkt->pkttype == CDK_PKT_PUBLIC_KEY || pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) { _cdk_u32tobuf( pos, buf ); cdk_stream_write( out, buf, 4 ); cdk_pk_get_keyid( pkt->pkt.public_key, keyid ); _cdk_u32tobuf( keyid[0], buf ); _cdk_u32tobuf( keyid[1], buf + 4 ); cdk_stream_write( out, buf, 8 ); cdk_pk_get_fingerprint( pkt->pkt.public_key, fpr ); cdk_stream_write( out, fpr, 20 ); } cdk_pkt_free( pkt ); cdk_pkt_init( pkt ); } cdk_stream_close( out ); leave: cdk_stream_close( inp ); cdk_free( fname ); cdk_free( pkt ); return rc; }
/** * cdk_sk_get_keyid: * @sk: the secret key * @keyid: buffer to hold the key ID * * Calculate the key ID of the secret key, actually the public key. **/ u32 cdk_sk_get_keyid(cdk_pkt_seckey_t sk, u32 * keyid) { u32 lowbits = 0; if (sk && sk->pk) { lowbits = cdk_pk_get_keyid(sk->pk, keyid); sk->keyid[0] = sk->pk->keyid[0]; sk->keyid[1] = sk->pk->keyid[1]; } return lowbits; }
/** * 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; }
static int xml_add_key (gnutls_string * xmlkey, int ext, cdk_pkt_pubkey_t pk, int sub) { const char *algo, *s; char keyid[16], fpr[41], tmp[32]; uint8_t fingerpr[20]; unsigned int kid[2]; int i = 0, rc = 0; if (!xmlkey || !pk) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } s = sub ? " <SUBKEY>\n" : " <MAINKEY>\n"; _gnutls_string_append_str (xmlkey, s); cdk_pk_get_keyid (pk, kid); snprintf (keyid, 16, "%08lX%08lX", kid[0], kid[1]); rc = xml_add_tag (xmlkey, "KEYID", keyid); if (rc) return rc; cdk_pk_get_fingerprint (pk, fingerpr); for (i = 0; i < 20; i++) sprintf (fpr + 2 * i, "%02X", fingerpr[i]); fpr[40] = '\0'; rc = xml_add_tag (xmlkey, "FINGERPRINT", fpr); if (rc) return rc; if (is_DSA (pk->pubkey_algo)) algo = "DSA"; else if (is_RSA (pk->pubkey_algo)) algo = "RSA"; else if (is_ELG (pk->pubkey_algo)) algo = "ELG"; else algo = "???"; rc = xml_add_tag (xmlkey, "PKALGO", algo); if (rc) return rc; sprintf (tmp, "%d", cdk_pk_get_nbits (pk)); rc = xml_add_tag (xmlkey, "KEYLEN", tmp); if (rc) return rc; sprintf (tmp, "%lu", pk->timestamp); rc = xml_add_tag (xmlkey, "CREATED", tmp); if (rc) return rc; if (pk->expiredate > 0) { sprintf (tmp, "%lu", (unsigned long) pk->expiredate); rc = xml_add_tag (xmlkey, "EXPIREDATE", tmp); if (rc) return rc; } sprintf (tmp, "%d", pk->is_revoked); rc = xml_add_tag (xmlkey, "REVOKED", tmp); if (rc) return rc; if (ext) { rc = xml_add_key_mpi (xmlkey, pk); if (rc) return rc; } s = sub ? " </SUBKEY>\n" : " </MAINKEY>\n"; _gnutls_string_append_str (xmlkey, s); return 0; }
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; }
static int keydb_parse_allsigs( cdk_kbnode_t knode, cdk_keydb_hd_t hd, int check ) { cdk_kbnode_t node, kb; cdk_pkt_signature_t sig; cdk_pkt_pubkey_t pk; struct cdk_subpkt_s * s = NULL; u32 expiredate = 0, curtime = _cdk_timestamp (); u32 keyid[2]; int rc = 0; if( !knode ) return CDK_Inv_Value; if( check && !hd ) return CDK_Inv_Mode; kb = cdk_kbnode_find( knode, CDK_PKT_SECRET_KEY ); if( kb ) return 0; /* reset */ for( node = knode; node; node = node->next ) { if( node->pkt->pkttype == CDK_PKT_USER_ID ) node->pkt->pkt.user_id->is_revoked = 0; else if( node->pkt->pkttype == CDK_PKT_PUBLIC_KEY || node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) node->pkt->pkt.public_key->is_revoked = 0; } kb = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY ); if( !kb ) return CDK_Inv_Packet; cdk_pk_get_keyid( kb->pkt->pkt.public_key, keyid ); for( node = knode; node; node = node->next) { if( node->pkt->pkttype == CDK_PKT_SIGNATURE ) { sig = node->pkt->pkt.signature; /* Revocation certificates for primary keys */ if( sig->sig_class == 0x20 ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_KEY ); if( kb ) { kb->pkt->pkt.public_key->is_revoked = 1; if( check ) _cdk_pk_check_sig (hd, kb, node, NULL); } else return CDK_Error_No_Key; } /* Revocation certificates for subkeys */ else if( sig->sig_class == 0x28 ) { kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY); if( kb ) { kb->pkt->pkt.public_key->is_revoked = 1; if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Revocation certifcates for user ID's */ else if( sig->sig_class == 0x30 ) { if( sig->keyid[0] != keyid[0] || sig->keyid[1] != keyid[1] ) continue; /* revokes an earlier signature, no userID. */ kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_USER_ID); if( kb ) { kb->pkt->pkt.user_id->is_revoked = 1; if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Direct certificates for primary keys */ else if( sig->sig_class == 0x1F ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_KEY ); if( kb ) { pk = kb->pkt->pkt.public_key; pk->is_invalid = 0; s = cdk_subpkt_find( node->pkt->pkt.signature->hashed, CDK_SIGSUBPKT_KEY_EXPIRE ); if( s ) { expiredate = _cdk_buftou32( s->d ); pk->expiredate = pk->timestamp + expiredate; pk->has_expired = pk->expiredate > curtime? 0 : 1; } if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Direct certificates for subkeys */ else if( sig->sig_class == 0x18 ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_SUBKEY); if( kb ) { pk = kb->pkt->pkt.public_key; pk->is_invalid = 0; s = cdk_subpkt_find( node->pkt->pkt.signature->hashed, CDK_SIGSUBPKT_KEY_EXPIRE ); if( s ) { expiredate = _cdk_buftou32( s->d ); pk->expiredate = pk->timestamp + expiredate; pk->has_expired = pk->expiredate > curtime? 0 : 1; } if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } } } node = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY ); if( node && node->pkt->pkt.public_key->version == 3 ) { /* v3 public keys have no additonal signatures for the key directly. we say the key is valid when we have at least a self signature. */ pk = node->pkt->pkt.public_key; for( node = knode; node; node = node->next ) { if( is_selfsig( node, keyid ) ) { pk->is_invalid = 0; break; } } } if( node && (node->pkt->pkt.public_key->is_revoked || node->pkt->pkt.public_key->has_expired) ) { /* if the primary key has been revoked, mark all subkeys as invalid because without a primary key they are not useable */ for( node = knode; node; node = node->next ) { if( node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) node->pkt->pkt.public_key->is_invalid = 1; } } return rc; }