pgprngpars.c

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

C
857
字号
		return PGPERR_SIG_MPI;
	l += 16 + (t+7)/8;
	if (alg == PGP_PKALG_RSA ||
	alg == PGP_PKALG_RSA_ENC || alg == PGP_PKALG_RSA_SIG) {
		if (len != l)
			return len < l ? PGPERR_SIG_SHORT : PGPERR_SIG_LONG;
	}
	return 0;
}

/*
* Version of ringSigParse for the signature packet formats being designed
* for a future version. We do not fully handle them here, but we do a
* basic parse on the sigs and we make sure there are no critical fields
* that we can't handle.
*
* Sig layout:
*
* Offset,Length Meaning
*	0		1	Version byte (=4)
*	1		1	Signature type (included in hash) (nested flag)
*	2		1	PK algorithm (1 = RSA) (included in hash)
*	3		1	Hash algorithm (1 = MD5) (included in hash)
*	4		2	Length of extra material included in hash (=y)
*	6		y	Subpackets (hashed)
* 6+y		2	Length of extra material not included in hash (=z)
* 8+y		z	Subpackets (unhashed)
*=====
*remainder not present on sig headers
*=====
*	8+y+z	2	 First 2 bytes of message digest (16-bit checksum)
*	10+y+z	2+w	MPI of PK-signed integer
*	12+y+z+w
*
*/
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)
{
	unsigned	l;				/* extralen */
	unsigned	t;				/* bit count of first MPI */
	size_t		mpiend;			/* byte position past first MPI */
	byte		alg;			/* pk alg for sig */

	if (version)
		*version = buf[0];
	if (len < 8)
		return PGPERR_SIG_SHORT;
	if (type)
		*type = buf[1];
	alg = buf[2];
	if (pkalg)
		*pkalg = alg;
	if (hashalg)
		*hashalg = buf[3];
	l = (unsigned)buf[4]<<8 | buf[5];	 	/* extra material */
	if (extralen)
		*extralen = l;
	if (len < 6+l+2)
		return PGPERR_SIG_SHORT;
	l += (unsigned)buf[l+6]<<8 | buf[l+7];	/* unhashed extra material */
	if (len < 8+l+2+2)
		return PGPERR_SIG_SHORT;
	t = (unsigned)buf[l+10] << 8 | buf[l+11]; /* first MPI size in bits */
	mpiend = 8+l+2+2+(t+7)/8;
	if (len < mpiend)
		return PGPERR_SIG_SHORT;
	if (t && buf[l+12] >> ((t-1)&7) != 1)
		return PGPERR_SIG_MPI;
	/* Special checking for RSA sigs */
	if (alg == PGP_PKALG_RSA ||
	alg == PGP_PKALG_RSA_ENC || alg == PGP_PKALG_RSA_SIG) {
		if (len > mpiend)
			return PGPERR_SIG_LONG;
	}
			
	/* Now parse subpackets, pick up keyid, timestamp and validity info */
	return ringSigParseSubpackets (buf+4, keyID, tstamp, validity);
}


