Some signatures have been witnessed on the keyserver network where the
hashed data lengths reported exceed the size of the overall packet. It
is assumed these are the results of some corruption somewhere, so if
they're detected don't try to parse any further (and drop them if we're
doing signature checking).
/*
* parse_subpackets - Parse the subpackets of a Type 4 signature.
* @data: The subpacket data.
/*
* parse_subpackets - Parse the subpackets of a Type 4 signature.
* @data: The subpacket data.
+ * @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.
*
* @keyid: A pointer to where we should return the keyid.
* @creationtime: A pointer to where we should return the creation time.
*
* 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.
*/
* 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, time_t *creation)
+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;
{
int offset = 0;
int length = 0;
log_assert(data != NULL);
log_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;
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++];
offset = 2;
while (offset < length) {
packetlen = data[offset++];
* key or pulls the data directly from v2/3. NULL can be passed for any
* values which aren't cared about.
*/
* key or pulls the data directly from v2/3. NULL can be passed for any
* values which aren't cared about.
*/
-void sig_info(struct openpgp_packet *packet, uint64_t *keyid, time_t *creation)
+onak_status_t sig_info(struct openpgp_packet *packet, uint64_t *keyid,
+ time_t *creation)
+ size_t length = 0;
+ onak_status_t res;
+
if (packet != NULL) {
switch (packet->data[0]) {
case 2:
if (packet != NULL) {
switch (packet->data[0]) {
case 2:
- length = parse_subpackets(&packet->data[4],
- keyid, creation);
- parse_subpackets(&packet->data[length + 4],
- keyid, creation);
- /*
- * Don't bother to look at the unsigned packets.
- */
+ 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;
}
}
break;
default:
break;
}
}
#include <time.h>
#include "keystructs.h"
#include "ll.h"
#include <time.h>
#include "keystructs.h"
#include "ll.h"
/**
* keysigs - Return the sigs on a given OpenPGP signature packet list.
/**
* keysigs - Return the sigs on a given OpenPGP signature packet list.
* key or pulls the data directly from v2/3. NULL can be passed for any
* values which aren't cared about.
*/
* key or pulls the data directly from v2/3. NULL can be passed for any
* values which aren't cared about.
*/
-void sig_info(struct openpgp_packet *packet, uint64_t *keyid, time_t *creation);
+onak_status_t sig_info(struct openpgp_packet *packet, uint64_t *keyid,
+ time_t *creation);
/**
* sig_keyid - Return the keyid for a given OpenPGP signature packet.
/**
* sig_keyid - Return the keyid for a given OpenPGP signature packet.
/**
* parse_subpackets - Parse the subpackets of a Type 4 signature.
* @data: The subpacket data.
/**
* parse_subpackets - Parse the subpackets of a Type 4 signature.
* @data: The subpacket data.
+ * @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.
*
* @keyid: A pointer to where we should return the keyid.
* @creationtime: A pointer to where we should return the creation time.
*
* 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.
*/
* 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, time_t *creation);
+onak_status_t parse_subpackets(unsigned char *data, size_t len,
+ size_t *parselen, uint64_t *keyid, time_t *creation);
size_t hashlen[8];
int chunks, i;
uint64_t keyid;
size_t hashlen[8];
int chunks, i;
uint64_t keyid;
keyheader[0] = 0x99;
keyheader[1] = key->publickey->length >> 8;
keyheader[0] = 0x99;
keyheader[1] = key->publickey->length >> 8;
- len = parse_subpackets(&sig->data[4], &keyid, NULL);
+ res = parse_subpackets(&sig->data[4],
+ sig->length - 4, &len,
+ &keyid, NULL);
+ if (res != ONAK_E_OK) {
+ /* If it parses badly, reject it */
+ return 0;
+ }
if (keyid == 0 &&
/* No unhashed data */
sig->data[4 + len] == 0 &&
if (keyid == 0 &&
/* No unhashed data */
sig->data[4 + len] == 0 &&
hashdata[chunks] = sig->data;
hashlen[chunks] = siglen = (sig->data[4] << 8) +
sig->data[5] + 6;;
hashdata[chunks] = sig->data;
hashlen[chunks] = siglen = (sig->data[4] << 8) +
sig->data[5] + 6;;
+ if (siglen > sig->length) {
+ /* Signature data exceed packet length, bogus */
+ return 0;
+ }
chunks++;
v4trailer[0] = 4;
chunks++;
v4trailer[0] = 4;