pgprngpars.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 857 行 · 第 1/2 页

C
857
字号
/*
* pgpRngPars.c - parse structures from a keyring. Validates its
* inpout very carefully, for use by ringopen.c.
* Also includes routines to "unparse" and assemble
* keyringpackets.
*
* Copyright (C) 1994-1997 Pretty Good Privacy, Inc. All rights reserved.
*
* Written by Colin Plumb.
*
* $Id: pgpRngPars.c,v 1.6.2.4 1997/06/07 09:50:37 mhw Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>

#include "pgpDebug.h"
#include "pgpRngPars.h"
#include "pgpRngPriv.h"	/* For ringHashBuf, pgpFingerprint20HashBuf */
#include "pgpHash.h"
#include "pgpUsuals.h"
#include "pgpKeySpec.h"
#include "pgpErr.h"
#include "pgpPubKey.h"
#include "pgpPktByte.h"

#ifndef NULL
#define NULL 0
#endif


/*
* Read a key from the buffer and extract vital statistics.
* If the KeyID cannot be determined, a fake keyID with a 32-bit CRC
* stuffed in the middle is created. This is designed to assist
* matching of bad keys.
*
* A key is:
* 0 Version: 1 byte
* 1 Timestamp: 4 bytes
* 5 Validity: 2 bytes (skipped if version PGPVERSION_3)
* 7 Algorithm: 1 byte
* [Algorithm-specific portion]
* 8 Some MP number from which we can extract key ID: modulus, etc.
* [Other algorithm-specific fields]
* [with possible extra data if it's a secret key]
*
* If "secretf" is set, additional data is allowed at the end of the
* packet. If it is clear, additional data results in PGPERR_KEY_LONG.
* (The format of the extra data is not checked.)
*/
int
ringKeyParse(byte const *buf, size_t len, byte *pkalg, byte keyID[8],
	word16 *keybits, word32 *tstamp, word16 *validity, int secretf)
{
	unsigned mlen, elen;
	int err;
	unsigned vsize;

	/* Defaults in case of error */
	if (keyID)
		memset(keyID, 0, 8);
	if (keybits)
		*keybits = 0;
	if (tstamp)
		*tstamp = 0;
	if (validity)
		*validity = 0;
	if (pkalg)
		*pkalg = 0;

	if (len < 1)
		goto fakeid_short;

	if (!KNOWN_PGP_VERSION(buf[0])) {
		err = PGPERR_KEY_VERSION;
		goto fakeid;
	}
	/* PGPVERSION_3 keys have no validity field */
	if (buf[0] == PGPVERSION_3) {
		vsize = 0;
	} else {
		vsize = 2;
	}
	if (len < 5)
		goto fakeid_short;

	if (tstamp)
		*tstamp = (word32)((unsigned)buf[1] << 8 | buf[2]) << 16 |
			((unsigned)buf[3] << 8 | buf[4]);
	if (len < 5 + vsize)
		goto fakeid_short;
	if (validity && vsize)
		*validity = (unsigned)buf[5] << 8 | buf[6];
	if (len < 6 + vsize)
		goto fakeid_short;
	if (pkalg)
		*pkalg = buf[5 + vsize];
	if (len < 8 + vsize)
		goto fakeid_short;

	/* Get bytes in modulus */
	mlen = (unsigned)buf[6 + vsize] << 8 | buf[7 + vsize];
	if (keybits)
		*keybits = (word16)mlen;

	if (mlen && len > 8 + vsize && buf[8 + vsize] >> ((mlen-1)&7) != 1) {
		err = PGPERR_KEY_MODMPI;
		goto fakeid;
	}
	mlen = (mlen + 7) / 8;
	if (len < 8 + vsize + mlen)
		goto fakeid_short;

	if (len < 10 + vsize + mlen)
		return PGPERR_KEY_SHORT;

	if (buf[5 + vsize] == PGP_PKALG_RSA ||
	buf[5 + vsize] == PGP_PKALG_RSA_ENC ||
		buf[5 + vsize] == PGP_PKALG_RSA_SIG) {
		/* Read keyID */
		if (keyID) {
			memcpy(keyID, buf + 8 + vsize + mlen - 8, 8);
			if (mlen < 8)
				memset(keyID, 0, 8 - mlen);
		}
		/* Sanity checks on the exponent */
		elen = (unsigned)buf[8+vsize+mlen] << 8 | buf[9+vsize+mlen];
		if (elen && len > 10+vsize+mlen &&
				buf[10+vsize+mlen] >> ((elen-1)&7) != 1)
			return PGPERR_KEY_EXPMPI;
		elen = (elen + 7) / 8;

		if (len < 10+vsize+mlen+elen)
			return PGPERR_KEY_SHORT;
		if ((buf[8 + vsize + mlen-1] & 1) == 0)
			return PGPERR_KEY_MODEVEN;
		if ((buf[10+vsize+mlen+elen-1] & 1) == 0)
			return PGPERR_KEY_EXPEVEN;
		if (len > 10+vsize+mlen+elen && !secretf)
			return PGPERR_KEY_LONG;
	} else if (keyID) {
			/*
		* Non-RSA keys use newer keyID algorithm.
		* Low bits of fingerprint20 hash of key, but we can't
		* use that function directly as key is not assembled yet.
				*/
		byte hash[20];
		if (secretf)
			len = ringKeyParsePublicPrefix(buf, len);
		err = pgpFingerprint20HashBuf(buf, len, hash);
		if (err < 0)
			return err;
		pgpAssert (err == sizeof(hash));
		memcpy(keyID, hash+sizeof(hash)-8, 8);
	}

	return 0;

fakeid_short:
	err = PGPERR_KEY_SHORT;
fakeid:
		/*
	* We couldn't read a KeyID. Create a bogus one.
	* The low 32 bits are 0 (which really stands out in a
	* keyring listing and is impossible in the usual case),
	* but the high 32 bits are a CRC of the packet, to reduce
	* reports of keyID collisions.
			*/
	if (keyID) {
		word32 fake = ringHashBuf(buf, len);
		keyID[0] = (byte)(fake >> 24);
		keyID[1] = (byte)(fake >> 16);
		keyID[2] = (byte)(fake >> 8);
		keyID[3] = (byte)fake;
	}
	return err;
}

