|
|
|
@ -125,10 +125,15 @@ keydata_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **er
|
|
|
|
|
return (int)length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pgp_free_sig_info(pgp_sig_info_t *sig)
|
|
|
|
|
{
|
|
|
|
|
free(sig->v4_hashed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_sig_info(pgp_sig_info_t *sig)
|
|
|
|
|
{
|
|
|
|
|
free(sig->v4_hashed);
|
|
|
|
|
pgp_free_sig_info(sig);
|
|
|
|
|
free(sig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -250,6 +255,13 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
}
|
|
|
|
|
vdata = pgp_callback_arg(cbinfo);
|
|
|
|
|
errors = pgp_callback_errors(cbinfo);
|
|
|
|
|
|
|
|
|
|
/* forget packet post-processing requests if packet is not
|
|
|
|
|
* passed in call immediately following tag where it was requested
|
|
|
|
|
* Parser shouldn't allow this, though */
|
|
|
|
|
vdata->store_pkt &= pkt->tag == PGP_PARSER_PACKET_END;
|
|
|
|
|
vdata->sig_is_valid &= pkt->tag == PGP_PARSER_PACKET_END;
|
|
|
|
|
|
|
|
|
|
switch (pkt->tag) {
|
|
|
|
|
case PGP_PTAG_CT_PUBLIC_KEY:
|
|
|
|
|
if (vdata->pubkey.version != 0) {
|
|
|
|
@ -262,6 +274,8 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
&vdata->pubkey, PGP_HASH_SHA1); /* TODO v3*/
|
|
|
|
|
|
|
|
|
|
vdata->last_seen = PRIMARYKEY;
|
|
|
|
|
vdata->store_pkt = 1;
|
|
|
|
|
vdata->not_commited = 1;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
|
|
|
|
|
case PGP_PTAG_CT_PUBLIC_SUBKEY:
|
|
|
|
@ -272,6 +286,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
}
|
|
|
|
|
vdata->subkey = content->pubkey;
|
|
|
|
|
vdata->last_seen = SUBKEY;
|
|
|
|
|
vdata->store_pkt = 1;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
@ -288,6 +303,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
}
|
|
|
|
|
vdata->userid = content->userid;
|
|
|
|
|
vdata->last_seen = ID;
|
|
|
|
|
vdata->store_pkt = 1;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
@ -311,6 +327,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
}
|
|
|
|
|
vdata->userattr = content->userattr;
|
|
|
|
|
vdata->last_seen = ATTRIBUTE;
|
|
|
|
|
vdata->store_pkt = 1;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
@ -360,21 +377,12 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
valid = pgp_check_useridcert_sig(&vdata->pubkey,
|
|
|
|
|
vdata->userid,
|
|
|
|
|
&content->sig,
|
|
|
|
|
sigkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
/* XXX TODO if valid : pgp_update_key_userid
|
|
|
|
|
* - id expiration
|
|
|
|
|
* - revocation
|
|
|
|
|
* - is primary
|
|
|
|
|
* */
|
|
|
|
|
sigkey);
|
|
|
|
|
} else if(vdata->last_seen == ATTRIBUTE) {
|
|
|
|
|
valid = pgp_check_userattrcert_sig(&vdata->pubkey,
|
|
|
|
|
&vdata->userattr,
|
|
|
|
|
&content->sig,
|
|
|
|
|
sigkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
sigkey);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -390,11 +398,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
valid = pgp_check_subkey_sig(&vdata->pubkey,
|
|
|
|
|
&vdata->subkey,
|
|
|
|
|
&content->sig,
|
|
|
|
|
&vdata->pubkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
/* XXX TODO if valid : pgp_update_key_subkey
|
|
|
|
|
* with expiration and flags from sig info */
|
|
|
|
|
&vdata->pubkey);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -402,11 +406,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
if(vdata->last_seen == PRIMARYKEY){
|
|
|
|
|
valid = pgp_check_direct_sig(&vdata->pubkey,
|
|
|
|
|
&content->sig,
|
|
|
|
|
sigkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
/* XXX TODO if valid : pgp_update_key
|
|
|
|
|
* with expiration and flags from sig info */
|
|
|
|
|
sigkey);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -434,11 +434,11 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
&vdata->result->valid_sigs,
|
|
|
|
|
&vdata->result->validc)) {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
|
|
|
|
|
"Can't add good sig to list\n");
|
|
|
|
|
"Can't add valid sig to list\n");
|
|
|
|
|
}
|
|
|
|
|
if(vdata->on_valid){
|
|
|
|
|
return vdata->on_valid(vdata,&content->sig);
|
|
|
|
|
}
|
|
|
|
|
vdata->sig_is_valid = 1;
|
|
|
|
|
copy_sig_info(&vdata->valid_sig_info,
|
|
|
|
|
&content->sig.info);
|
|
|
|
|
} else {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
|
|
|
|
|
"Bad Sig");
|
|
|
|
@ -446,15 +446,31 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
&vdata->result->invalid_sigs,
|
|
|
|
|
&vdata->result->invalidc)) {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
|
|
|
|
|
"Can't add good sig to list\n");
|
|
|
|
|
"Can't add invalid sig to list\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ignore these */
|
|
|
|
|
case PGP_PARSER_PACKET_END:
|
|
|
|
|
/* Store packet so that on_valid callback still
|
|
|
|
|
* can access it once valid signture is parsed */
|
|
|
|
|
if(vdata->store_pkt){
|
|
|
|
|
pgp_copy_packet(&vdata->last_pkt, &content->packet);
|
|
|
|
|
vdata->store_pkt = 0;
|
|
|
|
|
}else if(vdata->sig_is_valid){
|
|
|
|
|
pgp_cb_ret_t ret = PGP_KEEP_MEMORY;
|
|
|
|
|
if(vdata->on_valid){
|
|
|
|
|
ret = vdata->on_valid(vdata, &content->packet);
|
|
|
|
|
}
|
|
|
|
|
vdata->sig_is_valid = 0;
|
|
|
|
|
vdata->not_commited = 0;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
|
|
|
|
|
/* ignore these */
|
|
|
|
|
case PGP_PARSER_PTAG:
|
|
|
|
|
case PGP_PTAG_CT_SIGNATURE_HEADER:
|
|
|
|
|
case PGP_PARSER_PACKET_END:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PGP_GET_PASSPHRASE:
|
|
|
|
@ -727,6 +743,118 @@ validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
|
|
|
|
|
return val->validc && !val->invalidc && !val->unknownc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void printtime(time_t t)
|
|
|
|
|
{
|
|
|
|
|
struct tm *tm;
|
|
|
|
|
|
|
|
|
|
tm = gmtime(&t);
|
|
|
|
|
(void) printf("%04d-%02d-%02d\n",
|
|
|
|
|
tm->tm_year + 1900,
|
|
|
|
|
tm->tm_mon + 1,
|
|
|
|
|
tm->tm_mday);
|
|
|
|
|
}
|
|
|
|
|
static pgp_cb_ret_t key_filter_cb (
|
|
|
|
|
validate_key_cb_t *vdata,
|
|
|
|
|
const pgp_subpacket_t *sigpkt)
|
|
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
printtime(vdata->valid_sig_info.birthtime);
|
|
|
|
|
return PGP_RELEASE_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
|
pgp_filter_keys_from_mem(pgp_io_t *io,
|
|
|
|
|
pgp_keyring_t *destring,
|
|
|
|
|
pgp_keyring_t *certring,
|
|
|
|
|
const unsigned armour,
|
|
|
|
|
pgp_memory_t *mem)
|
|
|
|
|
{
|
|
|
|
|
pgp_validation_t vresult;
|
|
|
|
|
pgp_stream_t *stream;
|
|
|
|
|
const unsigned noaccum = 0;
|
|
|
|
|
validate_key_cb_t vdata;
|
|
|
|
|
const int printerrors = 1;
|
|
|
|
|
unsigned res;
|
|
|
|
|
|
|
|
|
|
(void) memset(&vresult, 0x0, sizeof(vresult));
|
|
|
|
|
(void) memset(&vdata, 0x0, sizeof(vdata));
|
|
|
|
|
vdata.result = &vresult;
|
|
|
|
|
vdata.getpassphrase = NULL;
|
|
|
|
|
|
|
|
|
|
stream = pgp_new(sizeof(*stream));
|
|
|
|
|
pgp_parse_options(stream, PGP_PTAG_SS_ALL, PGP_PARSE_PARSED);
|
|
|
|
|
pgp_setup_memory_read(io, &stream, mem, &vdata, pgp_validate_key_cb,
|
|
|
|
|
noaccum);
|
|
|
|
|
if (armour) {
|
|
|
|
|
pgp_reader_push_dearmour(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vdata.keyring = certring;
|
|
|
|
|
|
|
|
|
|
vdata.on_valid = &key_filter_cb;
|
|
|
|
|
vdata.on_valid_args = NULL;
|
|
|
|
|
|
|
|
|
|
stream->readinfo.accumulate = 1;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (armour) {
|
|
|
|
|
pgp_reader_pop_dearmour(stream);
|
|
|
|
|
}
|
|
|
|
|
/* don't call teardown_memory_read because memory was passed in */
|
|
|
|
|
pgp_stream_delete(stream);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \ingroup HighLevel_Verify
|
|
|
|
|
* \brief Validate all signatures on a single key against the given keyring
|
|
|
|
@ -747,37 +875,37 @@ pgp_validate_key_sigs(pgp_validation_t *result,
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
pgp_stream_t *stream;
|
|
|
|
|
validate_key_cb_t keysigs;
|
|
|
|
|
validate_key_cb_t vdata;
|
|
|
|
|
const int printerrors = 1;
|
|
|
|
|
|
|
|
|
|
(void) memset(&keysigs, 0x0, sizeof(keysigs));
|
|
|
|
|
keysigs.result = result;
|
|
|
|
|
keysigs.getpassphrase = cb_get_passphrase;
|
|
|
|
|
(void) memset(&vdata, 0x0, sizeof(vdata));
|
|
|
|
|
vdata.result = result;
|
|
|
|
|
vdata.getpassphrase = cb_get_passphrase;
|
|
|
|
|
|
|
|
|
|
stream = pgp_new(sizeof(*stream));
|
|
|
|
|
/* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
|
|
|
|
|
|
|
|
|
|
keysigs.keyring = keyring;
|
|
|
|
|
|
|
|
|
|
keysigs.on_valid = NULL;
|
|
|
|
|
keysigs.on_valid_args = NULL;
|
|
|
|
|
vdata.keyring = keyring;
|
|
|
|
|
|
|
|
|
|
pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
|
|
|
|
|
pgp_set_callback(stream, pgp_validate_key_cb, &vdata);
|
|
|
|
|
stream->readinfo.accumulate = 1;
|
|
|
|
|
pgp_keydata_reader_set(stream, key);
|
|
|
|
|
|
|
|
|
|
/* Note: Coverity incorrectly reports an error that keysigs.reader */
|
|
|
|
|
/* Note: Coverity incorrectly reports an error that vdata.reader */
|
|
|
|
|
/* is never used. */
|
|
|
|
|
keysigs.reader = stream->readinfo.arg;
|
|
|
|
|
vdata.reader = stream->readinfo.arg;
|
|
|
|
|
|
|
|
|
|
pgp_parse(stream, !printerrors);
|
|
|
|
|
|
|
|
|
|
pgp_pubkey_free(&keysigs.pubkey);
|
|
|
|
|
if (keysigs.subkey.version) {
|
|
|
|
|
pgp_pubkey_free(&keysigs.subkey);
|
|
|
|
|
pgp_pubkey_free(&vdata.pubkey);
|
|
|
|
|
if (vdata.subkey.version) {
|
|
|
|
|
pgp_pubkey_free(&vdata.subkey);
|
|
|
|
|
}
|
|
|
|
|
pgp_userid_free(&keysigs.userid);
|
|
|
|
|
pgp_data_free(&keysigs.userattr);
|
|
|
|
|
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_stream_delete(stream);
|
|
|
|
|
|
|
|
|
|