diff --git a/dist/src/lib/keyring.c b/dist/src/lib/keyring.c index 57f1b7d..b7d988e 100644 --- a/dist/src/lib/keyring.c +++ b/dist/src/lib/keyring.c @@ -134,7 +134,13 @@ pgp_key_free(pgp_key_t *keydata) FREE_ARRAY(keydata, packet); - /* XXX uidsigs revokes ? */ + for (n = 0; n < keydata->uidsigc; ++n) { + /* TODO + pgp_uidsig_free(&keydata->uidsigs[n]); + */ + } + + FREE_ARRAY(keydata, uidsig); if (keydata->type == PGP_PTAG_CT_PUBLIC_KEY) { pgp_pubkey_free(&keydata->key.pubkey); @@ -142,6 +148,13 @@ pgp_key_free(pgp_key_t *keydata) pgp_seckey_free(&keydata->key.seckey); } + /* TODO enckey sigkey seckey subkeys attributes directsig uidrevokes*/ + + if(keydata->revocation.reason){ + free(keydata->revocation.reason); + keydata->revocation.reason = NULL; + } + } /** @@ -473,8 +486,8 @@ pgp_is_key_supported(const pgp_key_t *key) \param src Source User ID \note If dst already has a userid, it will be freed. */ -static uint8_t * -copy_userid(uint8_t **dst, const uint8_t *src) +uint8_t * +pgp_copy_userid(uint8_t **dst, const uint8_t *src) { size_t len; @@ -483,7 +496,7 @@ copy_userid(uint8_t **dst, const uint8_t *src) free(*dst); } if ((*dst = calloc(1, len + 1)) == NULL) { - (void) fprintf(stderr, "copy_userid: bad alloc\n"); + (void) fprintf(stderr, "pgp_copy_userid: bad alloc\n"); } else { (void) memcpy(*dst, src, len); } @@ -530,7 +543,7 @@ pgp_add_userid(pgp_key_t *key, const uint8_t *userid) uidp = &key->uids[key->uidc++]; *uidp = NULL; /* now copy it */ - return copy_userid(uidp, userid); + return pgp_copy_userid(uidp, userid); } void print_packet_hex(const pgp_subpacket_t *pkt); diff --git a/dist/src/lib/keyring.h b/dist/src/lib/keyring.h index 39dbf8a..bce8be0 100644 --- a/dist/src/lib/keyring.h +++ b/dist/src/lib/keyring.h @@ -173,5 +173,5 @@ int pgp_add_to_secring(pgp_keyring_t *, const pgp_seckey_t *); int pgp_append_keyring(pgp_keyring_t *, pgp_keyring_t *); pgp_subpacket_t * pgp_copy_packet(pgp_subpacket_t *, const pgp_subpacket_t *); - +uint8_t * pgp_copy_userid(uint8_t **dst, const uint8_t *src); #endif /* KEYRING_H_ */ diff --git a/dist/src/lib/packet.h b/dist/src/lib/packet.h index a45e4c3..c999298 100644 --- a/dist/src/lib/packet.h +++ b/dist/src/lib/packet.h @@ -953,34 +953,72 @@ typedef struct pgp_revoke_t { uint32_t uid; /* index in uid array */ uint8_t code; /* revocation code */ char *reason; /* c'mon, spill the beans */ + pgp_subpacket_t *packet; } pgp_revoke_t; -/** signature subpackets */ +/** userid signature subpackets */ typedef struct pgp_uidsig_t { uint32_t uid; /* index in userid array in key */ - pgp_sig_info_t siginfo; /* trust signature */ + pgp_sig_info_t siginfo; uint8_t trustlevel; /* level of trust */ uint8_t trustamount; /* amount of trust */ - pgp_subpacket_t *packet; + uint8_t revoked; /* sigs revokes uid */ + pgp_subpacket_t packet; } pgp_uidsig_t; +/** subkey signature subpackets */ +typedef struct pgp_subkeysig_t { + uint32_t subkey; /* index of subkey in array */ + pgp_sig_info_t siginfo; + uint8_t revoked; /* sigs revokes subkey */ + pgp_subpacket_t packet; +} pgp_subkeysig_t; + +typedef struct pgp_subkey_t { + pgp_keydata_key_t key; /* pubkey/seckey data */ + uint8_t id[PGP_KEY_ID_SIZE]; +} pgp_subkey_t; + +typedef struct pgp_directsig_t { + pgp_sig_info_t siginfo; + pgp_subpacket_t packet; +} pgp_directsig_t; + /* describes a user's key */ struct pgp_key_t { - DYNARRAY(uint8_t *, uid); /* array of user ids */ + pgp_content_enum type; /* type of key */ + pgp_keydata_key_t key; /* pubkey/seckey data */ + /* TODO remove */ DYNARRAY(pgp_subpacket_t, packet); /* array of raw subpackets */ - DYNARRAY(pgp_uidsig_t, uidsig); /* array of signature subkeys */ + + DYNARRAY(uint8_t *, uid); /* array of user ids */ + DYNARRAY(pgp_uidsig_t, uidsig); /* array of signature for user ids */ + /* TODO remove */ + uint32_t uid0; /* primary uid index in uids array */ + + /* TODO user attributes */ + + /* TODO remove */ DYNARRAY(pgp_revoke_t, revoke); /* array of signature revocations */ - pgp_content_enum type; /* type of key */ - pgp_keydata_key_t key; /* pubkey/seckey data */ + + DYNARRAY(pgp_subkey_t, subkey); /* array of subkeys */ + DYNARRAY(pgp_subkeysig_t, subkeysig); /* array of sigs for subkeys */ + pgp_pubkey_t sigkey; /* signature key */ uint8_t sigid[PGP_KEY_ID_SIZE]; pgp_fingerprint_t sigfingerprint; /* pgp signature fingerprint */ + pgp_pubkey_t enckey; /* encryption key */ uint8_t encid[PGP_KEY_ID_SIZE]; pgp_fingerprint_t encfingerprint; /* pgp encryption id fingerprint */ - uint32_t uid0; /* primary uid index in uids array */ + + DYNARRAY(pgp_directsig_t, directsig); /* direct signatures */ + uint8_t revoked; /* key has been revoked */ + pgp_sig_info_t revokeinfo; /* trust signature */ + pgp_subpacket_t revokepacket; + /* TODO remove */ pgp_revoke_t revocation; /* revocation reason */ }; diff --git a/dist/src/lib/validate.c b/dist/src/lib/validate.c index 5bf992a..04dc34c 100644 --- a/dist/src/lib/validate.c +++ b/dist/src/lib/validate.c @@ -376,6 +376,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo) } break; + case PGP_SIG_REV_SUBKEY: case PGP_SIG_SUBKEY: /* * we ensure that the signing key is the @@ -392,6 +393,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo) } break; + case PGP_SIG_REV_KEY: case PGP_SIG_DIRECT: if(vdata->last_seen == PRIMARYKEY){ valid = pgp_check_direct_sig(&vdata->pubkey, @@ -400,12 +402,17 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo) } break; + if(vdata->last_seen == PRIMARYKEY){ + /* XXX TODO + valid = pgp_check_keyrev_sig(&vdata->pubkey, + &content->sig, + sigkey); + */ + } + break; + case PGP_SIG_STANDALONE: case PGP_SIG_PRIMARY: - case PGP_SIG_REV_KEY: - /* TODO */ - case PGP_SIG_REV_SUBKEY: - /* TODO */ case PGP_SIG_TIMESTAMP: case PGP_SIG_3RD_PARTY: PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, @@ -485,6 +492,18 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo) return PGP_RELEASE_MEMORY; } +static void validate_key_cb_free (validate_key_cb_t *vdata){ + + pgp_pubkey_free(&vdata->pubkey); + if (vdata->subkey.version) { + pgp_pubkey_free(&vdata->subkey); + } + pgp_userid_free(&vdata->userid); + pgp_data_free(&vdata->userattr); + pgp_subpacket_free(&vdata->last_pkt); + pgp_free_sig_info(&vdata->valid_sig_info); +} + pgp_cb_ret_t validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo) { @@ -753,14 +772,14 @@ static pgp_cb_ret_t key_filter_cb ( validate_key_cb_t *vdata, const pgp_subpacket_t *sigpkt) { + pgp_key_t *key; key_filter_cb_t *filter = vdata->on_valid_args; if(vdata->not_commited){ printf("New key ************************************** \n"); - /*hexdump(stdout, "signer ID", vdata->valid_sig_info.signer_id, - sizeof(vdata->valid_sig_info.signer_id));*/ hexdump(stdout, "pubkey ID", vdata->pubkeyid, sizeof(vdata->pubkeyid)); + /* TODO also ensure secret keys */ if((filter->key = pgp_ensure_pubkey(filter->destring, &vdata->pubkey, vdata->pubkeyid))==NULL){ @@ -768,45 +787,132 @@ static pgp_cb_ret_t key_filter_cb ( } } + key = filter->key; + if(key == NULL) + return PGP_FINISHED; + switch(vdata->last_seen){ - case ATTRIBUTE: - printf("ATTRIBUTE\n"); - break; - case ID: - printf("ID %s\n", vdata->userid); - /* XXX TODO add/update userid - * - id expiration - * - revocation - * - is primary - * */ - break; - case SUBKEY: - printf("SUBKEY\n"); - { - uint8_t subkeyid[PGP_KEY_ID_SIZE]; - pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, - &vdata->subkey, PGP_HASH_SHA1); - - hexdump(stdout, "subkey ID", subkeyid, - sizeof(subkeyid)); - /* XXX TODO add/update subkey - * with expiration and flags from sig info - if (memcmp(key->encid, "\0\0\0\0\0\0\0\0", 8) == 0) { - pgp_pubkey_dup(&key->enckey, pubkey); - (void) memcpy(&key->encid, pubkeyid, sizeof(PGP_KEY_ID_SIZE)); - (void) memcpy(&key->encfingerprint, &key->sigfingerprint, - sizeof(key->encfingerprint)); - * */ - } - break; - case PRIMARYKEY: - printf("PRIMARYKEY\n"); - /* XXX TODO direct key signature pgp_update_key - * with expiration and flags from sig info */ - break; - default: - printf("no_last_seen\n"); - break; + case PRIMARYKEY: + /* If this is a primary key revocation */ + if(vdata->valid_sig_info.type == PGP_SIG_REV_KEY){ + printf("PRIMARYKEY REVOKE\n"); + /* Mark key. This cannot be reset, revocation isn't undoable */ + key->revoked = 1; + /* Store revocation details */ + /* TODO store only if new revocation made later than current + * or systematically fail, since only one revocation + * should be allowed according rfc4880 */ + copy_sig_info(&key->revokeinfo, + &vdata->valid_sig_info); + pgp_copy_packet(&key->revokepacket, sigpkt); + + /* Direct key signature. Stack them unconditionally */ + }else{ + printf("PRIMARYKEY DIRECT KEY\n"); + pgp_directsig_t *directsigp; + EXPAND_ARRAY(key, directsig); + directsigp = &key->directsigs[key->directsigc++]; + copy_sig_info(&directsigp->siginfo, + &vdata->valid_sig_info); + pgp_copy_packet(&directsigp->packet, sigpkt); + } + break; + case ID: { + unsigned idx = 0; + uint8_t **uidp; + pgp_uidsig_t *uidsig; + + printf("ID %s\n", vdata->userid); + + /* Try to find identical userID */ + uidp = key->uids; + for (idx = 0 ; idx < key->uidc; idx++, uidp++) { + if (strcmp((char *)*uidp, (char *)vdata->userid) == 0) { + break; + } + } + /* Add a new one if none found */ + if(idx==key->uidc){ + EXPAND_ARRAY(key, uid); + uidp = &key->uids[key->uidc++]; + *uidp = NULL; + pgp_copy_userid(uidp, vdata->userid); + } + + /* Add uid sig info, pointing to that uid */ + EXPAND_ARRAY(key, uidsig); + uidsig = &key->uidsigs[key->uidsigc++]; + uidsig->uid = idx; + + /* if sig packet is revocation mark uidsig */ + if(vdata->valid_sig_info.type == PGP_SIG_REV_CERT){ + uidsig->revoked = 1; + printf("ID %s REVOKED\n", vdata->userid); + } + + /* store sig info and packet */ + copy_sig_info(&uidsig->siginfo, + &vdata->valid_sig_info); + pgp_copy_packet(&uidsig->packet, sigpkt); + + break; + } + case ATTRIBUTE: + printf("ATTRIBUTE -- IGNORED\n"); + /* TODO */ + break; + case SUBKEY:{ + unsigned idx = 0; + pgp_subkey_t *subkeyp; + pgp_subkeysig_t *subkeysig; + uint8_t subkeyid[PGP_KEY_ID_SIZE]; + + pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, + &vdata->subkey, PGP_HASH_SHA1); + + printf("SUBKEY\n"); + hexdump(stdout, "subkey ID", subkeyid, + sizeof(subkeyid)); + + /* Try to find identical ID */ + subkeyp = key->subkeys; + for (idx = 0 ; idx < key->subkeyc; idx++, subkeyp++) { + if(memcmp(subkeyid, subkeyp->id, + PGP_KEY_ID_SIZE) == 0 ){ + break; + } + } + /* Add a new one if none found */ + if(idx==key->subkeyc){ + EXPAND_ARRAY(key, subkey); + subkeyp = &key->subkeys[key->subkeyc++]; + /* copy subkey material */ + /* TODO also accept secret subkeys */ + pgp_pubkey_dup(&subkeyp->key.pubkey, &vdata->subkey); + /* copy subkeyID */ + memcpy(subkeyp->id, subkeyid, PGP_KEY_ID_SIZE); + } + + /* Add subkey sig info, pointing to that subkey */ + EXPAND_ARRAY(key, subkeysig); + subkeysig = &key->subkeysigs[key->subkeysigc++]; + subkeysig->subkey = idx; + + if(vdata->valid_sig_info.type == PGP_SIG_REV_CERT){ + subkeysig->revoked = 1; + } + + /* store sig info and packet */ + copy_sig_info(&subkeysig->siginfo, + &vdata->valid_sig_info); + pgp_copy_packet(&subkeysig->packet, sigpkt); + + break; + } + + default: + printf("no_last_seen\n"); + break; } printtime(vdata->valid_sig_info.birthtime); return PGP_RELEASE_MEMORY; @@ -850,14 +956,7 @@ pgp_filter_keys_from_mem(pgp_io_t *io, res = pgp_parse(stream, !printerrors); - pgp_pubkey_free(&vdata.pubkey); - if (vdata.subkey.version) { - pgp_pubkey_free(&vdata.subkey); - } - pgp_userid_free(&vdata.userid); - pgp_data_free(&vdata.userattr); - pgp_subpacket_free(&vdata.last_pkt); - pgp_free_sig_info(&vdata.valid_sig_info); + validate_key_cb_free(&vdata); if (armour) { pgp_reader_pop_dearmour(stream); @@ -909,15 +1008,7 @@ pgp_validate_key_sigs(pgp_validation_t *result, pgp_parse(stream, !printerrors); - pgp_pubkey_free(&vdata.pubkey); - if (vdata.subkey.version) { - pgp_pubkey_free(&vdata.subkey); - } - pgp_userid_free(&vdata.userid); - pgp_data_free(&vdata.userattr); - pgp_subpacket_free(&vdata.last_pkt); - pgp_free_sig_info(&vdata.valid_sig_info); - + validate_key_cb_free(&vdata); pgp_stream_delete(stream);