Browse Source

Added on_valid callback, itself called from key validation callback, for secure filtering purpose. Also enforced rfc4880 key packet sequencing

master
Edouard Tisserant 7 years ago
parent
commit
985448a132
5 changed files with 178 additions and 86 deletions
  1. +11
    -1
      dist/src/lib/keyring.c
  2. +10
    -0
      dist/src/lib/packet-parse.c
  3. +5
    -0
      dist/src/lib/packet.h
  4. +143
    -82
      dist/src/lib/validate.c
  5. +9
    -3
      dist/src/lib/validate.h

+ 11
- 1
dist/src/lib/keyring.c View File

@ -1029,6 +1029,15 @@ getkeybyfpr(pgp_io_t *io, const pgp_keyring_t *keyring,
}
return &keyring->keys[*from];
}
kfp = &keyring->keys[*from].encfingerprint;
if (kfp->length == length &&
memcmp(kfp->fingerprint, fpr, length) == 0) {
if (pubkey) {
*pubkey = &keyring->keys[*from].key.pubkey;
}
return &keyring->keys[*from];
}
}
return NULL;
}
@ -1308,7 +1317,7 @@ pgp_add_to_pubring(pgp_keyring_t *keyring, const pgp_pubkey_t *pubkey, pgp_conte
key->type = tag;
pgp_keyid(key->sigid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
pgp_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype);
key->key.pubkey = *pubkey;
(void) memcpy(&key->key.pubkey, pubkey, sizeof(key->key.pubkey));
/* WTF? key->key.pubkey.duration = duration; */
return 1;
case PGP_PTAG_CT_PUBLIC_SUBKEY:
@ -1316,6 +1325,7 @@ pgp_add_to_pubring(pgp_keyring_t *keyring, const pgp_pubkey_t *pubkey, pgp_conte
key = &keyring->keys[keyring->keyc - 1];
pgp_keyid(key->encid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
duration = key->key.pubkey.duration;
pgp_fingerprint(&key->encfingerprint, pubkey, keyring->hashtype);
(void) memcpy(&key->enckey, pubkey, sizeof(key->enckey));
key->enckey.duration = duration;
return 1;


+ 10
- 0
dist/src/lib/packet-parse.c View File

@ -1648,6 +1648,10 @@ parse_one_sig_subpacket(pgp_sig_t *sig,
sig->info.duration = pkt.u.ss_time;
sig->info.duration_set = 1;
}
if (pkt.tag == PGP_PTAG_SS_KEY_EXPIRY) {
sig->info.key_expiry = pkt.u.ss_time;
sig->info.key_expiry_set = 1;
}
break;
case PGP_PTAG_SS_TRUST:
@ -1695,12 +1699,18 @@ parse_one_sig_subpacket(pgp_sig_t *sig,
return 0;
}
pkt.u.ss_primary_userid = !!bools;
sig->info.primary_userid = pkt.u.ss_primary_userid;
break;
case PGP_PTAG_SS_KEY_FLAGS:
if (!read_data(&pkt.u.ss_key_flags, &subregion, stream)) {
return 0;
}
if(pkt.u.ss_key_flags.len > 0){
/* Only one byte is defined in rfc4880 for now */
sig->info.key_flags = pkt.u.ss_key_flags.contents[0];
sig->info.key_flags_set = 1;
}
break;
case PGP_PTAG_SS_KEYSERV_PREFS:


+ 5
- 0
dist/src/lib/packet.h View File

@ -618,6 +618,8 @@ typedef struct pgp_sig_info_t {
pgp_sig_type_t type; /* signature type value */
time_t birthtime; /* creation time of the signature */
time_t duration; /* number of seconds it's valid for */
time_t key_expiry; /* number of seconds key is valid for */
uint8_t key_flags;
uint8_t signer_id[PGP_KEY_ID_SIZE]; /* Eight-octet key ID
* of signer */
pgp_pubkey_alg_t key_alg; /* public key algorithm number */
@ -633,6 +635,9 @@ typedef struct pgp_sig_info_t {
unsigned birthtime_set:1;
unsigned signer_id_set:1;
unsigned duration_set:1;
unsigned key_expiry_set:1;
unsigned key_flags_set:1;
unsigned primary_userid:1;
} pgp_sig_info_t;
/** Struct used when parsing a signature */


+ 143
- 82
dist/src/lib/validate.c View File

@ -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);


+ 9
- 3
dist/src/lib/validate.h View File

@ -56,13 +56,15 @@ typedef struct {
} validate_reader_t;
/** Struct used with the validate_key_cb callback */
typedef struct {
typedef struct validate_key_cb_s{
pgp_pubkey_t pubkey;
pgp_pubkey_t subkey;
pgp_seckey_t seckey;
uint8_t pubkeyid[PGP_KEY_ID_SIZE];
enum {
ATTRIBUTE = 1,
ID
ID,
SUBKEY,
PRIMARYKEY
} last_seen;
uint8_t *userid;
pgp_data_t userattr;
@ -72,6 +74,10 @@ typedef struct {
pgp_validation_t *result;
pgp_cb_ret_t(*getpassphrase) (const pgp_packet_t *,
pgp_cbdata_t *);
pgp_cb_ret_t(*on_valid) (
struct validate_key_cb_s *,
const pgp_sig_t *);
void *on_valid_args;
} validate_key_cb_t;
/** Struct use with the validate_data_cb callback */


Loading…
Cancel
Save