|
|
|
@ -236,8 +236,7 @@ pgp_cb_ret_t
|
|
|
|
|
pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
{
|
|
|
|
|
const pgp_contents_t *content = &pkt->u;
|
|
|
|
|
const pgp_key_t *signer;
|
|
|
|
|
validate_key_cb_t *key;
|
|
|
|
|
validate_key_cb_t *vdata;
|
|
|
|
|
pgp_pubkey_t *sigkey;
|
|
|
|
|
pgp_error_t **errors;
|
|
|
|
|
pgp_io_t *io;
|
|
|
|
@ -249,119 +248,174 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
(void) fprintf(io->errs, "%s\n",
|
|
|
|
|
pgp_show_packet_tag(pkt->tag));
|
|
|
|
|
}
|
|
|
|
|
key = pgp_callback_arg(cbinfo);
|
|
|
|
|
vdata = pgp_callback_arg(cbinfo);
|
|
|
|
|
errors = pgp_callback_errors(cbinfo);
|
|
|
|
|
switch (pkt->tag) {
|
|
|
|
|
case PGP_PTAG_CT_PUBLIC_KEY:
|
|
|
|
|
if (key->pubkey.version != 0) {
|
|
|
|
|
if (vdata->pubkey.version != 0) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: version bad\n");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
key->pubkey = content->pubkey;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
vdata->pubkey = content->pubkey;
|
|
|
|
|
pgp_keyid(vdata->pubkeyid, PGP_KEY_ID_SIZE,
|
|
|
|
|
&vdata->pubkey, PGP_HASH_SHA1); /* TODO v3*/
|
|
|
|
|
|
|
|
|
|
case PGP_PTAG_CT_PUBLIC_SUBKEY:
|
|
|
|
|
if (key->subkey.version) {
|
|
|
|
|
pgp_pubkey_free(&key->subkey);
|
|
|
|
|
}
|
|
|
|
|
key->subkey = content->pubkey;
|
|
|
|
|
vdata->last_seen = PRIMARYKEY;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
|
|
|
|
|
case PGP_PTAG_CT_SECRET_KEY:
|
|
|
|
|
key->seckey = content->seckey;
|
|
|
|
|
key->pubkey = key->seckey.pubkey;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
case PGP_PTAG_CT_PUBLIC_SUBKEY:
|
|
|
|
|
if(vdata->last_seen == ID ||
|
|
|
|
|
vdata->last_seen == ATTRIBUTE){
|
|
|
|
|
if (vdata->subkey.version) {
|
|
|
|
|
pgp_pubkey_free(&vdata->subkey);
|
|
|
|
|
}
|
|
|
|
|
vdata->subkey = content->pubkey;
|
|
|
|
|
vdata->last_seen = SUBKEY;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: unexpected subkey\n");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PGP_PTAG_CT_USER_ID:
|
|
|
|
|
if (key->userid) {
|
|
|
|
|
pgp_userid_free(&key->userid);
|
|
|
|
|
}
|
|
|
|
|
key->userid = content->userid;
|
|
|
|
|
key->last_seen = ID;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
if(vdata->last_seen == PRIMARYKEY ||
|
|
|
|
|
vdata->last_seen == ATTRIBUTE ||
|
|
|
|
|
vdata->last_seen == ID){
|
|
|
|
|
if (vdata->userid) {
|
|
|
|
|
pgp_userid_free(&vdata->userid);
|
|
|
|
|
}
|
|
|
|
|
vdata->userid = content->userid;
|
|
|
|
|
vdata->last_seen = ID;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: unexpected userID\n");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PGP_PTAG_CT_USER_ATTR:
|
|
|
|
|
if (content->userattr.len == 0) {
|
|
|
|
|
if(vdata->last_seen == PRIMARYKEY ||
|
|
|
|
|
vdata->last_seen == ATTRIBUTE ||
|
|
|
|
|
vdata->last_seen == ID){
|
|
|
|
|
if (content->userattr.len == 0) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: user attribute length 0");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
(void) fprintf(io->outs, "user attribute, length=%d\n",
|
|
|
|
|
(int) content->userattr.len);
|
|
|
|
|
if (vdata->userattr.len) {
|
|
|
|
|
pgp_data_free(&vdata->userattr);
|
|
|
|
|
}
|
|
|
|
|
vdata->userattr = content->userattr;
|
|
|
|
|
vdata->last_seen = ATTRIBUTE;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
}else{
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: user attribute length 0");
|
|
|
|
|
"pgp_validate_key_cb: unexpected user attribute\n");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
(void) fprintf(io->outs, "user attribute, length=%d\n",
|
|
|
|
|
(int) content->userattr.len);
|
|
|
|
|
if (key->userattr.len) {
|
|
|
|
|
pgp_data_free(&key->userattr);
|
|
|
|
|
}
|
|
|
|
|
key->userattr = content->userattr;
|
|
|
|
|
key->last_seen = ATTRIBUTE;
|
|
|
|
|
return PGP_KEEP_MEMORY;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
case PGP_PTAG_CT_SIGNATURE: /* V3 sigs */
|
|
|
|
|
case PGP_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */
|
|
|
|
|
from = 0;
|
|
|
|
|
signer = pgp_getkeybyid(io, key->keyring,
|
|
|
|
|
content->sig.info.signer_id,
|
|
|
|
|
&from, &sigkey);
|
|
|
|
|
if (!signer) {
|
|
|
|
|
if (!add_sig_to_list(&content->sig.info,
|
|
|
|
|
&key->result->unknown_sigs,
|
|
|
|
|
&key->result->unknownc)) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: user attribute length 0");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (sigkey == &signer->enckey) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"WARNING: signature made with encryption key\n");
|
|
|
|
|
}
|
|
|
|
|
sigkey = NULL;
|
|
|
|
|
if(vdata->keyring){
|
|
|
|
|
const pgp_key_t *signer;
|
|
|
|
|
signer = pgp_getkeybyid(io, vdata->keyring,
|
|
|
|
|
content->sig.info.signer_id,
|
|
|
|
|
&from, &sigkey);
|
|
|
|
|
if (signer && sigkey == &signer->enckey) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"WARNING: signature made with encryption key\n");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* If no keyring is given to check against
|
|
|
|
|
* then this is a self certification check.
|
|
|
|
|
* First ensure signature issuer ID is pubkey's ID*/
|
|
|
|
|
if(memcmp(vdata->pubkeyid,
|
|
|
|
|
content->sig.info.signer_id,
|
|
|
|
|
PGP_KEY_ID_SIZE) == 0){
|
|
|
|
|
sigkey = &vdata->pubkey;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!sigkey) {
|
|
|
|
|
if (!add_sig_to_list(&content->sig.info,
|
|
|
|
|
&vdata->result->unknown_sigs,
|
|
|
|
|
&vdata->result->unknownc)) {
|
|
|
|
|
(void) fprintf(io->errs,
|
|
|
|
|
"pgp_validate_key_cb: out of memory");
|
|
|
|
|
return PGP_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch (content->sig.info.type) {
|
|
|
|
|
case PGP_CERT_GENERIC:
|
|
|
|
|
case PGP_CERT_PERSONA:
|
|
|
|
|
case PGP_CERT_CASUAL:
|
|
|
|
|
case PGP_CERT_POSITIVE:
|
|
|
|
|
case PGP_SIG_REV_CERT:
|
|
|
|
|
valid = (key->last_seen == ID) ?
|
|
|
|
|
pgp_check_useridcert_sig(&key->pubkey,
|
|
|
|
|
key->userid,
|
|
|
|
|
if(vdata->last_seen == ID){
|
|
|
|
|
valid = pgp_check_useridcert_sig(&vdata->pubkey,
|
|
|
|
|
vdata->userid,
|
|
|
|
|
&content->sig,
|
|
|
|
|
pgp_get_pubkey(signer),
|
|
|
|
|
key->reader->key->packets[
|
|
|
|
|
key->reader->packet].raw) :
|
|
|
|
|
pgp_check_userattrcert_sig(&key->pubkey,
|
|
|
|
|
&key->userattr,
|
|
|
|
|
sigkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
/* XXX TODO if valid : pgp_update_key_userid
|
|
|
|
|
* - id expiration
|
|
|
|
|
* - revocation
|
|
|
|
|
* - is primary
|
|
|
|
|
* */
|
|
|
|
|
} else if(vdata->last_seen == ATTRIBUTE) {
|
|
|
|
|
valid = pgp_check_userattrcert_sig(&vdata->pubkey,
|
|
|
|
|
&vdata->userattr,
|
|
|
|
|
&content->sig,
|
|
|
|
|
pgp_get_pubkey(signer),
|
|
|
|
|
key->reader->key->packets[
|
|
|
|
|
key->reader->packet].raw);
|
|
|
|
|
sigkey,
|
|
|
|
|
vdata->reader->key->packets[
|
|
|
|
|
vdata->reader->packet].raw);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PGP_SIG_SUBKEY:
|
|
|
|
|
/*
|
|
|
|
|
* XXX: we should also check that the signer is the
|
|
|
|
|
* key we are validating, I think.
|
|
|
|
|
* we ensure that the signing key is the
|
|
|
|
|
* primary key we are validating, "vdata->pubkey".
|
|
|
|
|
*/
|
|
|
|
|
valid = pgp_check_subkey_sig(&key->pubkey,
|
|
|
|
|
&key->subkey,
|
|
|
|
|
&content->sig,
|
|
|
|
|
pgp_get_pubkey(signer),
|
|
|
|
|
key->reader->key->packets[
|
|
|
|
|
key->reader->packet].raw);
|
|
|
|
|
if(vdata->last_seen == SUBKEY &&
|
|
|
|
|
memcmp(vdata->pubkeyid,
|
|
|
|
|
content->sig.info.signer_id,
|
|
|
|
|
PGP_KEY_ID_SIZE) == 0 ){
|
|
|
|
|
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 */
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PGP_SIG_DIRECT:
|
|
|
|
|
valid = pgp_check_direct_sig(&key->pubkey,
|
|
|
|
|
&content->sig,
|
|
|
|
|
pgp_get_pubkey(signer),
|
|
|
|
|
key->reader->key->packets[
|
|
|
|
|
key->reader->packet].raw);
|
|
|
|
|
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 */
|
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
@ -377,17 +431,20 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
if (!add_sig_to_list(&content->sig.info,
|
|
|
|
|
&key->result->valid_sigs,
|
|
|
|
|
&key->result->validc)) {
|
|
|
|
|
&vdata->result->valid_sigs,
|
|
|
|
|
&vdata->result->validc)) {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
|
|
|
|
|
"Can't add good sig to list\n");
|
|
|
|
|
}
|
|
|
|
|
if(vdata->on_valid){
|
|
|
|
|
return vdata->on_valid(vdata,&content->sig);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
|
|
|
|
|
"Bad Sig");
|
|
|
|
|
if (!add_sig_to_list(&content->sig.info,
|
|
|
|
|
&key->result->invalid_sigs,
|
|
|
|
|
&key->result->invalidc)) {
|
|
|
|
|
&vdata->result->invalid_sigs,
|
|
|
|
|
&vdata->result->invalidc)) {
|
|
|
|
|
PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
|
|
|
|
|
"Can't add good sig to list\n");
|
|
|
|
|
}
|
|
|
|
@ -401,8 +458,8 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PGP_GET_PASSPHRASE:
|
|
|
|
|
if (key->getpassphrase) {
|
|
|
|
|
return key->getpassphrase(pkt, cbinfo);
|
|
|
|
|
if (vdata->getpassphrase) {
|
|
|
|
|
return vdata->getpassphrase(pkt, cbinfo);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -412,7 +469,7 @@ pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
|
|
|
|
|
printf("Got trust\n");
|
|
|
|
|
//hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
|
|
|
|
|
//hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
|
|
|
|
|
//printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
|
|
|
|
|
//printf("Trust level %d, amount %d\n", vdata->trust.level, vdata->trust.amount);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -686,7 +743,8 @@ pgp_validate_key_sigs(pgp_validation_t *result,
|
|
|
|
|
const pgp_key_t *key,
|
|
|
|
|
const pgp_keyring_t *keyring,
|
|
|
|
|
pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
|
|
|
|
|
pgp_cbdata_t *))
|
|
|
|
|
pgp_cbdata_t *)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
pgp_stream_t *stream;
|
|
|
|
|
validate_key_cb_t keysigs;
|
|
|
|
@ -701,6 +759,9 @@ pgp_validate_key_sigs(pgp_validation_t *result,
|
|
|
|
|
|
|
|
|
|
keysigs.keyring = keyring;
|
|
|
|
|
|
|
|
|
|
keysigs.on_valid = NULL;
|
|
|
|
|
keysigs.on_valid_args = NULL;
|
|
|
|
|
|
|
|
|
|
pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
|
|
|
|
|
stream->readinfo.accumulate = 1;
|
|
|
|
|
pgp_keydata_reader_set(stream, key);
|
|
|
|
|