/*
* Parse the "extra data" on the new-style signature packets.
*
* This is a chain of subpackets, with the following format:
* Offset,Length Meaning
*	0	x(1-2)	Subpacket length (=y)
*	x	1	 Subpacket type (with critical flag)
*	x+1	y-1	Subpacket data
*
* We are only parsing a few of the subpackets now, returning an error
* if we see any critical ones that we don't handle. Also, we require
* there to be a keyid subpacket at present or it is an error.
*
* There are two such chains, each preceded by a two-byte count. The
* first is hashed and the second is not.
*/
static int
ringSigParseSubpackets(byte const *buf, byte keyID[8],
	word32 *tstamp, word16 *validity)
{
	unsigned	len;			/* Length of chain of subpackets */
	unsigned	sublen;				/* Length of subpacket */
	int 		type,	 		 	/* Type of subpacket */
				prevtype;		 	/* Type of previous subpacket */
	int			critical;	 		 /* Critical flag on subpacket */
	int			found_keyid = 0;	/* True if found a keyid subpacket */
	int			hashed;				/* True if parsing hashed subpackets */
	word32		creationtime = 0;	/* Creation time from subpacket */
	word32		expirationtime = 0;	/* Expiration time from subpacket */

	hashed = 1;
	/* Loop twice, once with hashed = 1 and once with hashed = 0 */
	do {
		prevtype = 0;
		len = (unsigned)buf[0]<<8 | buf[1];
		buf += 2;
		while (len) {
			if (len < 2)
				return PGPERR_SIG_BADEXTRA;
			/* Subpacket length may be one or two bytes */
			sublen = (unsigned)buf[0];
			if (sublen < 0xc0) {
				/* sublen is the length */
				len -= 1;
				buf += 1;
			} else if ((sublen & 0xe0) == 0xc0) {
				sublen &= 0x3f;
				sublen = (sublen << 8) + (unsigned)buf[1] + 192;
				len -= 2;
				buf += 2;
			} else {
				/* Badly formatted */
				return PGPERR_SIG_BADEXTRA;
			}
			if (len < 1)
				return PGPERR_SIG_BADEXTRA;
			type = buf[0];
			critical = type & SIGSUBF_CRITICAL;
			type &= ~SIGSUBF_CRITICAL;
			buf += 1;
			len -= 1;
			sublen -= 1;
			if (len < sublen)
				return PGPERR_SIG_BADEXTRA;
			/* Illegal to have critical packets in unhashed region */
			if (critical && !hashed)
				return PGPERR_SIG_BADEXTRA;
			/* Packets in order of nondecreasing type */
			if (type < prevtype)
				return PGPERR_SIG_BADEXTRA;
			switch (type) {
			case SIGSUB_CREATION:
				if (sublen != 4)
					return PGPERR_SIG_BADEXTRA;
				if (!tstamp && critical)
					return PGPERR_SIG_BADEXTRA;
				creationtime = (word32)((unsigned)buf[0]<<8|buf[1]) << 16 |
									((unsigned)buf[2]<<8|buf[3]);
				if (tstamp)
					*tstamp = creationtime;
				break;
			case SIGSUB_EXPIRATION:
				if (sublen != 4 || !hashed)
					return PGPERR_SIG_BADEXTRA;
				/* We don't really handle this yet */
				if (critical)
					return PGPERR_SIG_BADEXTRA;
				expirationtime = (word32)((unsigned)buf[0]<<8|buf[1]) << 16 |
									((unsigned)buf[2]<<8|buf[3]);
				/* Store it as days. expirationtime is really valid period */
				if (validity && creationtime)
					*validity = (word16) (expirationtime / (24 * 3600));
				break;
			case SIGSUB_KEYID:
				/* Allow longer than 8 byte keyid's unless critical */
				if (sublen < 8)
					return PGPERR_SIG_BADEXTRA;
				if (critical && (!keyID || sublen != 8))
					return PGPERR_SIG_BADEXTRA;
				if (keyID)
					memcpy(keyID, buf + sublen - 8, 8);
				found_keyid = 1;
				break;
			default:
				if (critical)
					return PGPERR_SIG_BADEXTRA;
			}
			buf += sublen;
			len -= sublen;
			prevtype = type;
		}
		hashed = !hashed;
	} while (!hashed);			/* Two iterations */
	/* For now we must have a keyid. We can live without a creation time. */
	if (keyID && !found_keyid)
		return PGPERR_SIG_BADEXTRA;
	return PGPERR_OK;
}

/*
* Look for a particular subpacket associated with the given signature.
* See comments above for format of subpackets. Return pointer to the
* subpacket data, after the length and type field.
* Critical and hashed tell whether the packet was critical and/or in the
* hashed region, respectively (return parameters).
* We don't need to do consistency checking, it's already been checked.
* (I couldn't resist doing a bit anyway.)
*
* nth should be set to 0 to find first match, 1 for second, etc.
* Returns number of matches total in *pmatches.
*/
byte const *
ringSigFindSubpacket(byte const *buf, int subpacktype, unsigned nth,
	size_t *plen, int *pcritical, int *phashed, word32 *pcreation,
	unsigned *pmatches)
{
	unsigned	len;			/* Length of chain of subpackets */
	unsigned	sublen;				/* Length of subpacket */
	int 		type;	 		 	/* Type of subpacket */
	int			critical;	 		 /* Critical flag on subpacket */
	int			hashed;				/* True if parsing hashed subpackets */
	unsigned	nmatches = 0;		 /* Number of matches so far */
	byte const *pbuf = NULL;		/* Return buffer pointer */

	if (buf[0] < PGPVERSION_3)
		return NULL;

	subpacktype &= ~SIGSUBF_CRITICAL;
	buf += 4;
	hashed = 1;
	/* Loop twice, once with hashed = 1 and once with hashed = 0 */
	do {
		len = (unsigned)buf[0]<<8 | buf[1];
		buf += 2;
		while (len) {
			if (len < 2)
				return NULL;
			/* Subpacket length may be one or two bytes */
			sublen = (unsigned)buf[0];
			if (sublen < 0xc0) {
				/* sublen is the length */
				len -= 1;
				buf += 1;
			} else if ((sublen & 0xe0) == 0xc0) {
				sublen &= 0x3f;
				sublen = (sublen << 8) + (unsigned)buf[1] + 192;
				len -= 2;
				buf += 2;
			} else {
				/* Badly formatted */
				return NULL;
			}
			if (len < 1)
				return NULL;
			type = buf[0];
			critical = type & SIGSUBF_CRITICAL;
			type &= ~SIGSUBF_CRITICAL;
			buf += 1;
			len -= 1;
			sublen -= 1;

			if (type == subpacktype) {
				/* Match! */
				if (nmatches == nth) {
					if (pcritical)
						*pcritical = critical;
					if (phashed)
						*phashed = hashed;
			if (plen)
						*plen = sublen;
					pbuf = buf;
				}
				nmatches += 1;
			}

			if (type == SIGSUB_CREATION) {
				pgpAssert (sublen == 4);
				if (pcreation) {
					*pcreation = (word32)((unsigned)buf[0]<<8|buf[1]) << 16 |
						((unsigned)buf[2]<<8|buf[3]);
				}
			}

			/* Skip to next packet */
			buf += sublen;
			len -= sublen;
		}
		hashed = !hashed;
	} while (!hashed);			/* Two iterations */
	if (pmatches)
		*pmatches = nmatches;
	return pbuf;				/* Will be non-null if we matched nth */
}


