static cdk_kbnode_t keydb_find_byusage( cdk_kbnode_t root, int req_usage, int is_pk ) { cdk_kbnode_t node; int pkttype = 0, req_type = 0; req_type = is_pk? CDK_PKT_PUBLIC_KEY : CDK_PKT_SECRET_KEY; if( !req_usage ) return cdk_kbnode_find( root, req_type ); node = cdk_kbnode_find( root, req_type ); if( node && !keydb_check_key( node->pkt ) ) return NULL; /* xxx: if there are more subkeys, use the one with the requested usage and the newest timestamp. */ for( node = root; node; node = node->next ) { pkttype = node->pkt->pkttype; if( is_pk && (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY || node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY) && keydb_check_key( node->pkt ) && (node->pkt->pkt.public_key->pubkey_usage & req_usage) ) return node; if( !is_pk && (node->pkt->pkttype == CDK_PKT_SECRET_KEY || node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY) && keydb_check_key( node->pkt ) && (node->pkt->pkt.secret_key->pk->pubkey_usage & req_usage) ) return node; } return NULL; }
/** * cdk_kbnode_find_packet: * @node: the key node * @pkttype: packet type * * Same as cdk_kbnode_find but it returns the packet instead of the node. **/ cdk_packet_t cdk_kbnode_find_packet (cdk_kbnode_t node, cdk_packet_type_t pkttype) { cdk_kbnode_t res; res = cdk_kbnode_find (node, pkttype); return res ? res->pkt : NULL; }
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; }
cdk_error_t cdk_keydb_get_keyblock( cdk_stream_t inp, cdk_kbnode_t * r_knode ) { cdk_packet_t pkt = NULL; cdk_kbnode_t knode = NULL, node = NULL; cdk_desig_revoker_t revkeys = NULL; u32 keyid[2], main_keyid[2]; int rc = 0, old_off; int key_seen = 0, got_key = 0; if( !inp || !r_knode ) return CDK_Inv_Value; memset( keyid, 0, sizeof keyid ); memset( main_keyid, 0, sizeof main_keyid ); while( 1 ) { pkt = cdk_calloc( 1, sizeof *pkt ); if( !pkt ) return CDK_Out_Of_Core; old_off = 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 || pkt->pkttype == CDK_PKT_SECRET_KEY || pkt->pkttype == CDK_PKT_SECRET_SUBKEY) { if (key_seen && (pkt->pkttype == CDK_PKT_PUBLIC_KEY || pkt->pkttype == CDK_PKT_SECRET_KEY) ) { cdk_stream_seek( inp, old_off ); break; } if( pkt->pkttype == CDK_PKT_PUBLIC_KEY || pkt->pkttype == CDK_PKT_SECRET_KEY ) { _cdk_pkt_get_keyid( pkt, main_keyid ); key_seen = 1; } else if( pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY || pkt->pkttype == CDK_PKT_SECRET_SUBKEY ) { if( pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) { pkt->pkt.public_key->main_keyid[0] = main_keyid[0]; pkt->pkt.public_key->main_keyid[1] = main_keyid[1]; } else { pkt->pkt.secret_key->main_keyid[0] = main_keyid[0]; pkt->pkt.secret_key->main_keyid[1] = main_keyid[1]; } } /* we save this for the signature */ _cdk_pkt_get_keyid( pkt, keyid ); got_key = 1; } else if( pkt->pkttype == CDK_PKT_USER_ID ) ; else if( pkt->pkttype == CDK_PKT_SIGNATURE ) { pkt->pkt.signature->key[0] = keyid[0]; pkt->pkt.signature->key[1] = keyid[1]; if( pkt->pkt.signature->sig_class == 0x1F && pkt->pkt.signature->revkeys ) revkeys = pkt->pkt.signature->revkeys; } node = cdk_kbnode_new( pkt ); if( !knode ) knode = node; else _cdk_kbnode_add( knode, node ); } if( got_key ) { keydb_merge_selfsig( knode, main_keyid ); rc = keydb_parse_allsigs( knode, NULL, 0 ); if( revkeys ) { node = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY ); if( node ) node->pkt->pkt.public_key->revkeys = revkeys; } } *r_knode = got_key ? knode : NULL; return rc; }
/*- * gnutls_openpgp_get_key - Retrieve a key from the keyring. * @key: the destination context to save the key. * @keyring: the datum struct that contains all keyring information. * @attr: The attribute (keyid, fingerprint, ...). * @by: What attribute is used. * * This function can be used to retrieve keys by different pattern * from a binary or a file keyring. -*/ int gnutls_openpgp_get_key (gnutls_datum_t * key, gnutls_openpgp_keyring_t keyring, key_attr_t by, opaque * pattern) { cdk_kbnode_t knode = NULL; unsigned long keyid[2]; unsigned char *buf; void *desc; size_t len; int rc = 0; cdk_keydb_search_t st; if (!key || !keyring || by == KEY_ATTR_NONE) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } memset (key, 0, sizeof *key); if (by == KEY_ATTR_SHORT_KEYID) { keyid[0] = _gnutls_read_uint32 (pattern); desc = keyid; } else if (by == KEY_ATTR_KEYID) { keyid[0] = _gnutls_read_uint32 (pattern); keyid[1] = _gnutls_read_uint32 (pattern + 4); desc = keyid; } else desc = pattern; rc = cdk_keydb_search_start (&st, keyring->db, by, desc); if (!rc) rc = cdk_keydb_search (st, keyring->db, &knode); cdk_keydb_search_release (st); if (rc) { rc = _gnutls_map_cdk_rc (rc); goto leave; } if (!cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY)) { rc = GNUTLS_E_OPENPGP_GETKEY_FAILED; goto leave; } /* We let the function allocate the buffer to avoid to call the function twice. */ rc = cdk_kbnode_write_to_mem_alloc (knode, &buf, &len); if (!rc) datum_append (key, buf, len); gnutls_free (buf); leave: cdk_kbnode_release (knode); return rc; }