/* Extract the modulus from a key and return it (buffer & length) */
byte const *
ringKeyParseModulus(byte const *buf, size_t len, unsigned *lenp)
{
	unsigned msize;
	unsigned vsize;

	*lenp = 0;
	if (buf[0] == PGPVERSION_3) {
		vsize = 0;
	} else {
		vsize = 2;
	}

	if (len < 8+vsize || !KNOWN_PGP_VERSION(buf[0]) ||
	(buf[5+vsize] != PGP_PKALG_RSA &&
	buf[5+vsize] != PGP_PKALG_RSA_ENC &&
		buf[5+vsize] != PGP_PKALG_RSA_SIG))
		return 0;

	/* Get bytes in modulus */
	msize = (unsigned)buf[6+vsize] << 8 | buf[7+vsize];
	msize = (msize + 7) / 8;

	*lenp = msize;
	return buf + 8 + vsize;
}

/* Extract the exponent from a key and return it (buffer & length) */
byte const *
ringKeyParseExponent(byte const *buf, size_t len, unsigned *lenp)
{
	unsigned size;
	unsigned vsize;

	*lenp = 0;

	if (buf[0] == PGPVERSION_3) {
		vsize = 0;
	} else {
		vsize = 2;
	}

	if (len < 10+vsize || !KNOWN_PGP_VERSION(buf[0]) ||
	(buf[5+vsize] != PGP_PKALG_RSA &&
	buf[5+vsize] != PGP_PKALG_RSA_ENC &&
		buf[5+vsize] != PGP_PKALG_RSA_SIG))
		return NULL;

	/* Get bytes in modulus */
	size = (unsigned)buf[6+vsize] << 8 | buf[7+vsize];
	size = (size + 7) / 8;

	if (len < 10 + vsize + size)
		return NULL;

	/* Skip modulus */
	size += 8 + vsize;
	buf += size;
	len -= size;

	/* Get bytes in exponent */
	size = (unsigned)buf[0] << 8 | buf[1];
	size = (size + 7) / 8;

	if (len < 2 + size)
		return NULL;

	*lenp = size;
	return buf + 2;
}

/*
* Return a pointer to the "extra" part of the signature packet, the part
* which gets hashed. We use two different conventions, one for PGP 2.6
* and earlier, and the other for the later version packets. The latter
* includes the whole packet up through the variable part.
*
* buf		 Signature buffer pointer
* len		 buf length in bytes
* lenp		 Return pointer to length of extra buffer
*/
byte const *
ringSigParseExtra(byte const *buf, size_t len, unsigned *lenp)
{
	*lenp = 0;					/* In case of error */
	if (buf[0] == PGPVERSION_3) {
		unsigned extralen;
		if (len < 6)			/* Too short */
			return NULL;
		extralen = (unsigned)buf[4]<<8 | buf[5];
		if (len < 6 + extralen)
			return NULL;		/* Too short */
		*lenp = 6 + extralen;
		return buf;
	} else {
		/* Format from version 2.6 and earlier */
		if (len < 2 || !KNOWN_PGP_VERSION(buf[0]) || len < 2u + buf[1])
			return NULL;	/* Too short or bad version */
		*lenp = buf[1];
		return buf+2;
	}
}