/*
* Return the length of the prefix of a secret key which is a public key,
* or 0 if it can't be determined. A key's prefix is:
* 0 1 - Version
* 1 4 - Creation time
* 5 2 - Vaidity period (days)
* 7 1 - Algorithm
* 8 ? - Algorithm-specific parameters
*/
size_t
ringKeyParsePublicPrefix(byte const *buf, size_t len)
{
	size_t size;
	unsigned vsize;

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

	/* Check version bytes */
	if (!KNOWN_PGP_VERSION(buf[0]) || len < 6+vsize)
		return 0;
	size = pgpPubKeyPrefixSize(buf[5+vsize], buf+6+vsize, len-6-vsize);
	if (size)
		size += 6+vsize;
	return size;
}

int
ringKeyParseFingerprint16(byte const *kbuf, size_t klen, byte *fingerprint)
{
	struct PgpHash const *h;
	struct PgpHashContext *hc;
byte const *buf;
unsigned len;

	h = pgpHashByNumber (PGP_HASH_MD5);
	if (!h)
		return PGPERR_BAD_HASHNUM;
	hc = pgpHashCreate(h);
	if (!hc)
		return PGPERR_NOMEM;

buf = ringKeyParseModulus(kbuf, klen, &len);
if (!buf)
		goto error;
pgpHashUpdate(hc, buf, len);

buf = ringKeyParseExponent(kbuf, klen, &len);
if (!buf)
		goto error;
pgpHashUpdate(hc, buf, len);

	buf = pgpHashFinal(hc);
	memcpy(fingerprint, buf, h->hashsize);
	pgpHashDestroy(hc);

	return h->hashsize;	/* Success */
error:
	pgpHashDestroy(hc);
	memset(fingerprint, 0, 16);
	return ringKeyParse(kbuf, klen, NULL, NULL, NULL, NULL, NULL, 0);
	/* Pkalg KeyID KeybitTstampValid */
}


/* Return the size which will be used to create the key prefix buffer */
size_t
ringKeyBufferLength(struct PgpKeySpec const *ks, byte pkalg)
{
	(void)pkalg;
	if (pgpKeySpecVersion(ks)==PGPVERSION_3)
		return 6;	/* version(1)+timestamp(4)+pkalg(1) */
	else
		return 8;	/* version(1)+timestamp(4)+validity(2)+pkalg(1) */
}

/* Create the key prefix buffer */
int
ringKeyToBuffer(byte *buf, struct PgpKeySpec const *ks, byte pkalg)
{
	word32 tstamp;
	word16 validity;
	unsigned vsize;


	buf[0] = pgpKeySpecVersion(ks);
	if (buf[0] == PGPVERSION_3) {
		vsize = 0;
	} else {
		vsize = 2;
	}
	tstamp = pgpKeySpecCreation(ks);
	buf[1] = (byte)(tstamp>>24);
	buf[2] = (byte)(tstamp>>16);
	buf[3] = (byte)(tstamp>> 8);
	buf[4] = (byte)(tstamp );
	if (vsize) {
		validity = pgpKeySpecValidity(ks);
		buf[5] = (byte)(validity>>8);
		buf[6] = (byte)(validity );
	}
	buf[5+vsize] = pkalg;
	return 0;
}

/* Return the size of a prefix buffer for a secret key */
size_t
ringSecBufferLength(struct PgpKeySpec const *ks, byte pkalg)
{
	return ringKeyBufferLength(ks, pkalg);
}

/* Create the prefix buffer for a secret key */
int
ringSecToBuffer(byte *buf, struct PgpKeySpec const *ks, byte pkalg)
{
	return ringKeyToBuffer(buf, ks, pkalg);
}


/*
* Local Variables:
* tab-width: 4
* End:
* vi: ts=4 sw=4
* vim: si
*/

⌨️ 快捷键说明

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