1406 lines
39 KiB
C
1406 lines
39 KiB
C
/*@-boundsread@*/
|
|
/** \ingroup rpmio signature
|
|
* \file rpmio/rpmpgp.c
|
|
* Routines to handle RFC-2440 detached signatures.
|
|
*/
|
|
|
|
#include "system.h"
|
|
#include "rpmio_internal.h"
|
|
#include "debug.h"
|
|
|
|
/*@access pgpDig @*/
|
|
/*@access pgpDigParams @*/
|
|
|
|
/*@unchecked@*/
|
|
static int _debug = 0;
|
|
|
|
/*@unchecked@*/
|
|
static int _print = 0;
|
|
|
|
/*@unchecked@*/ /*@null@*/
|
|
static pgpDig _dig = NULL;
|
|
|
|
/*@unchecked@*/ /*@null@*/
|
|
static pgpDigParams _digp = NULL;
|
|
|
|
#ifdef DYING
|
|
/* This is the unarmored RPM-GPG-KEY public key. */
|
|
const char * redhatPubKeyDSA = "\
|
|
mQGiBDfqVDgRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8\n\
|
|
HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSWShLabR3N1KXdXQYYcowTOM\n\
|
|
GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbWJbyjkg5Z3P7BlUOUJmrx3wCgobNV\n\
|
|
EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS\n\
|
|
ZVG7rKANEK2mxg1VB+vc/uUc4k49UxJJfCZg1gu1sPFV3GSa+Y/7jsiLktQvCiLP\n\
|
|
lncQt1dV+ENmHR5BdIDPWDzKBVbgWnSDnqQ6KrZ7T6AlZ74VMpjGxxkWU6vV2xsW\n\
|
|
XCLPA/9P/vtImA8CZN3jxGgtK5GGtDNJ/cMhhuv5tnfwFg4b/VGo2Jr8mhLUqoIb\n\
|
|
E6zeGAmZbUpdckDco8D5fiFmqTf5+++pCEpJLJkkzel/32N2w4qzPrcRMCiBURES\n\
|
|
PjCLd4Y5rPoU8E4kOHc/4BuHN903tiCsCPloCrWsQZ7UdxfQ5LQiUmVkIEhhdCwg\n\
|
|
SW5jIDxzZWN1cml0eUByZWRoYXQuY29tPohVBBMRAgAVBQI36lQ4AwsKAwMVAwID\n\
|
|
FgIBAheAAAoJECGRgM3bQqYOsBQAnRVtg7B25Hm11PHcpa8FpeddKiq2AJ9aO8sB\n\
|
|
XmLDmPOEFI75mpTrKYHF6rkCDQQ36lRyEAgAokgI2xJ+3bZsk8jRA8ORIX8DH05U\n\
|
|
lMH27qFYzLbT6npXwXYIOtVn0K2/iMDj+oEB1Aa2au4OnddYaLWp06v3d+XyS0t+\n\
|
|
5ab2ZfIQzdh7wCwxqRkzR+/H5TLYbMG+hvtTdylfqIX0WEfoOXMtWEGSVwyUsnM3\n\
|
|
Jy3LOi48rQQSCKtCAUdV20FoIGWhwnb/gHU1BnmES6UdQujFBE6EANqPhp0coYoI\n\
|
|
hHJ2oIO8ujQItvvNaU88j/s/izQv5e7MXOgVSjKe/WX3s2JtB/tW7utpy12wh1J+\n\
|
|
JsFdbLV/t8CozUTpJgx5mVA3RKlxjTA+On+1IEUWioB+iVfT7Ov/0kcAzwADBQf9\n\
|
|
E4SKCWRand8K0XloMYgmipxMhJNnWDMLkokvbMNTUoNpSfRoQJ9EheXDxwMpTPwK\n\
|
|
ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8\n\
|
|
BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5\n\
|
|
4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdRCCE+Y7YVP6IUf/w6YPQFQriWY\n\
|
|
FiA6fD10eB+BlIUqIw80VgjsBKmCwvKkn4jg8kibXgj4/TzQSx77uYokw1EqQ2wk\n\
|
|
OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h\n\
|
|
VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==\n\
|
|
";
|
|
|
|
/* This is the unarmored RPM-PGP-KEY public key. */
|
|
const char * redhatPubKeyRSA = "\
|
|
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\n\
|
|
z15FuA==\n\
|
|
";
|
|
#endif /* DYING */
|
|
|
|
struct pgpValTbl_s pgpSigTypeTbl[] = {
|
|
{ PGPSIGTYPE_BINARY, "Binary document signature" },
|
|
{ PGPSIGTYPE_TEXT, "Text document signature" },
|
|
{ PGPSIGTYPE_STANDALONE, "Standalone signature" },
|
|
{ PGPSIGTYPE_GENERIC_CERT, "Generic certification of a User ID and Public Key" },
|
|
{ PGPSIGTYPE_PERSONA_CERT, "Persona certification of a User ID and Public Key" },
|
|
{ PGPSIGTYPE_CASUAL_CERT, "Casual certification of a User ID and Public Key" },
|
|
{ PGPSIGTYPE_POSITIVE_CERT, "Positive certification of a User ID and Public Key" },
|
|
{ PGPSIGTYPE_SUBKEY_BINDING,"Subkey Binding Signature" },
|
|
{ PGPSIGTYPE_SIGNED_KEY, "Signature directly on a key" },
|
|
{ PGPSIGTYPE_KEY_REVOKE, "Key revocation signature" },
|
|
{ PGPSIGTYPE_SUBKEY_REVOKE, "Subkey revocation signature" },
|
|
{ PGPSIGTYPE_CERT_REVOKE, "Certification revocation signature" },
|
|
{ PGPSIGTYPE_TIMESTAMP, "Timestamp signature" },
|
|
{ -1, "Unknown signature type" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpPubkeyTbl[] = {
|
|
{ PGPPUBKEYALGO_RSA, "RSA" },
|
|
{ PGPPUBKEYALGO_RSA_ENCRYPT,"RSA(Encrypt-Only)" },
|
|
{ PGPPUBKEYALGO_RSA_SIGN, "RSA(Sign-Only)" },
|
|
{ PGPPUBKEYALGO_ELGAMAL_ENCRYPT,"Elgamal(Encrypt-Only)" },
|
|
{ PGPPUBKEYALGO_DSA, "DSA" },
|
|
{ PGPPUBKEYALGO_EC, "Elliptic Curve" },
|
|
{ PGPPUBKEYALGO_ECDSA, "ECDSA" },
|
|
{ PGPPUBKEYALGO_ELGAMAL, "Elgamal" },
|
|
{ PGPPUBKEYALGO_DH, "Diffie-Hellman (X9.42)" },
|
|
{ -1, "Unknown public key algorithm" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpSymkeyTbl[] = {
|
|
{ PGPSYMKEYALGO_PLAINTEXT, "Plaintext" },
|
|
{ PGPSYMKEYALGO_IDEA, "IDEA" },
|
|
{ PGPSYMKEYALGO_TRIPLE_DES, "3DES" },
|
|
{ PGPSYMKEYALGO_CAST5, "CAST5" },
|
|
{ PGPSYMKEYALGO_BLOWFISH, "BLOWFISH" },
|
|
{ PGPSYMKEYALGO_SAFER, "SAFER" },
|
|
{ PGPSYMKEYALGO_DES_SK, "DES/SK" },
|
|
{ PGPSYMKEYALGO_AES_128, "AES(128-bit key)" },
|
|
{ PGPSYMKEYALGO_AES_192, "AES(192-bit key)" },
|
|
{ PGPSYMKEYALGO_AES_256, "AES(256-bit key)" },
|
|
{ PGPSYMKEYALGO_TWOFISH, "TWOFISH(256-bit key)" },
|
|
{ PGPSYMKEYALGO_NOENCRYPT, "no encryption" },
|
|
{ -1, "Unknown symmetric key algorithm" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpCompressionTbl[] = {
|
|
{ PGPCOMPRESSALGO_NONE, "Uncompressed" },
|
|
{ PGPCOMPRESSALGO_ZIP, "ZIP" },
|
|
{ PGPCOMPRESSALGO_ZLIB, "ZLIB" },
|
|
{ PGPCOMPRESSALGO_BZIP2, "BZIP2" },
|
|
{ -1, "Unknown compression algorithm" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpHashTbl[] = {
|
|
{ PGPHASHALGO_MD5, "MD5" },
|
|
{ PGPHASHALGO_SHA1, "SHA1" },
|
|
{ PGPHASHALGO_RIPEMD160, "RIPEMD160" },
|
|
{ PGPHASHALGO_MD2, "MD2" },
|
|
{ PGPHASHALGO_TIGER192, "TIGER192" },
|
|
{ PGPHASHALGO_HAVAL_5_160, "HAVAL-5-160" },
|
|
{ PGPHASHALGO_SHA256, "SHA256" },
|
|
{ PGPHASHALGO_SHA384, "SHA384" },
|
|
{ PGPHASHALGO_SHA512, "SHA512" },
|
|
{ -1, "Unknown hash algorithm" },
|
|
};
|
|
|
|
/*@-exportlocal -exportheadervar@*/
|
|
/*@observer@*/ /*@unchecked@*/
|
|
struct pgpValTbl_s pgpKeyServerPrefsTbl[] = {
|
|
{ 0x80, "No-modify" },
|
|
{ -1, "Unknown key server preference" },
|
|
};
|
|
/*@=exportlocal =exportheadervar@*/
|
|
|
|
struct pgpValTbl_s pgpSubTypeTbl[] = {
|
|
{ PGPSUBTYPE_SIG_CREATE_TIME,"signature creation time" },
|
|
{ PGPSUBTYPE_SIG_EXPIRE_TIME,"signature expiration time" },
|
|
{ PGPSUBTYPE_EXPORTABLE_CERT,"exportable certification" },
|
|
{ PGPSUBTYPE_TRUST_SIG, "trust signature" },
|
|
{ PGPSUBTYPE_REGEX, "regular expression" },
|
|
{ PGPSUBTYPE_REVOCABLE, "revocable" },
|
|
{ PGPSUBTYPE_KEY_EXPIRE_TIME,"key expiration time" },
|
|
{ PGPSUBTYPE_ARR, "additional recipient request" },
|
|
{ PGPSUBTYPE_PREFER_SYMKEY, "preferred symmetric algorithms" },
|
|
{ PGPSUBTYPE_REVOKE_KEY, "revocation key" },
|
|
{ PGPSUBTYPE_ISSUER_KEYID, "issuer key ID" },
|
|
{ PGPSUBTYPE_NOTATION, "notation data" },
|
|
{ PGPSUBTYPE_PREFER_HASH, "preferred hash algorithms" },
|
|
{ PGPSUBTYPE_PREFER_COMPRESS,"preferred compression algorithms" },
|
|
{ PGPSUBTYPE_KEYSERVER_PREFERS,"key server preferences" },
|
|
{ PGPSUBTYPE_PREFER_KEYSERVER,"preferred key server" },
|
|
{ PGPSUBTYPE_PRIMARY_USERID,"primary user id" },
|
|
{ PGPSUBTYPE_POLICY_URL, "policy URL" },
|
|
{ PGPSUBTYPE_KEY_FLAGS, "key flags" },
|
|
{ PGPSUBTYPE_SIGNER_USERID, "signer's user id" },
|
|
{ PGPSUBTYPE_REVOKE_REASON, "reason for revocation" },
|
|
{ PGPSUBTYPE_FEATURES, "features" },
|
|
{ PGPSUBTYPE_EMBEDDED_SIG, "embedded signature" },
|
|
|
|
{ PGPSUBTYPE_INTERNAL_100, "internal subpkt type 100" },
|
|
{ PGPSUBTYPE_INTERNAL_101, "internal subpkt type 101" },
|
|
{ PGPSUBTYPE_INTERNAL_102, "internal subpkt type 102" },
|
|
{ PGPSUBTYPE_INTERNAL_103, "internal subpkt type 103" },
|
|
{ PGPSUBTYPE_INTERNAL_104, "internal subpkt type 104" },
|
|
{ PGPSUBTYPE_INTERNAL_105, "internal subpkt type 105" },
|
|
{ PGPSUBTYPE_INTERNAL_106, "internal subpkt type 106" },
|
|
{ PGPSUBTYPE_INTERNAL_107, "internal subpkt type 107" },
|
|
{ PGPSUBTYPE_INTERNAL_108, "internal subpkt type 108" },
|
|
{ PGPSUBTYPE_INTERNAL_109, "internal subpkt type 109" },
|
|
{ PGPSUBTYPE_INTERNAL_110, "internal subpkt type 110" },
|
|
{ -1, "Unknown signature subkey type" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpTagTbl[] = {
|
|
{ PGPTAG_PUBLIC_SESSION_KEY,"Public-Key Encrypted Session Key" },
|
|
{ PGPTAG_SIGNATURE, "Signature" },
|
|
{ PGPTAG_SYMMETRIC_SESSION_KEY,"Symmetric-Key Encrypted Session Key" },
|
|
{ PGPTAG_ONEPASS_SIGNATURE, "One-Pass Signature" },
|
|
{ PGPTAG_SECRET_KEY, "Secret Key" },
|
|
{ PGPTAG_PUBLIC_KEY, "Public Key" },
|
|
{ PGPTAG_SECRET_SUBKEY, "Secret Subkey" },
|
|
{ PGPTAG_COMPRESSED_DATA, "Compressed Data" },
|
|
{ PGPTAG_SYMMETRIC_DATA, "Symmetrically Encrypted Data" },
|
|
{ PGPTAG_MARKER, "Marker" },
|
|
{ PGPTAG_LITERAL_DATA, "Literal Data" },
|
|
{ PGPTAG_TRUST, "Trust" },
|
|
{ PGPTAG_USER_ID, "User ID" },
|
|
{ PGPTAG_PUBLIC_SUBKEY, "Public Subkey" },
|
|
{ PGPTAG_COMMENT_OLD, "Comment (from OpenPGP draft)" },
|
|
{ PGPTAG_PHOTOID, "PGP's photo ID" },
|
|
{ PGPTAG_ENCRYPTED_MDC, "Integrity protected encrypted data" },
|
|
{ PGPTAG_MDC, "Manipulaion detection code packet" },
|
|
{ PGPTAG_PRIVATE_60, "Private #60" },
|
|
{ PGPTAG_COMMENT, "Comment" },
|
|
{ PGPTAG_PRIVATE_62, "Private #62" },
|
|
{ PGPTAG_CONTROL, "Control (GPG)" },
|
|
{ -1, "Unknown packet tag" },
|
|
};
|
|
|
|
struct pgpValTbl_s pgpArmorTbl[] = {
|
|
{ PGPARMOR_MESSAGE, "MESSAGE" },
|
|
{ PGPARMOR_PUBKEY, "PUBLIC KEY BLOCK" },
|
|
{ PGPARMOR_SIGNATURE, "SIGNATURE" },
|
|
{ PGPARMOR_SIGNED_MESSAGE, "SIGNED MESSAGE" },
|
|
{ PGPARMOR_FILE, "ARMORED FILE" },
|
|
{ PGPARMOR_PRIVKEY, "PRIVATE KEY BLOCK" },
|
|
{ PGPARMOR_SECKEY, "SECRET KEY BLOCK" },
|
|
{ -1, "Unknown armor block" }
|
|
};
|
|
|
|
struct pgpValTbl_s pgpArmorKeyTbl[] = {
|
|
{ PGPARMORKEY_VERSION, "Version: " },
|
|
{ PGPARMORKEY_COMMENT, "Comment: " },
|
|
{ PGPARMORKEY_MESSAGEID, "MessageID: " },
|
|
{ PGPARMORKEY_HASH, "Hash: " },
|
|
{ PGPARMORKEY_CHARSET, "Charset: " },
|
|
{ -1, "Unknown armor key" }
|
|
};
|
|
|
|
/**
|
|
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
|
|
* @param p memory to free
|
|
* @return NULL always
|
|
*/
|
|
/*@unused@*/ static inline /*@null@*/ void *
|
|
_free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p)
|
|
/*@modifies p @*/
|
|
{
|
|
if (p != NULL) free((void *)p);
|
|
return NULL;
|
|
}
|
|
|
|
static void pgpPrtNL(void)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
if (!_print) return;
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
static void pgpPrtInt(const char *pre, int i)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
if (!_print) return;
|
|
if (pre && *pre)
|
|
fprintf(stderr, "%s", pre);
|
|
fprintf(stderr, " %d", i);
|
|
}
|
|
|
|
static void pgpPrtStr(const char *pre, const char *s)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
if (!_print) return;
|
|
if (pre && *pre)
|
|
fprintf(stderr, "%s", pre);
|
|
fprintf(stderr, " %s", s);
|
|
}
|
|
|
|
static void pgpPrtHex(const char *pre, const byte *p, unsigned int plen)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
if (!_print) return;
|
|
if (pre && *pre)
|
|
fprintf(stderr, "%s", pre);
|
|
fprintf(stderr, " %s", pgpHexStr(p, plen));
|
|
}
|
|
|
|
void pgpPrtVal(const char * pre, pgpValTbl vs, byte val)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
if (!_print) return;
|
|
if (pre && *pre)
|
|
fprintf(stderr, "%s", pre);
|
|
fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
/*@unused@*/ static /*@observer@*/
|
|
const char * pgpMpiHex(const byte *p)
|
|
/*@*/
|
|
{
|
|
static char prbuf[2048];
|
|
char *t = prbuf;
|
|
t = pgpHexCvt(t, p+2, pgpMpiLen(p)-2);
|
|
return prbuf;
|
|
}
|
|
|
|
/*@-boundswrite@*/
|
|
/**
|
|
* @return 0 on success
|
|
*/
|
|
static int pgpHexSet(const char * pre, int lbits,
|
|
/*@out@*/ mpnumber * mpn, const byte * p, const byte * pend)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies mpn, fileSystem @*/
|
|
{
|
|
unsigned int mbits = pgpMpiBits(p);
|
|
unsigned int nbits;
|
|
unsigned int nbytes;
|
|
char * t;
|
|
unsigned int ix;
|
|
|
|
if ((p + ((mbits+7) >> 3)) > pend)
|
|
return 1;
|
|
|
|
nbits = (lbits > mbits ? lbits : mbits);
|
|
nbytes = ((nbits + 7) >> 3);
|
|
t = xmalloc(2*nbytes+1);
|
|
ix = 2 * ((nbits - mbits) >> 3);
|
|
|
|
if (_debug)
|
|
fprintf(stderr, "*** mbits %u nbits %u nbytes %u t %p[%d] ix %u\n", mbits, nbits, nbytes, t, (2*nbytes+1), ix);
|
|
if (ix > 0) memset(t, (int)'0', ix);
|
|
strcpy(t+ix, pgpMpiHex(p));
|
|
if (_debug)
|
|
fprintf(stderr, "*** %s %s\n", pre, t);
|
|
(void) mpnsethex(mpn, t);
|
|
t = _free(t);
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t %s ", pre), mpfprintln(stderr, mpn->size, mpn->data);
|
|
return 0;
|
|
}
|
|
/*@=boundswrite@*/
|
|
|
|
int pgpPrtSubType(const byte *h, unsigned int hlen, pgpSigType sigtype)
|
|
{
|
|
const byte *p = h;
|
|
unsigned plen;
|
|
int i;
|
|
|
|
while (hlen > 0) {
|
|
i = pgpLen(p, &plen);
|
|
p += i;
|
|
hlen -= i;
|
|
|
|
pgpPrtVal(" ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL)));
|
|
if (p[0] & PGPSUBTYPE_CRITICAL)
|
|
if (_print)
|
|
fprintf(stderr, " *CRITICAL*");
|
|
switch (*p) {
|
|
case PGPSUBTYPE_PREFER_SYMKEY: /* preferred symmetric algorithms */
|
|
for (i = 1; i < plen; i++)
|
|
pgpPrtVal(" ", pgpSymkeyTbl, p[i]);
|
|
/*@switchbreak@*/ break;
|
|
case PGPSUBTYPE_PREFER_HASH: /* preferred hash algorithms */
|
|
for (i = 1; i < plen; i++)
|
|
pgpPrtVal(" ", pgpHashTbl, p[i]);
|
|
/*@switchbreak@*/ break;
|
|
case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */
|
|
for (i = 1; i < plen; i++)
|
|
pgpPrtVal(" ", pgpCompressionTbl, p[i]);
|
|
/*@switchbreak@*/ break;
|
|
case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */
|
|
for (i = 1; i < plen; i++)
|
|
pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
|
|
/*@switchbreak@*/ break;
|
|
case PGPSUBTYPE_SIG_CREATE_TIME:
|
|
/*@-mods -mayaliasunique @*/
|
|
if (_digp && !(_digp->saved & PGPDIG_SAVED_TIME) &&
|
|
(sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
|
|
{
|
|
_digp->saved |= PGPDIG_SAVED_TIME;
|
|
memcpy(_digp->time, p+1, sizeof(_digp->time));
|
|
}
|
|
/*@=mods =mayaliasunique @*/
|
|
/*@fallthrough@*/
|
|
case PGPSUBTYPE_SIG_EXPIRE_TIME:
|
|
case PGPSUBTYPE_KEY_EXPIRE_TIME:
|
|
if ((plen - 1) == 4) {
|
|
time_t t = pgpGrab(p+1, plen-1);
|
|
if (_print)
|
|
fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
|
|
} else
|
|
pgpPrtHex("", p+1, plen-1);
|
|
/*@switchbreak@*/ break;
|
|
|
|
case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */
|
|
/*@-mods -mayaliasunique @*/
|
|
if (_digp && !(_digp->saved & PGPDIG_SAVED_ID) &&
|
|
(sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
|
|
{
|
|
_digp->saved |= PGPDIG_SAVED_ID;
|
|
memcpy(_digp->signid, p+1, sizeof(_digp->signid));
|
|
}
|
|
/*@=mods =mayaliasunique @*/
|
|
/*@fallthrough@*/
|
|
case PGPSUBTYPE_EXPORTABLE_CERT:
|
|
case PGPSUBTYPE_TRUST_SIG:
|
|
case PGPSUBTYPE_REGEX:
|
|
case PGPSUBTYPE_REVOCABLE:
|
|
case PGPSUBTYPE_ARR:
|
|
case PGPSUBTYPE_REVOKE_KEY:
|
|
case PGPSUBTYPE_NOTATION:
|
|
case PGPSUBTYPE_PREFER_KEYSERVER:
|
|
case PGPSUBTYPE_PRIMARY_USERID:
|
|
case PGPSUBTYPE_POLICY_URL:
|
|
case PGPSUBTYPE_KEY_FLAGS:
|
|
case PGPSUBTYPE_SIGNER_USERID:
|
|
case PGPSUBTYPE_REVOKE_REASON:
|
|
case PGPSUBTYPE_FEATURES:
|
|
case PGPSUBTYPE_EMBEDDED_SIG:
|
|
case PGPSUBTYPE_INTERNAL_100:
|
|
case PGPSUBTYPE_INTERNAL_101:
|
|
case PGPSUBTYPE_INTERNAL_102:
|
|
case PGPSUBTYPE_INTERNAL_103:
|
|
case PGPSUBTYPE_INTERNAL_104:
|
|
case PGPSUBTYPE_INTERNAL_105:
|
|
case PGPSUBTYPE_INTERNAL_106:
|
|
case PGPSUBTYPE_INTERNAL_107:
|
|
case PGPSUBTYPE_INTERNAL_108:
|
|
case PGPSUBTYPE_INTERNAL_109:
|
|
case PGPSUBTYPE_INTERNAL_110:
|
|
default:
|
|
pgpPrtHex("", p+1, plen-1);
|
|
/*@switchbreak@*/ break;
|
|
}
|
|
pgpPrtNL();
|
|
p += plen;
|
|
hlen -= plen;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@-varuse =readonlytrans @*/
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpSigRSA[] = {
|
|
" m**d =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpSigDSA[] = {
|
|
" r =",
|
|
" s =",
|
|
NULL,
|
|
};
|
|
/*@=varuse =readonlytrans @*/
|
|
|
|
static int pgpPrtSigParams(/*@unused@*/ pgpTag tag, byte pubkey_algo, byte sigtype,
|
|
const byte *p, const byte *h, unsigned int hlen)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
const byte * pend = h + hlen;
|
|
int i;
|
|
|
|
for (i = 0; p < pend; i++, p += pgpMpiLen(p)) {
|
|
if (pubkey_algo == PGPPUBKEYALGO_RSA) {
|
|
if (i >= 1) break;
|
|
if (_dig &&
|
|
(sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT))
|
|
{
|
|
switch (i) {
|
|
case 0: /* m**d */
|
|
(void) mpnsethex(&_dig->c, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t m**d = "), mpfprintln(stderr, _dig->c.size, _dig->c.data);
|
|
/*@switchbreak@*/ break;
|
|
default:
|
|
/*@switchbreak@*/ break;
|
|
}
|
|
}
|
|
pgpPrtStr("", pgpSigRSA[i]);
|
|
} else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
|
|
if (i >= 2) break;
|
|
if (_dig &&
|
|
(sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT))
|
|
{
|
|
int xx;
|
|
xx = 0;
|
|
switch (i) {
|
|
case 0: /* r */
|
|
xx = pgpHexSet(pgpSigDSA[i], 160, &_dig->r, p, pend);
|
|
/*@switchbreak@*/ break;
|
|
case 1: /* s */
|
|
xx = pgpHexSet(pgpSigDSA[i], 160, &_dig->s, p, pend);
|
|
/*@switchbreak@*/ break;
|
|
default:
|
|
xx = 1;
|
|
/*@switchbreak@*/ break;
|
|
}
|
|
if (xx) return xx;
|
|
}
|
|
pgpPrtStr("", pgpSigDSA[i]);
|
|
} else {
|
|
if (_print)
|
|
fprintf(stderr, "%7d", i);
|
|
}
|
|
pgpPrtStr("", pgpMpiStr(p));
|
|
pgpPrtNL();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pgpPrtSig(pgpTag tag, const byte *h, unsigned int hlen)
|
|
/*@globals _digp @*/
|
|
/*@modifies *_digp @*/
|
|
{
|
|
byte version = h[0];
|
|
byte * p;
|
|
unsigned plen;
|
|
int rc;
|
|
|
|
switch (version) {
|
|
case 3:
|
|
{ pgpPktSigV3 v = (pgpPktSigV3)h;
|
|
time_t t;
|
|
|
|
if (v->hashlen != 5)
|
|
return 1;
|
|
|
|
pgpPrtVal("V3 ", pgpTagTbl, tag);
|
|
pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
|
|
pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
|
|
pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
|
|
pgpPrtNL();
|
|
t = pgpGrab(v->time, sizeof(v->time));
|
|
if (_print)
|
|
fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
|
|
pgpPrtNL();
|
|
pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid));
|
|
plen = pgpGrab(v->signhash16, sizeof(v->signhash16));
|
|
pgpPrtHex(" signhash16", v->signhash16, sizeof(v->signhash16));
|
|
pgpPrtNL();
|
|
|
|
if (_digp && _digp->pubkey_algo == 0) {
|
|
_digp->version = v->version;
|
|
_digp->hashlen = v->hashlen;
|
|
_digp->sigtype = v->sigtype;
|
|
_digp->hash = memcpy(xmalloc(v->hashlen), &v->sigtype, v->hashlen);
|
|
memcpy(_digp->time, v->time, sizeof(_digp->time));
|
|
memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
|
|
_digp->pubkey_algo = v->pubkey_algo;
|
|
_digp->hash_algo = v->hash_algo;
|
|
memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16));
|
|
}
|
|
|
|
p = ((byte *)v) + sizeof(*v);
|
|
rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen);
|
|
} break;
|
|
case 4:
|
|
{ pgpPktSigV4 v = (pgpPktSigV4)h;
|
|
|
|
pgpPrtVal("V4 ", pgpTagTbl, tag);
|
|
pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
|
|
pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
|
|
pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
|
|
pgpPrtNL();
|
|
|
|
p = &v->hashlen[0];
|
|
plen = pgpGrab(v->hashlen, sizeof(v->hashlen));
|
|
p += sizeof(v->hashlen);
|
|
|
|
if ((p + plen) > (h + hlen))
|
|
return 1;
|
|
|
|
if (_debug && _print)
|
|
fprintf(stderr, " hash[%u] -- %s\n", plen, pgpHexStr(p, plen));
|
|
if (_digp && _digp->pubkey_algo == 0) {
|
|
_digp->hashlen = sizeof(*v) + plen;
|
|
_digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
|
|
}
|
|
(void) pgpPrtSubType(p, plen, v->sigtype);
|
|
p += plen;
|
|
|
|
plen = pgpGrab(p,2);
|
|
p += 2;
|
|
|
|
if ((p + plen) > (h + hlen))
|
|
return 1;
|
|
|
|
if (_debug && _print)
|
|
fprintf(stderr, " unhash[%u] -- %s\n", plen, pgpHexStr(p, plen));
|
|
(void) pgpPrtSubType(p, plen, v->sigtype);
|
|
p += plen;
|
|
|
|
plen = pgpGrab(p,2);
|
|
pgpPrtHex(" signhash16", p, 2);
|
|
pgpPrtNL();
|
|
|
|
if (_digp && _digp->pubkey_algo == 0) {
|
|
_digp->version = v->version;
|
|
_digp->sigtype = v->sigtype;
|
|
_digp->pubkey_algo = v->pubkey_algo;
|
|
_digp->hash_algo = v->hash_algo;
|
|
memcpy(_digp->signhash16, p, sizeof(_digp->signhash16));
|
|
}
|
|
|
|
p += 2;
|
|
if (p > (h + hlen))
|
|
return 1;
|
|
|
|
rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen);
|
|
} break;
|
|
default:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*@-varuse =readonlytrans @*/
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpPublicRSA[] = {
|
|
" n =",
|
|
" e =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpSecretRSA[] = {
|
|
" d =",
|
|
" p =",
|
|
" q =",
|
|
" u =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpPublicDSA[] = {
|
|
" p =",
|
|
" q =",
|
|
" g =",
|
|
" y =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpSecretDSA[] = {
|
|
" x =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpPublicELGAMAL[] = {
|
|
" p =",
|
|
" g =",
|
|
" y =",
|
|
NULL,
|
|
};
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static const char * pgpSecretELGAMAL[] = {
|
|
" x =",
|
|
NULL,
|
|
};
|
|
/*@=varuse =readonlytrans @*/
|
|
|
|
static const byte * pgpPrtPubkeyParams(byte pubkey_algo,
|
|
/*@returned@*/ const byte *p, const byte *h, unsigned int hlen)
|
|
/*@globals fileSystem, internalState @*/
|
|
/*@modifies fileSystem, internalState @*/
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; p < &h[hlen]; i++, p += pgpMpiLen(p)) {
|
|
if (pubkey_algo == PGPPUBKEYALGO_RSA) {
|
|
if (i >= 2) break;
|
|
if (_dig) {
|
|
switch (i) {
|
|
case 0: /* n */
|
|
(void) mpbsethex(&_dig->rsa_pk.n, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t n = "), mpfprintln(stderr, _dig->rsa_pk.n.size, _dig->rsa_pk.n.modl);
|
|
/*@switchbreak@*/ break;
|
|
case 1: /* e */
|
|
(void) mpnsethex(&_dig->rsa_pk.e, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t e = "), mpfprintln(stderr, _dig->rsa_pk.e.size, _dig->rsa_pk.e.data);
|
|
/*@switchbreak@*/ break;
|
|
default:
|
|
/*@switchbreak@*/ break;
|
|
}
|
|
}
|
|
pgpPrtStr("", pgpPublicRSA[i]);
|
|
} else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
|
|
if (i >= 4) break;
|
|
if (_dig) {
|
|
switch (i) {
|
|
case 0: /* p */
|
|
(void) mpbsethex(&_dig->p, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t p = "), mpfprintln(stderr, _dig->p.size, _dig->p.modl);
|
|
/*@switchbreak@*/ break;
|
|
case 1: /* q */
|
|
(void) mpbsethex(&_dig->q, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t q = "), mpfprintln(stderr, _dig->q.size, _dig->q.modl);
|
|
/*@switchbreak@*/ break;
|
|
case 2: /* g */
|
|
(void) mpnsethex(&_dig->g, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t g = "), mpfprintln(stderr, _dig->g.size, _dig->g.data);
|
|
/*@switchbreak@*/ break;
|
|
case 3: /* y */
|
|
(void) mpnsethex(&_dig->y, pgpMpiHex(p));
|
|
if (_debug && _print)
|
|
fprintf(stderr, "\t y = "), mpfprintln(stderr, _dig->y.size, _dig->y.data);
|
|
/*@switchbreak@*/ break;
|
|
default:
|
|
/*@switchbreak@*/ break;
|
|
}
|
|
}
|
|
pgpPrtStr("", pgpPublicDSA[i]);
|
|
} else if (pubkey_algo == PGPPUBKEYALGO_ELGAMAL_ENCRYPT) {
|
|
if (i >= 3) break;
|
|
pgpPrtStr("", pgpPublicELGAMAL[i]);
|
|
} else {
|
|
if (_print)
|
|
fprintf(stderr, "%7d", i);
|
|
}
|
|
pgpPrtStr("", pgpMpiStr(p));
|
|
pgpPrtNL();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
static const byte * pgpPrtSeckeyParams(/*@unused@*/ byte pubkey_algo,
|
|
/*@returned@*/ const byte *p, const byte *h, unsigned int hlen)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int i;
|
|
|
|
switch (*p) {
|
|
case 0:
|
|
pgpPrtVal(" ", pgpSymkeyTbl, *p);
|
|
break;
|
|
case 255:
|
|
p++;
|
|
pgpPrtVal(" ", pgpSymkeyTbl, *p);
|
|
switch (p[1]) {
|
|
case 0x00:
|
|
pgpPrtVal(" simple ", pgpHashTbl, p[2]);
|
|
p += 2;
|
|
/*@innerbreak@*/ break;
|
|
case 0x01:
|
|
pgpPrtVal(" salted ", pgpHashTbl, p[2]);
|
|
pgpPrtHex("", p+3, 8);
|
|
p += 10;
|
|
/*@innerbreak@*/ break;
|
|
case 0x03:
|
|
pgpPrtVal(" iterated/salted ", pgpHashTbl, p[2]);
|
|
/*@-shiftnegative -shiftimplementation @*/ /* FIX: unsigned cast */
|
|
i = (16 + (p[11] & 0xf)) << ((p[11] >> 4) + 6);
|
|
/*@=shiftnegative =shiftimplementation @*/
|
|
pgpPrtHex("", p+3, 8);
|
|
pgpPrtInt(" iter", i);
|
|
p += 11;
|
|
/*@innerbreak@*/ break;
|
|
}
|
|
break;
|
|
default:
|
|
pgpPrtVal(" ", pgpSymkeyTbl, *p);
|
|
pgpPrtHex(" IV", p+1, 8);
|
|
p += 8;
|
|
break;
|
|
}
|
|
pgpPrtNL();
|
|
|
|
p++;
|
|
|
|
#ifdef NOTYET /* XXX encrypted MPI's need to be handled. */
|
|
for (i = 0; p < &h[hlen]; i++, p += pgpMpiLen(p)) {
|
|
if (pubkey_algo == PGPPUBKEYALGO_RSA) {
|
|
if (pgpSecretRSA[i] == NULL) break;
|
|
pgpPrtStr("", pgpSecretRSA[i]);
|
|
} else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
|
|
if (pgpSecretDSA[i] == NULL) break;
|
|
pgpPrtStr("", pgpSecretDSA[i]);
|
|
} else if (pubkey_algo == PGPPUBKEYALGO_ELGAMAL_ENCRYPT) {
|
|
if (pgpSecretELGAMAL[i] == NULL) break;
|
|
pgpPrtStr("", pgpSecretELGAMAL[i]);
|
|
} else {
|
|
if (_print)
|
|
fprintf(stderr, "%7d", i);
|
|
}
|
|
pgpPrtStr("", pgpMpiStr(p));
|
|
pgpPrtNL();
|
|
}
|
|
#else
|
|
pgpPrtHex(" secret", p, (hlen - (p - h) - 2));
|
|
pgpPrtNL();
|
|
p += (hlen - (p - h) - 2);
|
|
#endif
|
|
pgpPrtHex(" checksum", p, 2);
|
|
pgpPrtNL();
|
|
|
|
return p;
|
|
}
|
|
|
|
int pgpPrtKey(pgpTag tag, const byte *h, unsigned int hlen)
|
|
/*@globals _digp @*/
|
|
/*@modifies *_digp @*/
|
|
{
|
|
byte version = *h;
|
|
const byte * p;
|
|
unsigned plen;
|
|
time_t t;
|
|
int rc;
|
|
|
|
switch (version) {
|
|
case 3:
|
|
{ pgpPktKeyV3 v = (pgpPktKeyV3)h;
|
|
pgpPrtVal("V3 ", pgpTagTbl, tag);
|
|
pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
|
|
t = pgpGrab(v->time, sizeof(v->time));
|
|
if (_print)
|
|
fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
|
|
plen = pgpGrab(v->valid, sizeof(v->valid));
|
|
if (plen != 0)
|
|
fprintf(stderr, " valid %u days", plen);
|
|
pgpPrtNL();
|
|
|
|
if (_digp && _digp->tag == tag) {
|
|
_digp->version = v->version;
|
|
memcpy(_digp->time, v->time, sizeof(_digp->time));
|
|
_digp->pubkey_algo = v->pubkey_algo;
|
|
}
|
|
|
|
p = ((byte *)v) + sizeof(*v);
|
|
p = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen);
|
|
rc = 0;
|
|
} break;
|
|
case 4:
|
|
{ pgpPktKeyV4 v = (pgpPktKeyV4)h;
|
|
pgpPrtVal("V4 ", pgpTagTbl, tag);
|
|
pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
|
|
t = pgpGrab(v->time, sizeof(v->time));
|
|
if (_print)
|
|
fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
|
|
pgpPrtNL();
|
|
|
|
if (_digp && _digp->tag == tag) {
|
|
_digp->version = v->version;
|
|
memcpy(_digp->time, v->time, sizeof(_digp->time));
|
|
_digp->pubkey_algo = v->pubkey_algo;
|
|
}
|
|
|
|
p = ((byte *)v) + sizeof(*v);
|
|
p = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen);
|
|
if (!(tag == PGPTAG_PUBLIC_KEY || tag == PGPTAG_PUBLIC_SUBKEY))
|
|
p = pgpPrtSeckeyParams(v->pubkey_algo, p, h, hlen);
|
|
rc = 0;
|
|
} break;
|
|
default:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*@-boundswrite@*/
|
|
int pgpPrtUserID(pgpTag tag, const byte *h, unsigned int hlen)
|
|
/*@globals _digp @*/
|
|
/*@modifies *_digp @*/
|
|
{
|
|
pgpPrtVal("", pgpTagTbl, tag);
|
|
if (_print)
|
|
fprintf(stderr, " \"%.*s\"", (int)hlen, (const char *)h);
|
|
pgpPrtNL();
|
|
if (_digp) {
|
|
char * t;
|
|
_digp->userid = t = memcpy(xmalloc(hlen+1), h, hlen);
|
|
t[hlen] = '\0';
|
|
}
|
|
return 0;
|
|
}
|
|
/*@=boundswrite@*/
|
|
|
|
int pgpPrtComment(pgpTag tag, const byte *h, unsigned int hlen)
|
|
{
|
|
int i = hlen;
|
|
|
|
pgpPrtVal("", pgpTagTbl, tag);
|
|
if (_print)
|
|
fprintf(stderr, " ");
|
|
while (i > 0) {
|
|
int j;
|
|
if (*h >= ' ' && *h <= 'z') {
|
|
if (_print)
|
|
fprintf(stderr, "%s", (const char *)h);
|
|
j = strlen(h);
|
|
while (h[j] == '\0')
|
|
j++;
|
|
} else {
|
|
pgpPrtHex("", h, i);
|
|
j = i;
|
|
}
|
|
i -= j;
|
|
h += j;
|
|
}
|
|
pgpPrtNL();
|
|
return 0;
|
|
}
|
|
|
|
int pgpPubkeyFingerprint(const byte * pkt, /*@unused@*/ unsigned int pktlen,
|
|
byte * keyid)
|
|
{
|
|
const byte *s = pkt;
|
|
DIGEST_CTX ctx;
|
|
byte version;
|
|
int rc = -1; /* assume failure. */
|
|
|
|
if (pkt[0] != 0x99)
|
|
return rc;
|
|
version = pkt[3];
|
|
|
|
switch (version) {
|
|
case 3:
|
|
{ pgpPktKeyV3 v = (pgpPktKeyV3) (pkt + 3);
|
|
|
|
s += sizeof(pkt[0]) + sizeof(pkt[1]) + sizeof(pkt[2]) + sizeof(*v);
|
|
switch (v->pubkey_algo) {
|
|
case PGPPUBKEYALGO_RSA:
|
|
s += (pgpMpiLen(s) - 8);
|
|
/*@-boundswrite@*/
|
|
memmove(keyid, s, 8);
|
|
/*@=boundswrite@*/
|
|
rc = 0;
|
|
/*@innerbreak@*/ break;
|
|
default: /* TODO: md5 of mpi bodies (i.e. no length) */
|
|
/*@innerbreak@*/ break;
|
|
}
|
|
} break;
|
|
case 4:
|
|
{ pgpPktKeyV4 v = (pgpPktKeyV4) (pkt + 3);
|
|
byte * SHA1 = NULL;
|
|
int i;
|
|
|
|
s += sizeof(pkt[0]) + sizeof(pkt[1]) + sizeof(pkt[2]) + sizeof(*v);
|
|
switch (v->pubkey_algo) {
|
|
case PGPPUBKEYALGO_RSA:
|
|
for (i = 0; i < 2; i++)
|
|
s += pgpMpiLen(s);
|
|
/*@innerbreak@*/ break;
|
|
case PGPPUBKEYALGO_DSA:
|
|
for (i = 0; i < 4; i++)
|
|
s += pgpMpiLen(s);
|
|
/*@innerbreak@*/ break;
|
|
}
|
|
|
|
ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
|
|
(void) rpmDigestUpdate(ctx, pkt, (s-pkt));
|
|
(void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 0);
|
|
|
|
s = SHA1 + 12;
|
|
/*@-boundswrite@*/
|
|
memmove(keyid, s, 8);
|
|
/*@=boundswrite@*/
|
|
rc = 0;
|
|
|
|
if (SHA1) free(SHA1);
|
|
} break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int pgpPrtPkt(const byte *pkt, unsigned int pleft)
|
|
{
|
|
unsigned int val = *pkt;
|
|
unsigned int pktlen;
|
|
pgpTag tag;
|
|
unsigned int plen;
|
|
const byte *h;
|
|
unsigned int hlen = 0;
|
|
int rc = 0;
|
|
|
|
/* XXX can't deal with these. */
|
|
if (!(val & 0x80))
|
|
return -1;
|
|
|
|
if (val & 0x40) {
|
|
tag = (val & 0x3f);
|
|
plen = pgpLen(pkt+1, &hlen);
|
|
} else {
|
|
tag = (val >> 2) & 0xf;
|
|
plen = (1 << (val & 0x3));
|
|
hlen = pgpGrab(pkt+1, plen);
|
|
}
|
|
|
|
pktlen = 1 + plen + hlen;
|
|
if (pktlen > pleft)
|
|
return -1;
|
|
|
|
h = pkt + 1 + plen;
|
|
switch (tag) {
|
|
case PGPTAG_SIGNATURE:
|
|
rc = pgpPrtSig(tag, h, hlen);
|
|
break;
|
|
case PGPTAG_PUBLIC_KEY:
|
|
/* Get the public key fingerprint. */
|
|
if (_digp) {
|
|
/*@-mods@*/
|
|
if (!pgpPubkeyFingerprint(pkt, pktlen, _digp->signid))
|
|
_digp->saved |= PGPDIG_SAVED_ID;
|
|
else
|
|
memset(_digp->signid, 0, sizeof(_digp->signid));
|
|
/*@=mods@*/
|
|
}
|
|
/*@fallthrough@*/
|
|
case PGPTAG_PUBLIC_SUBKEY:
|
|
rc = pgpPrtKey(tag, h, hlen);
|
|
break;
|
|
case PGPTAG_SECRET_KEY:
|
|
case PGPTAG_SECRET_SUBKEY:
|
|
rc = pgpPrtKey(tag, h, hlen);
|
|
break;
|
|
case PGPTAG_USER_ID:
|
|
rc = pgpPrtUserID(tag, h, hlen);
|
|
break;
|
|
case PGPTAG_COMMENT:
|
|
case PGPTAG_COMMENT_OLD:
|
|
rc = pgpPrtComment(tag, h, hlen);
|
|
break;
|
|
|
|
case PGPTAG_RESERVED:
|
|
case PGPTAG_PUBLIC_SESSION_KEY:
|
|
case PGPTAG_SYMMETRIC_SESSION_KEY:
|
|
case PGPTAG_COMPRESSED_DATA:
|
|
case PGPTAG_SYMMETRIC_DATA:
|
|
case PGPTAG_MARKER:
|
|
case PGPTAG_LITERAL_DATA:
|
|
case PGPTAG_TRUST:
|
|
case PGPTAG_PHOTOID:
|
|
case PGPTAG_ENCRYPTED_MDC:
|
|
case PGPTAG_MDC:
|
|
case PGPTAG_PRIVATE_60:
|
|
case PGPTAG_PRIVATE_62:
|
|
case PGPTAG_CONTROL:
|
|
default:
|
|
pgpPrtVal("", pgpTagTbl, tag);
|
|
pgpPrtHex("", h, hlen);
|
|
pgpPrtNL();
|
|
break;
|
|
}
|
|
|
|
return (rc ? -1 : pktlen);
|
|
}
|
|
|
|
pgpDig pgpNewDig(void)
|
|
{
|
|
pgpDig dig = xcalloc(1, sizeof(*dig));
|
|
return dig;
|
|
}
|
|
|
|
/*@-boundswrite@*/
|
|
void pgpCleanDig(pgpDig dig)
|
|
{
|
|
if (dig != NULL) {
|
|
int i;
|
|
dig->signature.userid = _free(dig->signature.userid);
|
|
dig->pubkey.userid = _free(dig->pubkey.userid);
|
|
dig->signature.hash = _free(dig->signature.hash);
|
|
dig->pubkey.hash = _free(dig->pubkey.hash);
|
|
/*@-unqualifiedtrans@*/ /* FIX: double indirection */
|
|
for (i = 0; i < 4; i++) {
|
|
dig->signature.params[i] = _free(dig->signature.params[i]);
|
|
dig->pubkey.params[i] = _free(dig->pubkey.params[i]);
|
|
}
|
|
/*@=unqualifiedtrans@*/
|
|
|
|
memset(&dig->signature, 0, sizeof(dig->signature));
|
|
memset(&dig->pubkey, 0, sizeof(dig->pubkey));
|
|
|
|
dig->md5 = _free(dig->md5);
|
|
dig->sha1 = _free(dig->sha1);
|
|
mpnfree(&dig->hm);
|
|
mpnfree(&dig->r);
|
|
mpnfree(&dig->s);
|
|
|
|
(void) rsapkFree(&dig->rsa_pk);
|
|
mpnfree(&dig->m);
|
|
mpnfree(&dig->c);
|
|
mpnfree(&dig->rsahm);
|
|
}
|
|
/*@-nullstate@*/
|
|
return;
|
|
/*@=nullstate@*/
|
|
}
|
|
/*@=boundswrite@*/
|
|
|
|
pgpDig pgpFreeDig(/*@only@*/ /*@null@*/ pgpDig dig)
|
|
/*@modifies dig @*/
|
|
{
|
|
if (dig != NULL) {
|
|
|
|
/* DUmp the signature/pubkey data. */
|
|
pgpCleanDig(dig);
|
|
|
|
/*@-branchstate@*/
|
|
if (dig->hdrsha1ctx != NULL)
|
|
(void) rpmDigestFinal(dig->hdrsha1ctx, NULL, NULL, 0);
|
|
/*@=branchstate@*/
|
|
dig->hdrsha1ctx = NULL;
|
|
|
|
/*@-branchstate@*/
|
|
if (dig->sha1ctx != NULL)
|
|
(void) rpmDigestFinal(dig->sha1ctx, NULL, NULL, 0);
|
|
/*@=branchstate@*/
|
|
dig->sha1ctx = NULL;
|
|
|
|
mpbfree(&dig->p);
|
|
mpbfree(&dig->q);
|
|
mpnfree(&dig->g);
|
|
mpnfree(&dig->y);
|
|
mpnfree(&dig->hm);
|
|
mpnfree(&dig->r);
|
|
mpnfree(&dig->s);
|
|
|
|
#ifdef NOTYET
|
|
/*@-branchstate@*/
|
|
if (dig->hdrmd5ctx != NULL)
|
|
(void) rpmDigestFinal(dig->hdrmd5ctx, NULL, NULL, 0);
|
|
/*@=branchstate@*/
|
|
dig->hdrmd5ctx = NULL;
|
|
#endif
|
|
|
|
/*@-branchstate@*/
|
|
if (dig->md5ctx != NULL)
|
|
(void) rpmDigestFinal(dig->md5ctx, NULL, NULL, 0);
|
|
/*@=branchstate@*/
|
|
dig->md5ctx = NULL;
|
|
|
|
mpbfree(&dig->rsa_pk.n);
|
|
mpnfree(&dig->rsa_pk.e);
|
|
mpnfree(&dig->m);
|
|
mpnfree(&dig->c);
|
|
mpnfree(&dig->hm);
|
|
|
|
dig = _free(dig);
|
|
}
|
|
return dig;
|
|
}
|
|
|
|
int pgpPrtPkts(const byte * pkts, unsigned int pktlen, pgpDig dig, int printing)
|
|
/*@globals _dig, _digp, _print @*/
|
|
/*@modifies _dig, _digp, *_digp, _print @*/
|
|
{
|
|
unsigned int val = *pkts;
|
|
const byte *p;
|
|
unsigned int pleft;
|
|
int len;
|
|
|
|
_print = printing;
|
|
_dig = dig;
|
|
if (dig != NULL && (val & 0x80)) {
|
|
pgpTag tag = (val & 0x40) ? (val & 0x3f) : ((val >> 2) & 0xf);
|
|
_digp = (tag == PGPTAG_SIGNATURE) ? &_dig->signature : &_dig->pubkey;
|
|
_digp->tag = tag;
|
|
} else
|
|
_digp = NULL;
|
|
|
|
for (p = pkts, pleft = pktlen; p < (pkts + pktlen); p += len, pleft -= len) {
|
|
len = pgpPrtPkt(p, pleft);
|
|
if (len <= 0)
|
|
return len;
|
|
if (len > pleft) /* XXX shouldn't happen */
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@-boundswrite@*/
|
|
pgpArmor pgpReadPkts(const char * fn, const byte ** pkt, size_t * pktlen)
|
|
{
|
|
const byte * b = NULL;
|
|
ssize_t blen;
|
|
const char * enc = NULL;
|
|
const char * crcenc = NULL;
|
|
byte * dec;
|
|
byte * crcdec;
|
|
size_t declen;
|
|
size_t crclen;
|
|
uint32_t crcpkt, crc;
|
|
const char * armortype = NULL;
|
|
char * t, * te;
|
|
int pstate = 0;
|
|
pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */
|
|
int rc;
|
|
|
|
rc = rpmioSlurp(fn, &b, &blen);
|
|
if (rc || b == NULL || blen <= 0) {
|
|
goto exit;
|
|
}
|
|
|
|
if (pgpIsPkt(b)) {
|
|
#ifdef NOTYET /* XXX ASCII Pubkeys only, please. */
|
|
ec = 0; /* XXX fish out pkt type. */
|
|
#endif
|
|
goto exit;
|
|
}
|
|
|
|
#define TOKEQ(_s, _tok) (!strncmp((_s), (_tok), sizeof(_tok)-1))
|
|
|
|
for (t = (char *)b; t && *t; t = te) {
|
|
if ((te = strchr(t, '\n')) == NULL)
|
|
te = t + strlen(t);
|
|
else
|
|
te++;
|
|
|
|
switch (pstate) {
|
|
case 0:
|
|
armortype = NULL;
|
|
if (!TOKEQ(t, "-----BEGIN PGP "))
|
|
continue;
|
|
t += sizeof("-----BEGIN PGP ")-1;
|
|
|
|
rc = pgpValTok(pgpArmorTbl, t, te);
|
|
if (rc < 0) {
|
|
ec = PGPARMOR_ERR_UNKNOWN_ARMOR_TYPE;
|
|
goto exit;
|
|
}
|
|
if (rc != PGPARMOR_PUBKEY) /* XXX ASCII Pubkeys only, please. */
|
|
continue;
|
|
armortype = t;
|
|
|
|
t = te - (sizeof("-----\n")-1);
|
|
if (!TOKEQ(t, "-----\n"))
|
|
continue;
|
|
*t = '\0';
|
|
pstate++;
|
|
/*@switchbreak@*/ break;
|
|
case 1:
|
|
enc = NULL;
|
|
rc = pgpValTok(pgpArmorKeyTbl, t, te);
|
|
if (rc >= 0)
|
|
continue;
|
|
if (*t != '\n') {
|
|
pstate = 0;
|
|
continue;
|
|
}
|
|
enc = te; /* Start of encoded packets */
|
|
pstate++;
|
|
/*@switchbreak@*/ break;
|
|
case 2:
|
|
crcenc = NULL;
|
|
if (*t != '=')
|
|
continue;
|
|
*t++ = '\0'; /* Terminate encoded packets */
|
|
crcenc = t; /* Start of encoded crc */
|
|
pstate++;
|
|
/*@switchbreak@*/ break;
|
|
case 3:
|
|
pstate = 0;
|
|
if (!TOKEQ(t, "-----END PGP ")) {
|
|
ec = PGPARMOR_ERR_NO_END_PGP;
|
|
goto exit;
|
|
}
|
|
*t = '\0'; /* Terminate encoded crc */
|
|
t += sizeof("-----END PGP ")-1;
|
|
if (t >= te) continue;
|
|
|
|
if (armortype == NULL) /* XXX can't happen */
|
|
continue;
|
|
rc = strncmp(t, armortype, strlen(armortype));
|
|
if (rc)
|
|
continue;
|
|
|
|
t += strlen(armortype);
|
|
if (t >= te) continue;
|
|
|
|
if (!TOKEQ(t, "-----")) {
|
|
ec = PGPARMOR_ERR_NO_END_PGP;
|
|
goto exit;
|
|
}
|
|
t += (sizeof("-----")-1);
|
|
if (t >= te) continue;
|
|
/* XXX permitting \r here is not RFC-2440 compliant <shrug> */
|
|
if (!(*t == '\n' || *t == '\r')) continue;
|
|
|
|
crcdec = NULL;
|
|
crclen = 0;
|
|
if (b64decode(crcenc, (void **)&crcdec, &crclen) != 0) {
|
|
ec = PGPARMOR_ERR_CRC_DECODE;
|
|
goto exit;
|
|
}
|
|
crcpkt = pgpGrab(crcdec, crclen);
|
|
crcdec = _free(crcdec);
|
|
dec = NULL;
|
|
declen = 0;
|
|
if (b64decode(enc, (void **)&dec, &declen) != 0) {
|
|
ec = PGPARMOR_ERR_BODY_DECODE;
|
|
goto exit;
|
|
}
|
|
crc = pgpCRC(dec, declen);
|
|
if (crcpkt != crc) {
|
|
ec = PGPARMOR_ERR_CRC_CHECK;
|
|
goto exit;
|
|
}
|
|
b = _free(b);
|
|
b = dec;
|
|
blen = declen;
|
|
ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */
|
|
goto exit;
|
|
/*@notreached@*/ /*@switchbreak@*/ break;
|
|
}
|
|
}
|
|
ec = PGPARMOR_NONE;
|
|
|
|
exit:
|
|
if (ec > PGPARMOR_NONE && pkt)
|
|
*pkt = b;
|
|
else if (b != NULL)
|
|
b = _free(b);
|
|
if (pktlen)
|
|
*pktlen = blen;
|
|
return ec;
|
|
}
|
|
/*@=boundswrite@*/
|
|
|
|
char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
|
|
{
|
|
const char * enc;
|
|
char * t;
|
|
size_t nt;
|
|
char * val;
|
|
int lc;
|
|
|
|
nt = ((ns + 2) / 3) * 4;
|
|
/*@-globs@*/
|
|
/* Add additional bytes necessary for eol string(s). */
|
|
if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
|
|
lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
|
|
if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
|
|
++lc;
|
|
nt += lc * strlen(b64encode_eolstr);
|
|
}
|
|
/*@=globs@*/
|
|
|
|
nt += 512; /* XXX slop for armor and crc */
|
|
|
|
/*@-boundswrite@*/
|
|
val = t = xmalloc(nt + 1);
|
|
*t = '\0';
|
|
t = stpcpy(t, "-----BEGIN PGP ");
|
|
t = stpcpy(t, pgpValStr(pgpArmorTbl, atype));
|
|
/*@-globs@*/
|
|
t = stpcpy( stpcpy(t, "-----\nVersion: rpm-"), VERSION);
|
|
/*@=globs@*/
|
|
t = stpcpy(t, " (beecrypt-3.0.0)\n\n");
|
|
|
|
if ((enc = b64encode(s, ns)) != NULL) {
|
|
t = stpcpy(t, enc);
|
|
enc = _free(enc);
|
|
if ((enc = b64crc(s, ns)) != NULL) {
|
|
*t++ = '=';
|
|
t = stpcpy(t, enc);
|
|
enc = _free(enc);
|
|
}
|
|
}
|
|
|
|
t = stpcpy(t, "-----END PGP ");
|
|
t = stpcpy(t, pgpValStr(pgpArmorTbl, atype));
|
|
t = stpcpy(t, "-----\n");
|
|
/*@=boundswrite@*/
|
|
|
|
return val;
|
|
}
|
|
|
|
/*@=boundsread@*/
|