📄 pgprngpars.c
字号:
/*
* pgpRngPars.c - parse structures from a keyring. Validates its
* inpout very carefully, for use by ringopen.c.
* Also includes routines to "unparse" and assemble keyring packets.
*
* Written by Colin Plumb.
*
* $Id: pgpRngPars.c,v 1.48 1999/02/20 02:51:42 hal Exp $
*/
#include "pgpConfig.h"
#include <string.h>
#include "pgpDebug.h"
#include "pgpRngPars.h"
#include "pgpRngPriv.h" /* For ringHashBuf, pgpFingerprint20HashBuf */
#include "pgpHashPriv.h"
#include "pgpUsuals.h"
#include "pgpKeySpec.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpPktByte.h"
#include "pgpSigSpec.h"
#include "pgpMem.h"
#include "pgpX509Priv.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_4)
* 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 kPGPError_KEY_LONG.
* (The format of the extra data is not checked.)
*/
int
ringKeyParse(PGPContextRef context, PGPByte const *buf, size_t len,
PGPByte *pkalg, PGPByte keyID[8], PGPByte fp20n[20],
PGPUInt16 *keybits, PGPUInt32 *tstamp, PGPUInt16 *validity,
PGPByte *v3, int secretf)
{
unsigned mlen, elen;
int err;
unsigned vsize;
/* Defaults in case of error */
if (v3)
*v3 = 0;
if (keyID)
pgpClearMemory( keyID, 8);
if (fp20n)
pgpClearMemory( fp20n, 20);
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 = kPGPError_UnknownKeyVersion;
goto fakeid;
}
/* PGPVERSION_4 keys have no validity field */
if (buf[0] == PGPVERSION_4) {
if (v3)
*v3 = FALSE;
vsize = 0;
} else {
if (v3)
*v3 = TRUE;
vsize = 2;
}
if (len < 5)
goto fakeid_short;
if (tstamp)
*tstamp = (PGPUInt32)((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 = (PGPUInt16)mlen;
if (mlen && len > 8 + vsize && buf[8 + vsize] >> ((mlen-1)&7) != 1) {
err = kPGPError_MalformedKeyModulus;
goto fakeid;
}
mlen = (mlen + 7) / 8;
if (len < 8 + vsize + mlen)
goto fakeid_short;
if (len < 10 + vsize + mlen)
return kPGPError_KeyPacketTruncated;
if (buf[5 + vsize] == kPGPPublicKeyAlgorithm_RSA ||
buf[5 + vsize] == kPGPPublicKeyAlgorithm_RSAEncryptOnly ||
buf[5 + vsize] == kPGPPublicKeyAlgorithm_RSASignOnly) {
/* 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 kPGPError_MalformedKeyExponent;
elen = (elen + 7) / 8;
if (len < 10+vsize+mlen+elen)
return kPGPError_KeyPacketTruncated;
if ((buf[8 + vsize + mlen-1] & 1) == 0)
return kPGPError_RSAPublicModulusIsEven;
if ((buf[10+vsize+mlen+elen-1] & 1) == 0)
return kPGPError_RSAPublicExponentIsEven;
if (len > 10+vsize+mlen+elen && !secretf)
return kPGPError_KEY_LONG;
}
if (keyID) {
if (buf[0] < PGPVERSION_4) {
/* Old keyid rules, low 64 bits of modulus */
memcpy(keyID, buf + 8 + vsize + mlen - 8, 8);
if (mlen < 8)
pgpClearMemory( keyID, 8 - mlen);
} else {
/*
* PGPVERSION_4 (aka V4) 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.
*/
PGPByte hash[20];
if (secretf) {
PGPSize seclen = ringKeyParsePublicPrefix(buf, len);
err = pgpFingerprint20HashBuf(context, buf, seclen, hash);
} else {
err = pgpFingerprint20HashBuf(context, buf, len, hash);
}
if (err < 0)
return err;
pgpAssert (err == sizeof(hash));
memcpy(keyID, hash+sizeof(hash)-8, 8);
}
}
if (fp20n) {
PGPSize publen;
unsigned int numlen;
PGPByte const *numbuf;
if (secretf)
publen = ringKeyParsePublicPrefix(buf, len);
else
publen = len;
numbuf = ringKeyParseNumericData( buf, publen, &numlen);
err = pgpFingerprint20HashBuf(context, numbuf, numlen, fp20n);
if (err < 0)
return err;
}
return 0;
fakeid_short:
err = kPGPError_KeyPacketTruncated;
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) {
PGPUInt32 fake = ringHashBuf(buf, len);
keyID[0] = (PGPByte)(fake >> 24);
keyID[1] = (PGPByte)(fake >> 16);
keyID[2] = (PGPByte)(fake >> 8);
keyID[3] = (PGPByte)fake;
}
return err;
}
/*
* Extract the numeric key material from a key and return it
* (buffer & length)
*/
PGPByte const *
ringKeyParseNumericData(PGPByte const *buf, size_t len, unsigned *lenp)
{
unsigned vsize;
*lenp = 0;
if (buf[0] == PGPVERSION_4) {
vsize = 0;
} else {
vsize = 2;
}
if (len < 6+vsize || !KNOWN_PGP_VERSION(buf[0]))
return 0;
*lenp = len - (6 + vsize);
return buf + 6 + vsize;
}
/* Extract the modulus from a key and return it (buffer & length) */
PGPByte const *
ringKeyParseModulus(PGPByte const *buf, size_t len, unsigned *lenp)
{
unsigned msize;
unsigned vsize;
*lenp = 0;
if (buf[0] == PGPVERSION_4) {
vsize = 0;
} else {
vsize = 2;
}
if (len < 8+vsize || !KNOWN_PGP_VERSION(buf[0]) ||
(buf[5+vsize] != kPGPPublicKeyAlgorithm_RSA &&
buf[5+vsize] != kPGPPublicKeyAlgorithm_RSAEncryptOnly &&
buf[5+vsize] != kPGPPublicKeyAlgorithm_RSASignOnly))
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) */
PGPByte const *
ringKeyParseExponent(PGPByte const *buf, size_t len, unsigned *lenp)
{
unsigned size;
unsigned vsize;
*lenp = 0;
if (buf[0] == PGPVERSION_4) {
vsize = 0;
} else {
vsize = 2;
}
if (len < 10+vsize || !KNOWN_PGP_VERSION(buf[0]) ||
(buf[5+vsize] != kPGPPublicKeyAlgorithm_RSA &&
buf[5+vsize] != kPGPPublicKeyAlgorithm_RSAEncryptOnly &&
buf[5+vsize] != kPGPPublicKeyAlgorithm_RSASignOnly))
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
*/
PGPByte const *
ringSigParseExtra(PGPByte const *buf, size_t len, unsigned *lenp)
{
*lenp = 0; /* In case of error */
if (buf[0] == PGPVERSION_4) {
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) */
PGPByte const *
ringSigParseInteger(PGPByte 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] != kPGPPublicKeyAlgorithm_RSA &&
buf[0] != kPGPPublicKeyAlgorithm_RSAEncryptOnly &&
buf[0] != kPGPPublicKeyAlgorithm_RSASignOnly)
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(PGPByte const *buf, size_t len, PGPByte *pkalg, PGPByte keyID[8],
PGPUInt32 *tstamp, PGPUInt32 *validity, PGPByte *type, PGPByte *hashalg,
size_t *extralen, PGPByte *version, PGPBoolean *exportable,
PGPBoolean *revocable, PGPByte *trustLevel, PGPByte *trustValue,
PGPBoolean *hasRegExp, PGPBoolean *isX509, PGPBoolean *primaryUID);
static int
ringSigParseSubpackets(PGPByte const *buf, PGPByte keyID[8],
PGPUInt32 *tstamp, PGPUInt32 *validity, PGPBoolean *exportable,
PGPBoolean *revocable, PGPByte *trustLevel, PGPByte *trustValue,
PGPBoolean *hasRegExp, PGPBoolean *isX509, PGPBoolean *primaryUID);
/*
* 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(PGPByte const *buf, size_t len, PGPByte *pkalg, PGPByte keyID[8],
PGPUInt32 *tstamp, PGPUInt32 *validity, PGPByte *type, PGPByte *hashalg,
size_t *extralen, PGPByte *version, PGPBoolean *exportable,
PGPBoolean *revocable, PGPByte *trustLevel, PGPByte *trustValue,
PGPBoolean *hasRegExp, PGPBoolean *isX509, PGPBoolean *primaryUID)
{
unsigned l; /* extralen */
unsigned t;
PGPByte alg;
/* Default settings in case of error */
if (pkalg)
*pkalg = 0;
if (keyID)
pgpClearMemory( keyID, 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 (exportable)
*exportable = TRUE;
if (revocable)
*revocable = TRUE;
if (trustLevel)
*trustLevel = 0;
if (trustValue)
*trustValue = 0;
if (hasRegExp)
*hasRegExp = FALSE;
if (isX509)
*isX509 = FALSE;
if (primaryUID)
*primaryUID = FALSE;
if (len < 1)
return kPGPError_TruncatedSignature;
/* Forward compatibility */
if (buf[0] == PGPVERSION_4) {
return ringSigParse3(buf, len, pkalg, keyID, tstamp, validity, type,
hashalg, extralen, version, exportable,
revocable, trustLevel, trustValue, hasRegExp,
isX509, primaryUID);
}
if (version)
*version = buf[0];
if (!KNOWN_PGP_VERSION(buf[0]))
return kPGPError_UnknownSignatureVersion;
if (len < 2)
return kPGPError_TruncatedSignature;
l = buf[1];
if (extralen)
*extralen = l;
if (l >= 1) {
if (len < 3)
return kPGPError_TruncatedSignature;
if (type)
*type = buf[2];
if (l >= 5 && tstamp) {
if (len < 7)
return kPGPError_TruncatedSignature;
*tstamp = (PGPUInt32)((unsigned)buf[3]<<8|buf[4]) << 16 |
((unsigned)buf[5]<<8|buf[6]);
}
if (l >= 7 && tstamp) {
if (len < 9)
return kPGPError_TruncatedSignature;
*tstamp = (PGPUInt16)buf[7]<<8 | buf[8];
}
}
if (!extralen && l != 5)
return kPGPError_ExtraSignatureMaterial;
if (len < l+10)
return kPGPError_TruncatedSignature;
if (keyID)
memcpy(keyID, buf + 7, 8);
if (len < l+11)
return kPGPError_TruncatedSignature;
alg = buf[l+10];
if (pkalg)
*pkalg = alg;
#if 0
if (buf[l+10] != kPGPPublicKeyAlgorithm_RSA &&
buf[l+10] != kPGPPublicKeyAlgorithm_RSAEncryptOnly &&
buf[l+10] != kPGPPublicKeyAlgorithm_RSASignOnly)
return kPGPError_UnknownSignatureAlgorithm;
#endif
if (len < l+12)
return kPGPError_TruncatedSignature;
if (hashalg)
*hashalg = buf[l+11];
if (len < l+16)
return kPGPError_TruncatedSignature;
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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -