X-Git-Url: https://the.earth.li/gitweb/?p=onak.git;a=blobdiff_plain;f=decodekey.c;h=0ff0625929849713a2597bf36769f009badab90c;hp=9ae614d0cfe6e1701fbf1dd47ea4273c6883c82d;hb=adc800dbc424a1e246dd4a82a0c2e88eeda25531;hpb=0f4971d043c38bae1bfb95201622a1405110f899 diff --git a/decodekey.c b/decodekey.c index 9ae614d..0ff0625 100644 --- a/decodekey.c +++ b/decodekey.c @@ -1,15 +1,22 @@ /* * decodekey.c - Routines to further decode an OpenPGP key. * - * Jonathan McDowell + * Copyright 2002-2008 Jonathan McDowell * - * Copyright 2002 Project Purple + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. * - * $Id: decodekey.c,v 1.2 2003/06/04 20:57:07 noodles Exp $ + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . */ #include -#include #include #include #include @@ -20,17 +27,23 @@ #include "keyid.h" #include "keystructs.h" #include "ll.h" +#include "openpgp.h" /* * parse_subpackets - Parse the subpackets of a Type 4 signature. * @data: The subpacket data. - * @keyid: A pointer to where we should return the keyid. + * @len: The amount of data available to read. + * @parselen: The amount of data that was actually parsed. + * @keyid: A pointer to where we should return the keyid. + * @creationtime: A pointer to where we should return the creation time. * * This function parses the subkey data of a Type 4 signature and fills * in the supplied variables. It also returns the length of the data - * processed. + * processed. If the value of any piece of data is not desired a NULL + * can be passed instead of a pointer to a storage area for that value. */ -int parse_subpackets(unsigned char *data, uint64_t *keyid) +onak_status_t parse_subpackets(unsigned char *data, size_t len, + size_t *parselen, uint64_t *keyid, time_t *creation) { int offset = 0; int length = 0; @@ -38,8 +51,20 @@ int parse_subpackets(unsigned char *data, uint64_t *keyid) assert(data != NULL); + /* Make sure we actually have the 2 byte length field */ + if (len < 2) { + return ONAK_E_INVALID_PKT; + } + length = (data[0] << 8) + data[1] + 2; + /* If the length is off the end of the data available, it's bogus */ + if (len < length) { + return ONAK_E_INVALID_PKT; + } + + *parselen = length; + offset = 2; while (offset < length) { packetlen = data[offset++]; @@ -49,84 +74,168 @@ int parse_subpackets(unsigned char *data, uint64_t *keyid) } else if (packetlen == 255) { packetlen = data[offset++]; packetlen <<= 8; - packetlen = data[offset++]; + packetlen |= data[offset++]; packetlen <<= 8; - packetlen = data[offset++]; + packetlen |= data[offset++]; packetlen <<= 8; - packetlen = data[offset++]; + packetlen |= data[offset++]; } - switch (data[offset]) { - case 2: + /* Check the supplied length is within the remaining data */ + if (packetlen == 0 || (packetlen + offset) > length) { + return ONAK_E_INVALID_PKT; + } + switch (data[offset] & 0x7F) { + case OPENPGP_SIGSUB_CREATION: /* - * Signature creation time. Might want to output this? + * Signature creation time. */ + if (creation != NULL) { + *creation = data[offset + packetlen - 4]; + *creation <<= 8; + *creation = data[offset + packetlen - 3]; + *creation <<= 8; + *creation = data[offset + packetlen - 2]; + *creation <<= 8; + *creation = data[offset + packetlen - 1]; + } break; - case 0x83: /* * Signature expiration time. Might want to output this? */ break; - case 16: - *keyid = data[offset+packetlen - 8]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 7]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 6]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 5]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 4]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 3]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 2]; - *keyid <<= 8; - *keyid += data[offset+packetlen - 1]; - break; - case 23: - /* - * Key server preferences. Including no-modify. - */ + case OPENPGP_SIGSUB_ISSUER: + if (keyid != NULL) { + *keyid = data[offset+packetlen - 8]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 7]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 6]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 5]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 4]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 3]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 2]; + *keyid <<= 8; + *keyid += data[offset+packetlen - 1]; + } break; - case 25: + case OPENPGP_SIGSUB_EXPIRY: + case OPENPGP_SIGSUB_EXPORTABLE: + case OPENPGP_SIGSUB_TRUSTSIG: + case OPENPGP_SIGSUB_REGEX: + case OPENPGP_SIGSUB_REVOCABLE: + case OPENPGP_SIGSUB_CAPABILITIES: + case OPENPGP_SIGSUB_KEYEXPIRY: + case OPENPGP_SIGSUB_ARR: + case OPENPGP_SIGSUB_PREFSYM: + case OPENPGP_SIGSUB_REVOCATION_KEY: + case OPENPGP_SIGSUB_ISSUER_UID: + case OPENPGP_SIGSUB_URL: + case OPENPGP_SIGSUB_ISSUER_FINGER: + case OPENPGP_SIGSUB_NOTATION: + case OPENPGP_SIGSUB_PREFHASH: + case OPENPGP_SIGSUB_PREFCOMPRESS: + case OPENPGP_SIGSUB_KEYSERVER: + case OPENPGP_SIGSUB_PREFKEYSERVER: + case OPENPGP_SIGSUB_PRIMARYUID: + case OPENPGP_SIGSUB_POLICYURI: + case OPENPGP_SIGSUB_KEYFLAGS: + case OPENPGP_SIGSUB_SIGNER_UID: + case OPENPGP_SIGSUB_REVOKE_REASON: + case OPENPGP_SIGSUB_FEATURES: + case OPENPGP_SIGSUB_SIGNATURE_TARGET: + case OPENPGP_SIGSUB_EMBEDDED_SIG: /* - * Primary UID. + * Various subpacket types we know about, but don't + * currently handle. Some are candidates for being + * supported if we add signature checking support. */ break; default: /* * We don't care about unrecognized packets unless bit - * 7 is set in which case we prefer an error than - * ignoring it. + * 7 is set in which case we log a major error. */ - assert(!(data[offset] & 0x80)); + if (data[offset] & 0x80) { + return ONAK_E_UNSUPPORTED_FEATURE; + } } offset += packetlen; } - return length; + return ONAK_E_OK; } /** - * keysigs - Return the sigs on a given OpenPGP signature list. - * @curll: The current linked list. Can be NULL to create a new list. - * @sigs: The signature list we want the sigs on. + * sig_info - Get info on a given OpenPGP signature packet + * @packet: The signature packet + * @keyid: A pointer for where to return the signature keyid + * @creation: A pointer for where to return the signature creation time * - * Returns a linked list of stats_key elements containing the sigs on the - * supplied OpenPGP packet list. + * Gets any info about a signature packet; parses the subpackets for a v4 + * key or pulls the data directly from v2/3. NULL can be passed for any + * values which aren't cared about. */ -struct ll *keysigs(struct ll *curll, - struct openpgp_packet_list *sigs) +onak_status_t sig_info(struct openpgp_packet *packet, uint64_t *keyid, + time_t *creation) { - uint64_t keyid = 0; - - while (sigs != NULL) { - keyid = sig_keyid(sigs->packet); - sigs = sigs->next; - curll = lladd(curll, createandaddtohash(keyid)); + size_t length = 0; + onak_status_t res; + + if (packet != NULL) { + switch (packet->data[0]) { + case 2: + case 3: + if (keyid != NULL) { + *keyid = packet->data[7]; + *keyid <<= 8; + *keyid += packet->data[8]; + *keyid <<= 8; + *keyid += packet->data[9]; + *keyid <<= 8; + *keyid += packet->data[10]; + *keyid <<= 8; + *keyid += packet->data[11]; + *keyid <<= 8; + *keyid += packet->data[12]; + *keyid <<= 8; + *keyid += packet->data[13]; + *keyid <<= 8; + *keyid += packet->data[14]; + } + if (creation != NULL) { + *creation = packet->data[3]; + *creation <<= 8; + *creation = packet->data[4]; + *creation <<= 8; + *creation = packet->data[5]; + *creation <<= 8; + *creation = packet->data[6]; + } + break; + case 4: + res = parse_subpackets(&packet->data[4], + packet->length - 4, + &length, keyid, creation); + if (res != ONAK_E_OK) { + return res; + } + res = parse_subpackets(&packet->data[length + 4], + packet->length - (4 + length), + &length, keyid, creation); + if (res != ONAK_E_OK) { + return res; + } + break; + default: + break; + } } - return curll; + return ONAK_E_OK; } /** @@ -137,47 +246,14 @@ struct ll *keysigs(struct ll *curll, */ uint64_t sig_keyid(struct openpgp_packet *packet) { - int length = 0; uint64_t keyid = 0; - - if (packet != NULL) { - keyid = 0; - switch (packet->data[0]) { - case 2: - case 3: - keyid = packet->data[7]; - keyid <<= 8; - keyid += packet->data[8]; - keyid <<= 8; - keyid += packet->data[9]; - keyid <<= 8; - keyid += packet->data[10]; - keyid <<= 8; - keyid += packet->data[11]; - keyid <<= 8; - keyid += packet->data[12]; - keyid <<= 8; - keyid += packet->data[13]; - keyid <<= 8; - keyid += packet->data[14]; - break; - case 4: - length = parse_subpackets(&packet->data[4], - &keyid); - parse_subpackets(&packet->data[length + 4], - &keyid); - /* - * Don't bother to look at the unsigned packets. - */ - break; - default: - break; - } - } + + sig_info(packet, &keyid, NULL); return keyid; } + /* * TODO: Abstract out; all our linked lists should be generic and then we can * llsize them. @@ -207,6 +283,10 @@ char **keyuids(struct openpgp_publickey *key, char **primary) char buf[1024]; char **uids = NULL; int count = 0; + + if (primary != NULL) { + *primary = NULL; + } if (key != NULL && key->uids != NULL) { uids = malloc((spsize(key->uids) + 1) * sizeof (char *)); @@ -214,7 +294,7 @@ char **keyuids(struct openpgp_publickey *key, char **primary) curuid = key->uids; while (curuid != NULL) { buf[0] = 0; - if (curuid->packet->tag == 13) { + if (curuid->packet->tag == OPENPGP_PACKET_UID) { snprintf(buf, 1023, "%.*s", (int) curuid->packet->length, curuid->packet->data); @@ -223,13 +303,41 @@ char **keyuids(struct openpgp_publickey *key, char **primary) curuid = curuid -> next; } uids[count] = NULL; - } - /* - * TODO: Parse subpackets for real primary ID (v4 keys) - */ - if (primary != NULL) { - *primary = uids[0]; + + /* + * TODO: Parse subpackets for real primary ID (v4 keys) + */ + if (primary != NULL) { + *primary = uids[0]; + } } return uids; } + +/** + * keysubkeys - Takes a key and returns an array of its subkey keyids. + * @key: The key to get the subkeys of. + * + * keysubkeys takes a public key structure and returns an array of the + * subkey keyids for that key. + */ +struct openpgp_fingerprint *keysubkeys(struct openpgp_publickey *key) +{ + struct openpgp_signedpacket_list *cursubkey = NULL; + struct openpgp_fingerprint *subkeys = NULL; + int count = 0; + + if (key != NULL && key->subkeys != NULL) { + subkeys = malloc((spsize(key->subkeys) + 1) * + sizeof (struct openpgp_fingerprint)); + cursubkey = key->subkeys; + while (cursubkey != NULL) { + get_fingerprint(cursubkey->packet, &subkeys[count++]); + cursubkey = cursubkey -> next; + } + subkeys[count].length = 0; + } + + return subkeys; +}