/* Extract the RSA integer from a sig and return it (buffer & length) */
byte const *
ringSigParseInteger(byte const *buf, size_t len, unsigned *lenp)
{
	unsigned size;

	*lenp = 0;

	if (len < 2 || !KNOWN_PGP_VERSION(buf[0]))
		return NULL;	/* Too short or bad version */
	if (len < 16u + buf[1])
		return NULL;	/* Too short */
	/* Skip forward to PK algorithm */
	len -= 10 + buf[1];
	buf += 10 + buf[1];
	if (buf[0] != PGP_PKALG_RSA &&
	buf[0] != PGP_PKALG_RSA_ENC && buf[0] != PGP_PKALG_RSA_SIG)
		return NULL;	/* Not RSA */

	/* Get bytes in modulus */
	size = (unsigned)buf[4] << 8 | buf[5];
	size = (size + 7) / 8;

	if (len < 6 + size)
		return NULL;

	*lenp = size;
	return buf + 6;
}

/* Forward reference */
static int
ringSigParse3(byte const *buf, size_t len, byte *pkalg, byte keyID[8],
	word32 *tstamp, word16 *validity, byte *type, byte *hashalg,
	size_t *extralen, byte *version);
static int
ringSigParseSubpackets(byte const *buf, byte keyID[8],
	word32 *tstamp, word16 *validity);


/*
* Read a signature from the file, positioned just after the header.
* "len" is the length of the signature packet. Leaves the file
* pointed after the length.
*
* A signature is:
* 0 Version: 1 byte
* 1 Length of following material: 1 byte (must be 5!)
* 2 Signature type: 1 byte
* 3 Timestamp: 4 bytes
* 7 KeyID: 8 bytes
* 15 Public-key algorithm: 1 byte
* 16 Hash algorithm: 1 byte
* 17 First 2 bytes of hash: 2 bytes
* 19 MPI of signature (header)
* 21 MPI of signature (data)
*
* This reads up to the keyID (15 bytes) into a buffer,
* then sets up the various fields.
*/
int
ringSigParse(byte const *buf, size_t len, byte *pkalg, byte keyID[8],
	word32 *tstamp, word16 *validity, byte *type, byte *hashalg,
	size_t *extralen, byte *version)
{
	unsigned l;	/* extralen */
	unsigned t;
	byte alg;

	/* Default settings in case of error */
	if (pkalg)
		*pkalg = 0;
	if (keyID)
		memset(keyID, 0, 8);
	if (tstamp)
		*tstamp = 0;
	if (validity)
		*validity = 0;
	if (type)
		*type = 255;
	if (hashalg)
		*hashalg = 255;
	if (extralen)
		*extralen = 0;
	if (version)
		*version = 0;

	if (len < 1)
		return PGPERR_SIG_SHORT;
	/* Forward compatibility */
	if (buf[0] == PGPVERSION_3) {
		return ringSigParse3(buf, len, pkalg, keyID, tstamp, validity, type,
							hashalg, extralen, version);
	}
	if (version)
		*version = buf[0];
	if (!KNOWN_PGP_VERSION(buf[0]))
		return PGPERR_SIG_VERSION;
	if (len < 2)
		return PGPERR_SIG_SHORT;
	l = buf[1];
	if (extralen)
		*extralen = l;
	if (l >= 1) {
		if (len < 3)
			return PGPERR_SIG_SHORT;
		if (type)
			*type = buf[2];
		if (l >= 5 && tstamp) {
			if (len < 7)
				return PGPERR_SIG_SHORT;
			*tstamp = (word32)((unsigned)buf[3]<<8|buf[4]) << 16 |
			((unsigned)buf[5]<<8|buf[6]);
		}
		if (l >= 7 && validity) {
			if (len < 9)
				return PGPERR_SIG_SHORT;
			*tstamp = (word16)buf[7]<<8 | buf[8];
		}
	}
	if (!extralen && l != 5)
		return PGPERR_SIG_EXTRALEN;
	if (len < l+10)
		return PGPERR_SIG_SHORT;
	if (keyID)
		memcpy(keyID, buf + 7, 8);
	if (len < l+11)
		return PGPERR_SIG_SHORT;
	alg = buf[l+10];
	if (pkalg)
		*pkalg = alg;
#if 0
	if (buf[l+10] != PGP_PKALG_RSA &&
	buf[l+10] != PGP_PKALG_RSA_ENC && buf[l+10] != PGP_PKALG_RSA_SIG)
			 return PGPERR_SIG_PKALG;
#endif
		if (len < l+12)
			 return PGPERR_SIG_SHORT;
		if (hashalg)
			 *hashalg = buf[l+11];
		if (len < l+16)
			 return PGPERR_SIG_SHORT;
		t = (unsigned)buf[l+14] << 8 | buf[l+15];
	if (t && len > l+16 && buf[l+16] >> ((t-1)&7) != 1)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?