summaryrefslogtreecommitdiff
path: root/rpmio
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2022-04-11 15:04:45 +0200
committerPanu Matilainen <pmatilai@redhat.com>2022-04-12 09:48:53 +0300
commitd8bb57eeabe249c2c85bf46b1162d7e57a310e37 (patch)
treed9a2ed7b35cf391efebd31445f7c0ec212968319 /rpmio
parenteaf359f35c6433cfe80fc8814795081b92171be8 (diff)
downloadrpm-d8bb57eeabe249c2c85bf46b1162d7e57a310e37.tar.gz
Move the internal OpenPGP implementation to its own file.
Split the internal OpenPGP implementation into the bits that are needed by a new OpenPGP backend like Sequoia, and the bits that are not needed by another OpenPGP backend. Move most of the functionality in rpmio/rpmpgp.c into rpmio/rpmpgp_internal.c. Leave pgpValStr, and pgpIdentItem, which are used for printing and needn't be reimplemented by other backends, and pgpReadPkts, which is just a thin wrapper around pgpParsePkts, and which uses an internal rpm function that a new backend shouldn't have to worry about emulating or even calling. Move the symbol tables, which are used by pgpValStr, pgpIdentItem, and the internal OpenPGP implementation to rpmio/rpmpgp.h. These are common to all implementations. Fixes #2000.
Diffstat (limited to 'rpmio')
-rw-r--r--rpmio/Makefile.am4
-rw-r--r--rpmio/rpmpgp.c1504
-rw-r--r--rpmio/rpmpgp.h173
-rw-r--r--rpmio/rpmpgp_internal.c1344
4 files changed, 1522 insertions, 1503 deletions
diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am
index 6ff64fa1d..35718cbf8 100644
--- a/rpmio/Makefile.am
+++ b/rpmio/Makefile.am
@@ -20,11 +20,11 @@ usrlib_LTLIBRARIES = librpmio.la
librpmio_la_SOURCES = \
argv.c base64.c digest.h digest.c expression.c macro.c \
rpmhook.c rpmio.c rpmlog.c rpmmalloc.c rgetopt.c \
- rpmpgp.c rpmsq.c rpmsw.c url.c \
+ rpmpgp.c rpmpgp.h rpmsq.c rpmsw.c url.c \
rpmio_internal.h rpmhook.h rpmvercmp.c rpmver.c \
rpmstring.c rpmfileutil.c rpmglob.c \
rpmkeyring.c rpmstrpool.c rpmmacro_internal.h \
- rpmlua.c rpmlua.h lposix.c lposix.h
+ rpmlua.c rpmlua.h lposix.c lposix.h rpmpgp_internal.c
if WITH_OPENSSL
librpmio_la_SOURCES += digest_openssl.c
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index cf827d6d2..efff7ff06 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -9,222 +9,14 @@
#include <netinet/in.h>
#include <rpm/rpmstring.h>
#include <rpm/rpmlog.h>
-#include <rpm/rpmbase64.h>
#include "rpmio/digest.h"
+#include "rpmio/rpmpgp.h"
#include "rpmio/rpmio_internal.h" /* XXX rpmioSlurp */
#include "debug.h"
-static int _print = 0;
-
-/** \ingroup rpmio
- * Values parsed from OpenPGP signature/pubkey packet(s).
- */
-struct pgpDigParams_s {
- char * userid;
- uint8_t * hash;
- uint8_t tag;
-
- uint8_t key_flags; /*!< key usage flags */
- uint8_t version; /*!< version number. */
- uint32_t time; /*!< key/signature creation time. */
- uint8_t pubkey_algo; /*!< public key algorithm. */
-
- uint8_t hash_algo;
- uint8_t sigtype;
- uint32_t hashlen;
- uint8_t signhash16[2];
- pgpKeyID_t signid;
- uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset.
- * `PGPDIG_SIG_HAS_*` are reset for each signature. */
-#define PGPDIG_SAVED_TIME (1 << 0)
-#define PGPDIG_SAVED_ID (1 << 1)
-#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2)
-#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3)
-
- pgpDigAlg alg;
-};
-
-/** \ingroup rpmio
- * Container for values parsed from an OpenPGP signature and public key.
- */
-struct pgpDig_s {
- struct pgpDigParams_s * signature;
- struct pgpDigParams_s * pubkey;
-};
-
-typedef const struct pgpValTbl_s {
- int val;
- char const * const str;
-} * pgpValTbl;
-
-static struct pgpValTbl_s const 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" },
-};
-
-static struct pgpValTbl_s const 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)" },
- { PGPPUBKEYALGO_EDDSA, "EdDSA" },
- { -1, "Unknown public key algorithm" },
-};
-
-static struct pgpValTbl_s const 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" },
-};
-
-static struct pgpValTbl_s const pgpCompressionTbl[] = {
- { PGPCOMPRESSALGO_NONE, "Uncompressed" },
- { PGPCOMPRESSALGO_ZIP, "ZIP" },
- { PGPCOMPRESSALGO_ZLIB, "ZLIB" },
- { PGPCOMPRESSALGO_BZIP2, "BZIP2" },
- { -1, "Unknown compression algorithm" },
-};
-
-static struct pgpValTbl_s const 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" },
- { PGPHASHALGO_SHA224, "SHA224" },
- { -1, "Unknown hash algorithm" },
-};
-
-static struct pgpValTbl_s const pgpKeyServerPrefsTbl[] = {
- { 0x80, "No-modify" },
- { -1, "Unknown key server preference" },
-};
-
-static struct pgpValTbl_s const 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" },
-};
-
-static struct pgpValTbl_s const 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" },
-};
-
-static struct pgpValTbl_s const 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" }
-};
-
-static struct pgpValTbl_s const pgpArmorKeyTbl[] = {
- { PGPARMORKEY_VERSION, "Version: " },
- { PGPARMORKEY_COMMENT, "Comment: " },
- { PGPARMORKEY_MESSAGEID, "MessageID: " },
- { PGPARMORKEY_HASH, "Hash: " },
- { PGPARMORKEY_CHARSET, "Charset: " },
- { -1, "Unknown armor key" }
-};
-
-static void pgpPrtNL(void)
-{
- if (!_print) return;
- fprintf(stderr, "\n");
-}
-
-static const char * pgpValStr(pgpValTbl vs, uint8_t val)
+const char * pgpValStr(pgpValTbl vs, uint8_t val)
{
do {
if (vs->val == val)
@@ -258,1053 +50,6 @@ const char * pgpValString(pgpValType type, uint8_t val)
return (tbl != NULL) ? pgpValStr(tbl, val) : NULL;
}
-static void pgpPrtHex(const char *pre, const uint8_t *p, size_t plen)
-{
- char *hex = NULL;
- if (!_print) return;
- if (pre && *pre)
- fprintf(stderr, "%s", pre);
- hex = rpmhex(p, plen);
- fprintf(stderr, " %s", hex);
- free(hex);
-}
-
-static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val)
-{
- if (!_print) return;
- if (pre && *pre)
- fprintf(stderr, "%s", pre);
- fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
-}
-
-static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen)
-{
- if (!_print) return;
- if (pre && *pre)
- fprintf(stderr, "%s", pre);
- if (plen == 4) {
- char buf[1024];
- time_t t = pgpGrab(p, plen);
- struct tm _tm, *tms = localtime_r(&t, &_tm);
- if (strftime(buf, sizeof(buf), "%c", tms) > 0)
- fprintf(stderr, " %-24.24s(0x%08x)", buf, (unsigned)t);
- } else {
- pgpPrtHex("", p+1, plen-1);
- }
-}
-
-/** \ingroup rpmpgp
- * Return value of an OpenPGP string.
- * @param vs table of (string,value) pairs
- * @param s string token to lookup
- * @param se end-of-string address
- * @return byte value
- */
-static inline
-int pgpValTok(pgpValTbl vs, const char * s, const char * se)
-{
- do {
- size_t vlen = strlen(vs->str);
- if (vlen <= (se-s) && rstreqn(s, vs->str, vlen))
- break;
- } while ((++vs)->val != -1);
- return vs->val;
-}
-
-/** \ingroup rpmpgp
- * Decode length from 1, 2, or 5 octet body length encoding, used in
- * new format packet headers and V4 signature subpackets.
- * Partial body lengths are (intentionally) not supported.
- * @param s pointer to length encoding buffer
- * @param slen buffer size
- * @param[out] *lenp decoded length
- * @return no. of bytes used to encode the length, 0 on error
- */
-static inline
-size_t pgpLen(const uint8_t *s, size_t slen, size_t * lenp)
-{
- size_t dlen = 0;
- size_t lenlen = 0;
-
- /*
- * Callers can only ensure we'll always have the first byte, beyond
- * that the required size is not known until we decode it so we need
- * to check if we have enough bytes to read the size as we go.
- */
- if (*s < 192) {
- lenlen = 1;
- dlen = *s;
- } else if (*s < 224 && slen > 2) {
- lenlen = 2;
- dlen = (((s[0]) - 192) << 8) + s[1] + 192;
- } else if (*s == 255 && slen > 5) {
- lenlen = 5;
- dlen = pgpGrab(s+1, 4);
- }
-
- if (slen - lenlen < dlen)
- lenlen = 0;
-
- if (lenlen)
- *lenp = dlen;
-
- return lenlen;
-}
-
-struct pgpPkt {
- uint8_t tag; /* decoded PGP tag */
- const uint8_t *head; /* pointer to start of packet (header) */
- const uint8_t *body; /* pointer to packet body */
- size_t blen; /* length of body in bytes */
-};
-
-/** \ingroup rpmpgp
- * Read a length field `nbytes` long. Checks that the buffer is big enough to
- * hold `nbytes + *valp` bytes.
- * @param s pointer to read from
- * @param nbytes length of length field
- * @param send pointer past end of buffer
- * @param[out] *valp decoded length
- * @return 0 if buffer can hold `nbytes + *valp` of data,
- * otherwise -1.
- */
-static int pgpGet(const uint8_t *s, size_t nbytes, const uint8_t *send,
- size_t *valp)
-{
- int rc = -1;
-
- *valp = 0;
- if (nbytes <= 4 && send - s >= nbytes) {
- unsigned int val = pgpGrab(s, nbytes);
- if (send - s - nbytes >= val) {
- rc = 0;
- *valp = val;
- }
- }
-
- return rc;
-}
-
-static int decodePkt(const uint8_t *p, size_t plen, struct pgpPkt *pkt)
-{
- int rc = -1; /* assume failure */
-
- /* Valid PGP packet header must always have two or more bytes in it */
- if (p && plen >= 2 && p[0] & 0x80) {
- size_t lenlen = 0;
- size_t hlen = 0;
-
- if (p[0] & 0x40) {
- /* New format packet, body length encoding in second byte */
- lenlen = pgpLen(p+1, plen-1, &pkt->blen);
- pkt->tag = (p[0] & 0x3f);
- } else {
- /* Old format packet, body length encoding in tag byte */
- lenlen = (1 << (p[0] & 0x3));
- /* Reject indefinite length packets and check bounds */
- if (pgpGet(p + 1, lenlen, p + plen, &pkt->blen))
- return rc;
- pkt->tag = (p[0] >> 2) & 0xf;
- }
- hlen = lenlen + 1;
-
- /* Does the packet header and its body fit in our boundaries? */
- if (lenlen && (hlen + pkt->blen <= plen)) {
- pkt->head = p;
- pkt->body = pkt->head + hlen;
- rc = 0;
- }
- }
-
- return rc;
-}
-
-#define CRC24_INIT 0xb704ce
-#define CRC24_POLY 0x1864cfb
-
-/** \ingroup rpmpgp
- * Return CRC of a buffer.
- * @param octets bytes
- * @param len no. of bytes
- * @return crc of buffer
- */
-static inline
-unsigned int pgpCRC(const uint8_t *octets, size_t len)
-{
- unsigned int crc = CRC24_INIT;
- size_t i;
-
- while (len--) {
- crc ^= (*octets++) << 16;
- for (i = 0; i < 8; i++) {
- crc <<= 1;
- if (crc & 0x1000000)
- crc ^= CRC24_POLY;
- }
- }
- return crc & 0xffffff;
-}
-
-static int pgpVersion(const uint8_t *h, size_t hlen, uint8_t *version)
-{
- if (hlen < 1)
- return -1;
-
- *version = h[0];
- return 0;
-}
-
-int pgpSignatureType(pgpDigParams _digp)
-{
- int rc = -1;
-
- if (_digp && _digp->tag == PGPTAG_SIGNATURE)
- rc = _digp->sigtype;
-
- return rc;
-}
-
-static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
- pgpDigParams _digp, int hashed)
-{
- const uint8_t *p = h;
- size_t plen = 0, i;
- int rc = 0;
-
- while (hlen > 0 && rc == 0) {
- int impl = 0;
- i = pgpLen(p, hlen, &plen);
- if (i == 0 || plen < 1 || i + plen > hlen)
- break;
-
- p += i;
- hlen -= i;
-
- pgpPrtVal(" ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL)));
- if (p[0] & PGPSUBTYPE_CRITICAL)
- if (_print)
- fprintf(stderr, " *CRITICAL*");
- switch (*p & ~PGPSUBTYPE_CRITICAL) {
- case PGPSUBTYPE_PREFER_SYMKEY: /* preferred symmetric algorithms */
- for (i = 1; i < plen; i++)
- pgpPrtVal(" ", pgpSymkeyTbl, p[i]);
- break;
- case PGPSUBTYPE_PREFER_HASH: /* preferred hash algorithms */
- for (i = 1; i < plen; i++)
- pgpPrtVal(" ", pgpHashTbl, p[i]);
- break;
- case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */
- for (i = 1; i < plen; i++)
- pgpPrtVal(" ", pgpCompressionTbl, p[i]);
- break;
- case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */
- for (i = 1; i < plen; i++)
- pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
- break;
- case PGPSUBTYPE_SIG_CREATE_TIME: /* signature creation time */
- if (!hashed)
- break; /* RFC 4880 §5.2.3.4 creation time MUST be hashed */
- if (plen-1 != sizeof(_digp->time))
- break; /* other lengths not understood */
- if (_digp->saved & PGPDIG_SIG_HAS_CREATION_TIME)
- return 1; /* duplicate timestamps not allowed */
- impl = *p;
- if (!(_digp->saved & PGPDIG_SAVED_TIME))
- _digp->time = pgpGrab(p+1, sizeof(_digp->time));
- _digp->saved |= PGPDIG_SAVED_TIME | PGPDIG_SIG_HAS_CREATION_TIME;
- break;
- case PGPSUBTYPE_SIG_EXPIRE_TIME:
- case PGPSUBTYPE_KEY_EXPIRE_TIME:
- pgpPrtTime(" ", p+1, plen-1);
- break;
-
- case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */
- impl = *p;
- if (!(_digp->saved & PGPDIG_SAVED_ID) &&
- (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
- {
- if (plen-1 != sizeof(_digp->signid))
- break;
- _digp->saved |= PGPDIG_SAVED_ID;
- memcpy(_digp->signid, p+1, sizeof(_digp->signid));
- }
- case PGPSUBTYPE_KEY_FLAGS: /* Key usage flags */
- /* Subpackets in the unhashed section cannot be trusted */
- if (!hashed)
- break;
- /* Reject duplicate key usage flags */
- if (_digp->saved & PGPDIG_SIG_HAS_KEY_FLAGS)
- return 1;
- impl = *p;
- _digp->saved |= PGPDIG_SIG_HAS_KEY_FLAGS;
- _digp->key_flags = plen >= 2 ? p[1] : 0;
- break;
- 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_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);
- break;
- }
- pgpPrtNL();
-
- if (!impl && (p[0] & PGPSUBTYPE_CRITICAL))
- rc = 1;
-
- p += plen;
- hlen -= plen;
- }
-
- if (hlen != 0)
- rc = 1;
-
- return rc;
-}
-
-pgpDigAlg pgpDigAlgFree(pgpDigAlg alg)
-{
- if (alg) {
- if (alg->free)
- alg->free(alg);
- free(alg);
- }
- return NULL;
-}
-
-static int processMpis(const int mpis, pgpDigAlg sigalg,
- const uint8_t *p, const uint8_t *const pend)
-{
- int i = 0, rc = 1; /* assume failure */
- for (; i < mpis && pend - p >= 2; i++) {
- unsigned int mpil = pgpMpiLen(p);
- if (pend - p < mpil)
- return rc;
- if (sigalg && sigalg->setmpi(sigalg, i, p))
- return rc;
- p += mpil;
- }
-
- /* Does the size and number of MPI's match our expectations? */
- if (p == pend && i == mpis)
- rc = 0;
- return rc;
-}
-
-static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo,
- const uint8_t *p, const uint8_t *h, size_t hlen,
- pgpDigParams sigp)
-{
- const uint8_t * pend = h + hlen;
- pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo);
-
- int rc = processMpis(sigalg->mpis, sigalg, p, pend);
-
- /* We can't handle more than one sig at a time */
- if (rc == 0 && sigp->alg == NULL && sigp->tag == PGPTAG_SIGNATURE)
- sigp->alg = sigalg;
- else
- pgpDigAlgFree(sigalg);
-
- return rc;
-}
-
-static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
- pgpDigParams _digp)
-{
- uint8_t version = 0;
- const uint8_t * p;
- size_t plen;
- int rc = 1;
-
- /* Reset the saved flags */
- _digp->saved &= PGPDIG_SAVED_TIME | PGPDIG_SAVED_ID;
- _digp->key_flags = 0;
-
- if (pgpVersion(h, hlen, &version))
- return rc;
-
- switch (version) {
- case 3:
- { pgpPktSigV3 v = (pgpPktSigV3)h;
-
- if (hlen <= sizeof(*v) || v->hashlen != 5)
- return 1;
-
- pgpPrtVal("V3 ", pgpTagTbl, tag);
- pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
- pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
- pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
- pgpPrtNL();
- pgpPrtTime(" ", v->time, sizeof(v->time));
- 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->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);
- if (!(_digp->saved & PGPDIG_SAVED_TIME))
- _digp->time = pgpGrab(v->time, sizeof(v->time));
- if (!(_digp->saved & PGPDIG_SAVED_ID))
- memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
- _digp->saved = PGPDIG_SAVED_TIME | PGPDIG_SIG_HAS_CREATION_TIME | PGPDIG_SAVED_ID;
- _digp->pubkey_algo = v->pubkey_algo;
- _digp->hash_algo = v->hash_algo;
- memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16));
- }
-
- p = ((uint8_t *)v) + sizeof(*v);
- rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
- } break;
- case 4:
- { pgpPktSigV4 v = (pgpPktSigV4)h;
- const uint8_t *const hend = h + hlen;
-
- if (hlen <= sizeof(*v))
- return 1;
-
- pgpPrtVal("V4 ", pgpTagTbl, tag);
- pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
- pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
- pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
- pgpPrtNL();
-
- p = &v->hashlen[0];
- if (pgpGet(v->hashlen, sizeof(v->hashlen), hend, &plen))
- return 1;
- p += sizeof(v->hashlen);
-
- if ((p + plen) > hend)
- return 1;
-
- if (_digp->pubkey_algo == 0) {
- _digp->hashlen = sizeof(*v) + plen;
- _digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
- }
- if (pgpPrtSubType(p, plen, v->sigtype, _digp, 1))
- return 1;
- p += plen;
-
- if (!(_digp->saved & PGPDIG_SIG_HAS_CREATION_TIME))
- return 1; /* RFC 4880 §5.2.3.4 creation time MUST be hashed */
-
- if (pgpGet(p, 2, hend, &plen))
- return 1;
- p += 2;
-
- if ((p + plen) > hend)
- return 1;
-
- if (pgpPrtSubType(p, plen, v->sigtype, _digp, 0))
- return 1;
- p += plen;
-
- if (h + hlen - p < 2)
- return 1;
- pgpPrtHex(" signhash16", p, 2);
- pgpPrtNL();
-
- if (_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 > hend)
- return 1;
-
- rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
- } break;
- default:
- rpmlog(RPMLOG_WARNING, _("Unsupported version of signature: V%d\n"), version);
- rc = 1;
- break;
- }
- return rc;
-}
-
-static uint8_t curve_oids[] = {
- PGPCURVE_NIST_P_256, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
- PGPCURVE_NIST_P_384, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
- PGPCURVE_NIST_P_521, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
- PGPCURVE_BRAINPOOL_P256R1, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07,
- PGPCURVE_BRAINPOOL_P512R1, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d,
- PGPCURVE_ED25519, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
- PGPCURVE_CURVE25519, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
- 0,
-};
-
-static int pgpCurveByOid(const uint8_t *p, int l)
-{
- uint8_t *curve;
- for (curve = curve_oids; *curve; curve += 2 + curve[1])
- if (l == (int)curve[1] && !memcmp(p, curve + 2, l))
- return (int)curve[0];
- return 0;
-}
-
-static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
- const uint8_t *p, const uint8_t *h, size_t hlen,
- pgpDigParams keyp)
-{
- int rc = 1;
- const uint8_t *pend = h + hlen;
- int curve = 0;
- if (pubkey_algo == PGPPUBKEYALGO_EDDSA) {
- int len = (hlen > 1) ? p[0] : 0;
- if (len == 0 || len == 0xff || len >= hlen)
- goto exit;
- curve = pgpCurveByOid(p + 1, len);
- p += len + 1;
- }
- pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo, curve);
- rc = processMpis(keyalg->mpis, keyalg, p, pend);
-
- /* We can't handle more than one key at a time */
- if (rc == 0 && keyp->alg == NULL && (keyp->tag == PGPTAG_PUBLIC_KEY ||
- keyp->tag == PGPTAG_PUBLIC_SUBKEY))
-
- keyp->alg = keyalg;
- else
- pgpDigAlgFree(keyalg);
-
-exit:
- return rc;
-}
-
-static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
- pgpDigParams _digp)
-{
- uint8_t version = 0;
- const uint8_t * p = NULL;
- int rc = 1;
-
- if (pgpVersion(h, hlen, &version))
- return rc;
-
- /* We only permit V4 keys, V3 keys are long long since deprecated */
- switch (version) {
- case 4:
- { pgpPktKeyV4 v = (pgpPktKeyV4)h;
-
- if (hlen > sizeof(*v)) {
- pgpPrtVal("V4 ", pgpTagTbl, tag);
- pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
- pgpPrtTime(" ", v->time, sizeof(v->time));
- pgpPrtNL();
-
- /* If _digp->hash is not NULL then signature is already loaded */
- if (_digp->hash == NULL) {
- _digp->version = v->version;
- _digp->time = pgpGrab(v->time, sizeof(v->time));
- _digp->pubkey_algo = v->pubkey_algo;
- }
-
- p = ((uint8_t *)v) + sizeof(*v);
- rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp);
- }
- } break;
- default:
- rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), h[0]);
- }
- return rc;
-}
-
-static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen,
- pgpDigParams _digp)
-{
- pgpPrtVal("", pgpTagTbl, tag);
- if (_print)
- fprintf(stderr, " \"%.*s\"", (int)hlen, (const char *)h);
- pgpPrtNL();
- free(_digp->userid);
- _digp->userid = memcpy(xmalloc(hlen+1), h, hlen);
- _digp->userid[hlen] = '\0';
- return 0;
-}
-
-int pgpPubkeyFingerprint(const uint8_t *h, size_t hlen,
- uint8_t **fp, size_t *fplen)
-{
- int rc = -1; /* assume failure */
- const uint8_t *se;
- const uint8_t *pend = h + hlen;
- uint8_t version = 0;
-
- if (pgpVersion(h, hlen, &version))
- return rc;
-
- /* We only permit V4 keys, V3 keys are long long since deprecated */
- switch (version) {
- case 4:
- { pgpPktKeyV4 v = (pgpPktKeyV4) (h);
- int mpis = -1;
-
- /* Packet must be strictly larger than v to have room for the
- * required MPIs and (for EdDSA) the curve ID */
- if (hlen < sizeof(*v) + sizeof(uint8_t))
- return rc;
- se = (uint8_t *)(v + 1);
- switch (v->pubkey_algo) {
- case PGPPUBKEYALGO_EDDSA:
- /* EdDSA has a curve id before the MPIs */
- if (se[0] == 0x00 || se[0] == 0xff || pend - se < 1 + se[0])
- return rc;
- se += 1 + se[0];
- mpis = 1;
- break;
- case PGPPUBKEYALGO_RSA:
- mpis = 2;
- break;
- case PGPPUBKEYALGO_DSA:
- mpis = 4;
- break;
- default:
- return rc;
- }
-
- /* Does the size and number of MPI's match our expectations? */
- if (processMpis(mpis, NULL, se, pend) == 0) {
- DIGEST_CTX ctx = rpmDigestInit(RPM_HASH_SHA1, RPMDIGEST_NONE);
- uint8_t *d = NULL;
- size_t dlen = 0;
- uint8_t in[3] = { 0x99, (hlen >> 8), hlen };
-
- (void) rpmDigestUpdate(ctx, in, 3);
- (void) rpmDigestUpdate(ctx, h, hlen);
- (void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0);
-
- if (dlen == 20) {
- rc = 0;
- *fp = d;
- *fplen = dlen;
- } else {
- free(d);
- }
- }
-
- } break;
- default:
- rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version);
- }
- return rc;
-}
-
-static int getKeyID(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
-{
- uint8_t *fp = NULL;
- size_t fplen = 0;
- int rc = pgpPubkeyFingerprint(h, hlen, &fp, &fplen);
- if (fp && fplen > 8) {
- memcpy(keyid, (fp + (fplen-8)), 8);
- free(fp);
- }
- return rc;
-}
-
-int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid)
-{
- struct pgpPkt p;
-
- if (decodePkt(pkt, pktlen, &p))
- return -1;
-
- return getKeyID(p.body, p.blen, keyid);
-}
-
-static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
-{
- int rc = 0;
-
- switch (p->tag) {
- case PGPTAG_SIGNATURE:
- rc = pgpPrtSig(p->tag, p->body, p->blen, _digp);
- break;
- case PGPTAG_PUBLIC_KEY:
- /* Get the public key Key ID. */
- rc = getKeyID(p->body, p->blen, _digp->signid);
- if (rc)
- memset(_digp->signid, 0, sizeof(_digp->signid));
- else {
- _digp->saved |= PGPDIG_SAVED_ID;
- rc = pgpPrtKey(p->tag, p->body, p->blen, _digp);
- }
- break;
- case PGPTAG_USER_ID:
- rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp);
- break;
- case PGPTAG_RESERVED:
- rc = -1;
- break;
- case PGPTAG_COMMENT:
- case PGPTAG_COMMENT_OLD:
- case PGPTAG_PUBLIC_SUBKEY:
- case PGPTAG_SECRET_KEY:
- case PGPTAG_SECRET_SUBKEY:
- 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, p->tag);
- pgpPrtHex("", p->body, p->blen);
- pgpPrtNL();
- break;
- }
-
- return rc;
-}
-
-pgpDigParams pgpDigParamsFree(pgpDigParams digp)
-{
- if (digp) {
- pgpDigAlgFree(digp->alg);
- free(digp->userid);
- free(digp->hash);
- memset(digp, 0, sizeof(*digp));
- free(digp);
- }
- return NULL;
-}
-
-int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2)
-{
- int rc = 1; /* assume different, eg if either is NULL */
- if (p1 && p2) {
- /* XXX Should we compare something else too? */
- if (p1->tag != p2->tag)
- goto exit;
- if (p1->hash_algo != p2->hash_algo)
- goto exit;
- if (p1->pubkey_algo != p2->pubkey_algo)
- goto exit;
- if (p1->version != p2->version)
- goto exit;
- if (p1->sigtype != p2->sigtype)
- goto exit;
- if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0)
- goto exit;
- if (p1->userid && p2->userid && strcmp(p1->userid, p2->userid) != 0)
- goto exit;
-
- /* Parameters match ... at least for our purposes */
- rc = 0;
- }
-exit:
- return rc;
-}
-
-unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
-{
- unsigned int algo = 0; /* assume failure */
- if (digp) {
- switch (algotype) {
- case PGPVAL_PUBKEYALGO:
- algo = digp->pubkey_algo;
- break;
- case PGPVAL_HASHALGO:
- algo = digp->hash_algo;
- break;
- }
- }
- return algo;
-}
-
-const uint8_t *pgpDigParamsSignID(pgpDigParams digp)
-{
- return digp->signid;
-}
-
-const char *pgpDigParamsUserID(pgpDigParams digp)
-{
- return digp->userid;
-}
-
-int pgpDigParamsVersion(pgpDigParams digp)
-{
- return digp->version;
-}
-
-uint32_t pgpDigParamsCreationTime(pgpDigParams digp)
-{
- return digp->time;
-}
-
-static pgpDigParams pgpDigParamsNew(uint8_t tag)
-{
- pgpDigParams digp = xcalloc(1, sizeof(*digp));
- digp->tag = tag;
- return digp;
-}
-
-static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag)
-{
- int rc = -1;
- if (pkt->tag == exptag) {
- uint8_t head[] = {
- 0x99,
- (pkt->blen >> 8),
- (pkt->blen ),
- };
-
- rpmDigestUpdate(hash, head, 3);
- rpmDigestUpdate(hash, pkt->body, pkt->blen);
- rc = 0;
- }
- return rc;
-}
-
-static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig,
- const struct pgpPkt *all, int i)
-{
- int rc = -1;
- DIGEST_CTX hash = NULL;
-
- switch (selfsig->sigtype) {
- case PGPSIGTYPE_SUBKEY_BINDING:
- hash = rpmDigestInit(selfsig->hash_algo, 0);
- if (hash) {
- rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY);
- if (!rc)
- rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY);
- }
- break;
- default:
- /* ignore types we can't handle */
- rc = 0;
- break;
- }
-
- if (hash && rc == 0)
- rc = pgpVerifySignature(key, selfsig, hash);
-
- rpmDigestFinal(hash, NULL, NULL, 0);
-
- return rc;
-}
-
-static int parseSubkeySig(const struct pgpPkt *pkt, uint8_t tag,
- pgpDigParams *params_p) {
- pgpDigParams params = *params_p = NULL; /* assume failure */
-
- if (pkt->tag != PGPTAG_SIGNATURE)
- goto fail;
-
- params = pgpDigParamsNew(tag);
-
- if (pgpPrtSig(tag, pkt->body, pkt->blen, params))
- goto fail;
-
- if (params->sigtype != PGPSIGTYPE_SUBKEY_BINDING &&
- params->sigtype != PGPSIGTYPE_SUBKEY_REVOKE)
- {
- goto fail;
- }
-
- *params_p = params;
- return 0;
-fail:
- pgpDigParamsFree(params);
- return -1;
-}
-
-static const size_t RPM_MAX_OPENPGP_BYTES = 65535; /* max number of bytes in a key */
-
-int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
- pgpDigParams * ret)
-{
- const uint8_t *p = pkts;
- const uint8_t *pend = pkts + pktlen;
- pgpDigParams digp = NULL;
- pgpDigParams selfsig = NULL;
- int i = 0;
- int alloced = 16; /* plenty for normal cases */
- int rc = -1; /* assume failure */
- int expect = 0;
- int prevtag = 0;
-
- if (pktlen > RPM_MAX_OPENPGP_BYTES)
- return rc; /* reject absurdly large data */
-
- struct pgpPkt *all = xmalloc(alloced * sizeof(*all));
- while (p < pend) {
- struct pgpPkt *pkt = &all[i];
- if (decodePkt(p, (pend - p), pkt))
- break;
-
- if (digp == NULL) {
- if (pkttype && pkt->tag != pkttype) {
- break;
- } else {
- digp = pgpDigParamsNew(pkt->tag);
- }
- }
-
- if (expect) {
- if (pkt->tag != expect)
- break;
- selfsig = pgpDigParamsNew(pkt->tag);
- }
-
- if (pgpPrtPkt(pkt, selfsig ? selfsig : digp))
- break;
-
- if (selfsig) {
- /* subkeys must be followed by binding signature */
- int xx = 1; /* assume failure */
-
- if (!(prevtag == PGPTAG_PUBLIC_SUBKEY &&
- selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING))
- xx = pgpVerifySelf(digp, selfsig, all, i);
-
- selfsig = pgpDigParamsFree(selfsig);
- if (xx)
- break;
- expect = 0;
- }
-
- if (pkt->tag == PGPTAG_PUBLIC_SUBKEY)
- expect = PGPTAG_SIGNATURE;
- prevtag = pkt->tag;
-
- i++;
- p += (pkt->body - pkt->head) + pkt->blen;
- if (pkttype == PGPTAG_SIGNATURE)
- break;
-
- if (alloced <= i) {
- alloced *= 2;
- all = xrealloc(all, alloced * sizeof(*all));
- }
- }
-
- rc = (digp && (p == pend) && expect == 0) ? 0 : -1;
-
- free(all);
- selfsig = pgpDigParamsFree(selfsig);
- if (ret && rc == 0) {
- *ret = digp;
- } else {
- pgpDigParamsFree(digp);
- }
- return rc;
-}
-
-int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen,
- pgpDigParams mainkey, pgpDigParams **subkeys,
- int *subkeysCount)
-{
- const uint8_t *p = pkts;
- const uint8_t *pend = pkts + pktlen;
- pgpDigParams *digps = NULL;
- int count = 0;
- int alloced = 10;
- struct pgpPkt pkt;
- int rc, i;
-
- digps = xmalloc(alloced * sizeof(*digps));
-
- while (p < pend) {
- if (decodePkt(p, (pend - p), &pkt))
- break;
-
- p += (pkt.body - pkt.head) + pkt.blen;
-
- if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) {
- if (count == alloced) {
- alloced <<= 1;
- digps = xrealloc(digps, alloced * sizeof(*digps));
- }
-
- digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY);
- /* Copy UID from main key to subkey */
- digps[count]->userid = xstrdup(mainkey->userid);
-
- if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) {
- pgpDigParamsFree(digps[count]);
- continue;
- }
-
- if (pgpPrtKey(pkt.tag, pkt.body, pkt.blen, digps[count])) {
- pgpDigParamsFree(digps[count]);
- continue;
- }
-
- pgpDigParams subkey_sig = NULL;
- if (decodePkt(p, pend - p, &pkt) ||
- parseSubkeySig(&pkt, 0, &subkey_sig))
- {
- pgpDigParamsFree(digps[count]);
- break;
- }
-
- /* Is the subkey revoked or incapable of signing? */
- int ignore = subkey_sig->sigtype != PGPSIGTYPE_SUBKEY_BINDING ||
- !((subkey_sig->saved & PGPDIG_SIG_HAS_KEY_FLAGS) &&
- (subkey_sig->key_flags & 0x02));
- if (ignore) {
- pgpDigParamsFree(digps[count]);
- } else {
- digps[count]->key_flags = subkey_sig->key_flags;
- digps[count]->saved |= PGPDIG_SIG_HAS_KEY_FLAGS;
- count++;
- }
- p += (pkt.body - pkt.head) + pkt.blen;
- pgpDigParamsFree(subkey_sig);
- }
- }
- rc = (p == pend) ? 0 : -1;
-
- if (rc == 0) {
- *subkeys = xrealloc(digps, count * sizeof(*digps));
- *subkeysCount = count;
- } else {
- for (i = 0; i < count; i++)
- pgpDigParamsFree(digps[i]);
- free(digps);
- }
-
- return rc;
-}
-
char *pgpIdentItem(pgpDigParams digp)
{
char *id = NULL;
@@ -1325,193 +70,6 @@ char *pgpIdentItem(pgpDigParams digp)
return id;
}
-rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
-{
- DIGEST_CTX ctx = rpmDigestDup(hashctx);
- uint8_t *hash = NULL;
- size_t hashlen = 0;
- rpmRC res = RPMRC_FAIL; /* assume failure */
-
- if (sig == NULL || ctx == NULL)
- goto exit;
-
- if (sig->hash != NULL)
- rpmDigestUpdate(ctx, sig->hash, sig->hashlen);
-
- if (sig->version == 4) {
- /* V4 trailer is six octets long (rfc4880) */
- uint8_t trailer[6];
- uint32_t nb = sig->hashlen;
- nb = htonl(nb);
- trailer[0] = sig->version;
- trailer[1] = 0xff;
- memcpy(trailer+2, &nb, 4);
- rpmDigestUpdate(ctx, trailer, sizeof(trailer));
- }
-
- rpmDigestFinal(ctx, (void **)&hash, &hashlen, 0);
- ctx = NULL;
-
- /* Compare leading 16 bits of digest for quick check. */
- if (hash == NULL || memcmp(hash, sig->signhash16, 2) != 0)
- goto exit;
-
- /*
- * If we have a key, verify the signature for real. Otherwise we've
- * done all we can, return NOKEY to indicate "looks okay but dunno."
- */
- if (key && key->alg) {
- pgpDigAlg sa = sig->alg;
- pgpDigAlg ka = key->alg;
- if (sa && sa->verify) {
- if (sa->verify(ka, sa, hash, hashlen, sig->hash_algo) == 0) {
- res = RPMRC_OK;
- }
- }
- } else {
- res = RPMRC_NOKEY;
- }
-
-exit:
- free(hash);
- rpmDigestFinal(ctx, NULL, NULL, 0);
- return res;
-
-}
-
-static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen)
-{
- const char * enc = NULL;
- const char * crcenc = NULL;
- uint8_t * dec;
- uint8_t * 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 */
-
-#define TOKEQ(_s, _tok) (rstreqn((_s), (_tok), sizeof(_tok)-1))
-
- for (t = (char *)b; t && *t; t = te) {
- int rc;
- 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 = pgpValStr(pgpArmorTbl, rc);
- t += strlen(armortype);
- if (!TOKEQ(t, "-----"))
- continue;
- t += sizeof("-----")-1;
- if (*t != '\n' && *t != '\r')
- continue;
- *t = '\0';
- pstate++;
- break;
- case 1:
- enc = NULL;
- rc = pgpValTok(pgpArmorKeyTbl, t, te);
- if (rc >= 0)
- continue;
- if (*t != '\n' && *t != '\r') {
- pstate = 0;
- continue;
- }
- enc = te; /* Start of encoded packets */
- pstate++;
- break;
- case 2:
- crcenc = NULL;
- if (*t != '=')
- continue;
- *t++ = '\0'; /* Terminate encoded packets */
- crcenc = t; /* Start of encoded crc */
- pstate++;
- 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;
- if (!rstreqn(t, armortype, strlen(armortype)))
- continue;
-
- t += strlen(armortype);
- if (t >= te) continue;
-
- if (!TOKEQ(t, "-----")) {
- ec = PGPARMOR_ERR_NO_END_PGP;
- goto exit;
- }
- t += (sizeof("-----")-1);
- /* Handle EOF without EOL here, *t == '\0' at EOF */
- if (*t && (t >= te)) continue;
- /* XXX permitting \r here is not RFC-2440 compliant <shrug> */
- if (!(*t == '\n' || *t == '\r' || *t == '\0')) continue;
-
- crcdec = NULL;
- crclen = 0;
- if (rpmBase64Decode(crcenc, (void **)&crcdec, &crclen) != 0 || crclen != 3) {
- crcdec = _free(crcdec);
- ec = PGPARMOR_ERR_CRC_DECODE;
- goto exit;
- }
- crcpkt = pgpGrab(crcdec, crclen);
- crcdec = _free(crcdec);
- dec = NULL;
- declen = 0;
- if (rpmBase64Decode(enc, (void **)&dec, &declen) != 0) {
- ec = PGPARMOR_ERR_BODY_DECODE;
- goto exit;
- }
- crc = pgpCRC(dec, declen);
- if (crcpkt != crc) {
- ec = PGPARMOR_ERR_CRC_CHECK;
- _free(dec);
- goto exit;
- }
- if (pkt)
- *pkt = dec;
- else
- _free(dec);
- if (pktlen) *pktlen = declen;
- ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */
- goto exit;
- break;
- }
- }
- ec = PGPARMOR_NONE;
-
-exit:
- return ec;
-}
-
pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen)
{
uint8_t * b = NULL;
@@ -1519,64 +77,8 @@ pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen)
pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */
int rc = rpmioSlurp(fn, &b, &blen);
if (rc == 0 && b != NULL && blen > 0) {
- ec = decodePkts(b, pkt, pktlen);
+ ec = pgpParsePkts((const char *) b, pkt, pktlen);
}
free(b);
return ec;
}
-
-pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen)
-{
- pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */
- if (armor && strlen(armor) > 0) {
- uint8_t *b = (uint8_t*) xstrdup(armor);
- ec = decodePkts(b, pkt, pktlen);
- free(b);
- }
- return ec;
-}
-
-int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen)
-{
- const uint8_t *p = pkts;
- const uint8_t *pend = pkts + pktslen;
- struct pgpPkt pkt;
-
- while (p < pend) {
- if (decodePkt(p, (pend - p), &pkt))
- return -1;
-
- if (pkt.tag == PGPTAG_PUBLIC_KEY && pkts != p) {
- *certlen = p - pkts;
- return 0;
- }
-
- p += (pkt.body - pkt.head) + pkt.blen;
- }
-
- *certlen = pktslen;
-
- return 0;
-}
-
-char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
-{
- char *buf = NULL, *val = NULL;
- char *enc = rpmBase64Encode(s, ns, -1);
- char *crc = rpmBase64CRC(s, ns);
- const char *valstr = pgpValStr(pgpArmorTbl, atype);
-
- if (crc != NULL && enc != NULL) {
- rasprintf(&buf, "%s=%s", enc, crc);
- }
- free(crc);
- free(enc);
-
- rasprintf(&val, "-----BEGIN PGP %s-----\nVersion: rpm-" VERSION"\n\n"
- "%s\n-----END PGP %s-----\n",
- valstr, buf != NULL ? buf : "", valstr);
-
- free(buf);
- return val;
-}
-
diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h
new file mode 100644
index 000000000..0641f0803
--- /dev/null
+++ b/rpmio/rpmpgp.h
@@ -0,0 +1,173 @@
+#ifndef _RPMPGP_INTERNAL_H
+#define _RPMPGP_INTERNAL_H
+
+#include <rpm/rpmpgp.h>
+
+typedef const struct pgpValTbl_s {
+ int val;
+ char const * const str;
+} * pgpValTbl;
+
+const char * pgpValStr(pgpValTbl vs, uint8_t val);
+
+
+static struct pgpValTbl_s const 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" },
+};
+
+static struct pgpValTbl_s const 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)" },
+ { PGPPUBKEYALGO_EDDSA, "EdDSA" },
+ { -1, "Unknown public key algorithm" },
+};
+
+static struct pgpValTbl_s const 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" },
+};
+
+static struct pgpValTbl_s const pgpCompressionTbl[] = {
+ { PGPCOMPRESSALGO_NONE, "Uncompressed" },
+ { PGPCOMPRESSALGO_ZIP, "ZIP" },
+ { PGPCOMPRESSALGO_ZLIB, "ZLIB" },
+ { PGPCOMPRESSALGO_BZIP2, "BZIP2" },
+ { -1, "Unknown compression algorithm" },
+};
+
+static struct pgpValTbl_s const 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" },
+ { PGPHASHALGO_SHA224, "SHA224" },
+ { -1, "Unknown hash algorithm" },
+};
+
+static struct pgpValTbl_s const pgpKeyServerPrefsTbl[] = {
+ { 0x80, "No-modify" },
+ { -1, "Unknown key server preference" },
+};
+
+static struct pgpValTbl_s const 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" },
+};
+
+static struct pgpValTbl_s const 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" },
+};
+
+static struct pgpValTbl_s const 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" }
+};
+
+static struct pgpValTbl_s const pgpArmorKeyTbl[] = {
+ { PGPARMORKEY_VERSION, "Version: " },
+ { PGPARMORKEY_COMMENT, "Comment: " },
+ { PGPARMORKEY_MESSAGEID, "MessageID: " },
+ { PGPARMORKEY_HASH, "Hash: " },
+ { PGPARMORKEY_CHARSET, "Charset: " },
+ { -1, "Unknown armor key" }
+};
+
+#endif /* _RPMPGP_INTERNAL_H */
diff --git a/rpmio/rpmpgp_internal.c b/rpmio/rpmpgp_internal.c
new file mode 100644
index 000000000..a4edefc8b
--- /dev/null
+++ b/rpmio/rpmpgp_internal.c
@@ -0,0 +1,1344 @@
+/** \ingroup rpmio signature
+ * \file rpmio/rpmpgp_internal.c
+ * Routines to handle RFC-2440 detached signatures.
+ */
+
+#include "system.h"
+
+#include <time.h>
+#include <netinet/in.h>
+#include <rpm/rpmstring.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmbase64.h>
+
+#include "rpmio/digest.h"
+#include "rpmio/rpmpgp.h"
+#include "rpmio/rpmio_internal.h" /* XXX rpmioSlurp */
+
+#include "debug.h"
+
+static int _print = 0;
+
+/** \ingroup rpmio
+ * Values parsed from OpenPGP signature/pubkey packet(s).
+ */
+struct pgpDigParams_s {
+ char * userid;
+ uint8_t * hash;
+ uint8_t tag;
+
+ uint8_t key_flags; /*!< key usage flags */
+ uint8_t version; /*!< version number. */
+ uint32_t time; /*!< key/signature creation time. */
+ uint8_t pubkey_algo; /*!< public key algorithm. */
+
+ uint8_t hash_algo;
+ uint8_t sigtype;
+ uint32_t hashlen;
+ uint8_t signhash16[2];
+ pgpKeyID_t signid;
+ uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset.
+ * `PGPDIG_SIG_HAS_*` are reset for each signature. */
+#define PGPDIG_SAVED_TIME (1 << 0)
+#define PGPDIG_SAVED_ID (1 << 1)
+#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2)
+#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3)
+
+ pgpDigAlg alg;
+};
+
+static void pgpPrtNL(void)
+{
+ if (!_print) return;
+ fprintf(stderr, "\n");
+}
+
+static void pgpPrtHex(const char *pre, const uint8_t *p, size_t plen)
+{
+ char *hex = NULL;
+ if (!_print) return;
+ if (pre && *pre)
+ fprintf(stderr, "%s", pre);
+ hex = rpmhex(p, plen);
+ fprintf(stderr, " %s", hex);
+ free(hex);
+}
+
+static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val)
+{
+ if (!_print) return;
+ if (pre && *pre)
+ fprintf(stderr, "%s", pre);
+ fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
+}
+
+static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen)
+{
+ if (!_print) return;
+ if (pre && *pre)
+ fprintf(stderr, "%s", pre);
+ if (plen == 4) {
+ char buf[1024];
+ time_t t = pgpGrab(p, plen);
+ struct tm _tm, *tms = localtime_r(&t, &_tm);
+ if (strftime(buf, sizeof(buf), "%c", tms) > 0)
+ fprintf(stderr, " %-24.24s(0x%08x)", buf, (unsigned)t);
+ } else {
+ pgpPrtHex("", p+1, plen-1);
+ }
+}
+
+/** \ingroup rpmpgp
+ * Return value of an OpenPGP string.
+ * @param vs table of (string,value) pairs
+ * @param s string token to lookup
+ * @param se end-of-string address
+ * @return byte value
+ */
+static inline
+int pgpValTok(pgpValTbl vs, const char * s, const char * se)
+{
+ do {
+ size_t vlen = strlen(vs->str);
+ if (vlen <= (se-s) && rstreqn(s, vs->str, vlen))
+ break;
+ } while ((++vs)->val != -1);
+ return vs->val;
+}
+
+/** \ingroup rpmpgp
+ * Decode length from 1, 2, or 5 octet body length encoding, used in
+ * new format packet headers and V4 signature subpackets.
+ * Partial body lengths are (intentionally) not supported.
+ * @param s pointer to length encoding buffer
+ * @param slen buffer size
+ * @param[out] *lenp decoded length
+ * @return no. of bytes used to encode the length, 0 on error
+ */
+static inline
+size_t pgpLen(const uint8_t *s, size_t slen, size_t * lenp)
+{
+ size_t dlen = 0;
+ size_t lenlen = 0;
+
+ /*
+ * Callers can only ensure we'll always have the first byte, beyond
+ * that the required size is not known until we decode it so we need
+ * to check if we have enough bytes to read the size as we go.
+ */
+ if (*s < 192) {
+ lenlen = 1;
+ dlen = *s;
+ } else if (*s < 224 && slen > 2) {
+ lenlen = 2;
+ dlen = (((s[0]) - 192) << 8) + s[1] + 192;
+ } else if (*s == 255 && slen > 5) {
+ lenlen = 5;
+ dlen = pgpGrab(s+1, 4);
+ }
+
+ if (slen - lenlen < dlen)
+ lenlen = 0;
+
+ if (lenlen)
+ *lenp = dlen;
+
+ return lenlen;
+}
+
+struct pgpPkt {
+ uint8_t tag; /* decoded PGP tag */
+ const uint8_t *head; /* pointer to start of packet (header) */
+ const uint8_t *body; /* pointer to packet body */
+ size_t blen; /* length of body in bytes */
+};
+
+/** \ingroup rpmpgp
+ * Read a length field `nbytes` long. Checks that the buffer is big enough to
+ * hold `nbytes + *valp` bytes.
+ * @param s pointer to read from
+ * @param nbytes length of length field
+ * @param send pointer past end of buffer
+ * @param[out] *valp decoded length
+ * @return 0 if buffer can hold `nbytes + *valp` of data,
+ * otherwise -1.
+ */
+static int pgpGet(const uint8_t *s, size_t nbytes, const uint8_t *send,
+ size_t *valp)
+{
+ int rc = -1;
+
+ *valp = 0;
+ if (nbytes <= 4 && send - s >= nbytes) {
+ unsigned int val = pgpGrab(s, nbytes);
+ if (send - s - nbytes >= val) {
+ rc = 0;
+ *valp = val;
+ }
+ }
+
+ return rc;
+}
+
+static int decodePkt(const uint8_t *p, size_t plen, struct pgpPkt *pkt)
+{
+ int rc = -1; /* assume failure */
+
+ /* Valid PGP packet header must always have two or more bytes in it */
+ if (p && plen >= 2 && p[0] & 0x80) {
+ size_t lenlen = 0;
+ size_t hlen = 0;
+
+ if (p[0] & 0x40) {
+ /* New format packet, body length encoding in second byte */
+ lenlen = pgpLen(p+1, plen-1, &pkt->blen);
+ pkt->tag = (p[0] & 0x3f);
+ } else {
+ /* Old format packet, body length encoding in tag byte */
+ lenlen = (1 << (p[0] & 0x3));
+ /* Reject indefinite length packets and check bounds */
+ if (pgpGet(p + 1, lenlen, p + plen, &pkt->blen))
+ return rc;
+ pkt->tag = (p[0] >> 2) & 0xf;
+ }
+ hlen = lenlen + 1;
+
+ /* Does the packet header and its body fit in our boundaries? */
+ if (lenlen && (hlen + pkt->blen <= plen)) {
+ pkt->head = p;
+ pkt->body = pkt->head + hlen;
+ rc = 0;
+ }
+ }
+
+ return rc;
+}
+
+#define CRC24_INIT 0xb704ce
+#define CRC24_POLY 0x1864cfb
+
+/** \ingroup rpmpgp
+ * Return CRC of a buffer.
+ * @param octets bytes
+ * @param len no. of bytes
+ * @return crc of buffer
+ */
+static inline
+unsigned int pgpCRC(const uint8_t *octets, size_t len)
+{
+ unsigned int crc = CRC24_INIT;
+ size_t i;
+
+ while (len--) {
+ crc ^= (*octets++) << 16;
+ for (i = 0; i < 8; i++) {
+ crc <<= 1;
+ if (crc & 0x1000000)
+ crc ^= CRC24_POLY;
+ }
+ }
+ return crc & 0xffffff;
+}
+
+static int pgpVersion(const uint8_t *h, size_t hlen, uint8_t *version)
+{
+ if (hlen < 1)
+ return -1;
+
+ *version = h[0];
+ return 0;
+}
+
+int pgpSignatureType(pgpDigParams _digp)
+{
+ int rc = -1;
+
+ if (_digp && _digp->tag == PGPTAG_SIGNATURE)
+ rc = _digp->sigtype;
+
+ return rc;
+}
+
+static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
+ pgpDigParams _digp, int hashed)
+{
+ const uint8_t *p = h;
+ size_t plen = 0, i;
+ int rc = 0;
+
+ while (hlen > 0 && rc == 0) {
+ int impl = 0;
+ i = pgpLen(p, hlen, &plen);
+ if (i == 0 || plen < 1 || i + plen > hlen)
+ break;
+
+ p += i;
+ hlen -= i;
+
+ pgpPrtVal(" ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL)));
+ if (p[0] & PGPSUBTYPE_CRITICAL)
+ if (_print)
+ fprintf(stderr, " *CRITICAL*");
+ switch (*p & ~PGPSUBTYPE_CRITICAL) {
+ case PGPSUBTYPE_PREFER_SYMKEY: /* preferred symmetric algorithms */
+ for (i = 1; i < plen; i++)
+ pgpPrtVal(" ", pgpSymkeyTbl, p[i]);
+ break;
+ case PGPSUBTYPE_PREFER_HASH: /* preferred hash algorithms */
+ for (i = 1; i < plen; i++)
+ pgpPrtVal(" ", pgpHashTbl, p[i]);
+ break;
+ case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */
+ for (i = 1; i < plen; i++)
+ pgpPrtVal(" ", pgpCompressionTbl, p[i]);
+ break;
+ case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */
+ for (i = 1; i < plen; i++)
+ pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
+ break;
+ case PGPSUBTYPE_SIG_CREATE_TIME: /* signature creation time */
+ if (!hashed)
+ break; /* RFC 4880 §5.2.3.4 creation time MUST be hashed */
+ if (plen-1 != sizeof(_digp->time))
+ break; /* other lengths not understood */
+ if (_digp->saved & PGPDIG_SIG_HAS_CREATION_TIME)
+ return 1; /* duplicate timestamps not allowed */
+ impl = *p;
+ if (!(_digp->saved & PGPDIG_SAVED_TIME))
+ _digp->time = pgpGrab(p+1, sizeof(_digp->time));
+ _digp->saved |= PGPDIG_SAVED_TIME | PGPDIG_SIG_HAS_CREATION_TIME;
+ break;
+ case PGPSUBTYPE_SIG_EXPIRE_TIME:
+ case PGPSUBTYPE_KEY_EXPIRE_TIME:
+ pgpPrtTime(" ", p+1, plen-1);
+ break;
+
+ case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */
+ impl = *p;
+ if (!(_digp->saved & PGPDIG_SAVED_ID) &&
+ (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
+ {
+ if (plen-1 != sizeof(_digp->signid))
+ break;
+ _digp->saved |= PGPDIG_SAVED_ID;
+ memcpy(_digp->signid, p+1, sizeof(_digp->signid));
+ }
+ case PGPSUBTYPE_KEY_FLAGS: /* Key usage flags */
+ /* Subpackets in the unhashed section cannot be trusted */
+ if (!hashed)
+ break;
+ /* Reject duplicate key usage flags */
+ if (_digp->saved & PGPDIG_SIG_HAS_KEY_FLAGS)
+ return 1;
+ impl = *p;
+ _digp->saved |= PGPDIG_SIG_HAS_KEY_FLAGS;
+ _digp->key_flags = plen >= 2 ? p[1] : 0;
+ break;
+ 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_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);
+ break;
+ }
+ pgpPrtNL();
+
+ if (!impl && (p[0] & PGPSUBTYPE_CRITICAL))
+ rc = 1;
+
+ p += plen;
+ hlen -= plen;
+ }
+
+ if (hlen != 0)
+ rc = 1;
+
+ return rc;
+}
+
+pgpDigAlg pgpDigAlgFree(pgpDigAlg alg)
+{
+ if (alg) {
+ if (alg->free)
+ alg->free(alg);
+ free(alg);
+ }
+ return NULL;
+}
+
+static int processMpis(const int mpis, pgpDigAlg sigalg,
+ const uint8_t *p, const uint8_t *const pend)
+{
+ int i = 0, rc = 1; /* assume failure */
+ for (; i < mpis && pend - p >= 2; i++) {
+ unsigned int mpil = pgpMpiLen(p);
+ if (pend - p < mpil)
+ return rc;
+ if (sigalg && sigalg->setmpi(sigalg, i, p))
+ return rc;
+ p += mpil;
+ }
+
+ /* Does the size and number of MPI's match our expectations? */
+ if (p == pend && i == mpis)
+ rc = 0;
+ return rc;
+}
+
+static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo,
+ const uint8_t *p, const uint8_t *h, size_t hlen,
+ pgpDigParams sigp)
+{
+ const uint8_t * pend = h + hlen;
+ pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo);
+
+ int rc = processMpis(sigalg->mpis, sigalg, p, pend);
+
+ /* We can't handle more than one sig at a time */
+ if (rc == 0 && sigp->alg == NULL && sigp->tag == PGPTAG_SIGNATURE)
+ sigp->alg = sigalg;
+ else
+ pgpDigAlgFree(sigalg);
+
+ return rc;
+}
+
+static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
+ pgpDigParams _digp)
+{
+ uint8_t version = 0;
+ const uint8_t * p;
+ size_t plen;
+ int rc = 1;
+
+ /* Reset the saved flags */
+ _digp->saved &= PGPDIG_SAVED_TIME | PGPDIG_SAVED_ID;
+ _digp->key_flags = 0;
+
+ if (pgpVersion(h, hlen, &version))
+ return rc;
+
+ switch (version) {
+ case 3:
+ { pgpPktSigV3 v = (pgpPktSigV3)h;
+
+ if (hlen <= sizeof(*v) || v->hashlen != 5)
+ return 1;
+
+ pgpPrtVal("V3 ", pgpTagTbl, tag);
+ pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
+ pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
+ pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
+ pgpPrtNL();
+ pgpPrtTime(" ", v->time, sizeof(v->time));
+ 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->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);
+ if (!(_digp->saved & PGPDIG_SAVED_TIME))
+ _digp->time = pgpGrab(v->time, sizeof(v->time));
+ if (!(_digp->saved & PGPDIG_SAVED_ID))
+ memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
+ _digp->saved = PGPDIG_SAVED_TIME | PGPDIG_SIG_HAS_CREATION_TIME | PGPDIG_SAVED_ID;
+ _digp->pubkey_algo = v->pubkey_algo;
+ _digp->hash_algo = v->hash_algo;
+ memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16));
+ }
+
+ p = ((uint8_t *)v) + sizeof(*v);
+ rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
+ } break;
+ case 4:
+ { pgpPktSigV4 v = (pgpPktSigV4)h;
+ const uint8_t *const hend = h + hlen;
+
+ if (hlen <= sizeof(*v))
+ return 1;
+
+ pgpPrtVal("V4 ", pgpTagTbl, tag);
+ pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
+ pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
+ pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
+ pgpPrtNL();
+
+ p = &v->hashlen[0];
+ if (pgpGet(v->hashlen, sizeof(v->hashlen), hend, &plen))
+ return 1;
+ p += sizeof(v->hashlen);
+
+ if ((p + plen) > hend)
+ return 1;
+
+ if (_digp->pubkey_algo == 0) {
+ _digp->hashlen = sizeof(*v) + plen;
+ _digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
+ }
+ if (pgpPrtSubType(p, plen, v->sigtype, _digp, 1))
+ return 1;
+ p += plen;
+
+ if (!(_digp->saved & PGPDIG_SIG_HAS_CREATION_TIME))
+ return 1; /* RFC 4880 §5.2.3.4 creation time MUST be hashed */
+
+ if (pgpGet(p, 2, hend, &plen))
+ return 1;
+ p += 2;
+
+ if ((p + plen) > hend)
+ return 1;
+
+ if (pgpPrtSubType(p, plen, v->sigtype, _digp, 0))
+ return 1;
+ p += plen;
+
+ if (h + hlen - p < 2)
+ return 1;
+ pgpPrtHex(" signhash16", p, 2);
+ pgpPrtNL();
+
+ if (_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 > hend)
+ return 1;
+
+ rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
+ } break;
+ default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of signature: V%d\n"), version);
+ rc = 1;
+ break;
+ }
+ return rc;
+}
+
+static uint8_t curve_oids[] = {
+ PGPCURVE_NIST_P_256, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
+ PGPCURVE_NIST_P_384, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
+ PGPCURVE_NIST_P_521, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
+ PGPCURVE_BRAINPOOL_P256R1, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07,
+ PGPCURVE_BRAINPOOL_P512R1, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d,
+ PGPCURVE_ED25519, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
+ PGPCURVE_CURVE25519, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
+ 0,
+};
+
+static int pgpCurveByOid(const uint8_t *p, int l)
+{
+ uint8_t *curve;
+ for (curve = curve_oids; *curve; curve += 2 + curve[1])
+ if (l == (int)curve[1] && !memcmp(p, curve + 2, l))
+ return (int)curve[0];
+ return 0;
+}
+
+static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
+ const uint8_t *p, const uint8_t *h, size_t hlen,
+ pgpDigParams keyp)
+{
+ int rc = 1;
+ const uint8_t *pend = h + hlen;
+ int curve = 0;
+ if (pubkey_algo == PGPPUBKEYALGO_EDDSA) {
+ int len = (hlen > 1) ? p[0] : 0;
+ if (len == 0 || len == 0xff || len >= hlen)
+ goto exit;
+ curve = pgpCurveByOid(p + 1, len);
+ p += len + 1;
+ }
+ pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo, curve);
+ rc = processMpis(keyalg->mpis, keyalg, p, pend);
+
+ /* We can't handle more than one key at a time */
+ if (rc == 0 && keyp->alg == NULL && (keyp->tag == PGPTAG_PUBLIC_KEY ||
+ keyp->tag == PGPTAG_PUBLIC_SUBKEY))
+
+ keyp->alg = keyalg;
+ else
+ pgpDigAlgFree(keyalg);
+
+exit:
+ return rc;
+}
+
+static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
+ pgpDigParams _digp)
+{
+ uint8_t version = 0;
+ const uint8_t * p = NULL;
+ int rc = 1;
+
+ if (pgpVersion(h, hlen, &version))
+ return rc;
+
+ /* We only permit V4 keys, V3 keys are long long since deprecated */
+ switch (version) {
+ case 4:
+ { pgpPktKeyV4 v = (pgpPktKeyV4)h;
+
+ if (hlen > sizeof(*v)) {
+ pgpPrtVal("V4 ", pgpTagTbl, tag);
+ pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
+ pgpPrtTime(" ", v->time, sizeof(v->time));
+ pgpPrtNL();
+
+ /* If _digp->hash is not NULL then signature is already loaded */
+ if (_digp->hash == NULL) {
+ _digp->version = v->version;
+ _digp->time = pgpGrab(v->time, sizeof(v->time));
+ _digp->pubkey_algo = v->pubkey_algo;
+ }
+
+ p = ((uint8_t *)v) + sizeof(*v);
+ rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp);
+ }
+ } break;
+ default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), h[0]);
+ }
+ return rc;
+}
+
+static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen,
+ pgpDigParams _digp)
+{
+ pgpPrtVal("", pgpTagTbl, tag);
+ if (_print)
+ fprintf(stderr, " \"%.*s\"", (int)hlen, (const char *)h);
+ pgpPrtNL();
+ free(_digp->userid);
+ _digp->userid = memcpy(xmalloc(hlen+1), h, hlen);
+ _digp->userid[hlen] = '\0';
+ return 0;
+}
+
+int pgpPubkeyFingerprint(const uint8_t *h, size_t hlen,
+ uint8_t **fp, size_t *fplen)
+{
+ int rc = -1; /* assume failure */
+ const uint8_t *se;
+ const uint8_t *pend = h + hlen;
+ uint8_t version = 0;
+
+ if (pgpVersion(h, hlen, &version))
+ return rc;
+
+ /* We only permit V4 keys, V3 keys are long long since deprecated */
+ switch (version) {
+ case 4:
+ { pgpPktKeyV4 v = (pgpPktKeyV4) (h);
+ int mpis = -1;
+
+ /* Packet must be strictly larger than v to have room for the
+ * required MPIs and (for EdDSA) the curve ID */
+ if (hlen < sizeof(*v) + sizeof(uint8_t))
+ return rc;
+ se = (uint8_t *)(v + 1);
+ switch (v->pubkey_algo) {
+ case PGPPUBKEYALGO_EDDSA:
+ /* EdDSA has a curve id before the MPIs */
+ if (se[0] == 0x00 || se[0] == 0xff || pend - se < 1 + se[0])
+ return rc;
+ se += 1 + se[0];
+ mpis = 1;
+ break;
+ case PGPPUBKEYALGO_RSA:
+ mpis = 2;
+ break;
+ case PGPPUBKEYALGO_DSA:
+ mpis = 4;
+ break;
+ default:
+ return rc;
+ }
+
+ /* Does the size and number of MPI's match our expectations? */
+ if (processMpis(mpis, NULL, se, pend) == 0) {
+ DIGEST_CTX ctx = rpmDigestInit(RPM_HASH_SHA1, RPMDIGEST_NONE);
+ uint8_t *d = NULL;
+ size_t dlen = 0;
+ uint8_t in[3] = { 0x99, (hlen >> 8), hlen };
+
+ (void) rpmDigestUpdate(ctx, in, 3);
+ (void) rpmDigestUpdate(ctx, h, hlen);
+ (void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0);
+
+ if (dlen == 20) {
+ rc = 0;
+ *fp = d;
+ *fplen = dlen;
+ } else {
+ free(d);
+ }
+ }
+
+ } break;
+ default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version);
+ }
+ return rc;
+}
+
+static int getKeyID(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
+{
+ uint8_t *fp = NULL;
+ size_t fplen = 0;
+ int rc = pgpPubkeyFingerprint(h, hlen, &fp, &fplen);
+ if (fp && fplen > 8) {
+ memcpy(keyid, (fp + (fplen-8)), 8);
+ free(fp);
+ }
+ return rc;
+}
+
+int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid)
+{
+ struct pgpPkt p;
+
+ if (decodePkt(pkt, pktlen, &p))
+ return -1;
+
+ return getKeyID(p.body, p.blen, keyid);
+}
+
+static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
+{
+ int rc = 0;
+
+ switch (p->tag) {
+ case PGPTAG_SIGNATURE:
+ rc = pgpPrtSig(p->tag, p->body, p->blen, _digp);
+ break;
+ case PGPTAG_PUBLIC_KEY:
+ /* Get the public key Key ID. */
+ rc = getKeyID(p->body, p->blen, _digp->signid);
+ if (rc)
+ memset(_digp->signid, 0, sizeof(_digp->signid));
+ else {
+ _digp->saved |= PGPDIG_SAVED_ID;
+ rc = pgpPrtKey(p->tag, p->body, p->blen, _digp);
+ }
+ break;
+ case PGPTAG_USER_ID:
+ rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp);
+ break;
+ case PGPTAG_RESERVED:
+ rc = -1;
+ break;
+ case PGPTAG_COMMENT:
+ case PGPTAG_COMMENT_OLD:
+ case PGPTAG_PUBLIC_SUBKEY:
+ case PGPTAG_SECRET_KEY:
+ case PGPTAG_SECRET_SUBKEY:
+ 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, p->tag);
+ pgpPrtHex("", p->body, p->blen);
+ pgpPrtNL();
+ break;
+ }
+
+ return rc;
+}
+
+pgpDigParams pgpDigParamsFree(pgpDigParams digp)
+{
+ if (digp) {
+ pgpDigAlgFree(digp->alg);
+ free(digp->userid);
+ free(digp->hash);
+ memset(digp, 0, sizeof(*digp));
+ free(digp);
+ }
+ return NULL;
+}
+
+int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2)
+{
+ int rc = 1; /* assume different, eg if either is NULL */
+ if (p1 && p2) {
+ /* XXX Should we compare something else too? */
+ if (p1->tag != p2->tag)
+ goto exit;
+ if (p1->hash_algo != p2->hash_algo)
+ goto exit;
+ if (p1->pubkey_algo != p2->pubkey_algo)
+ goto exit;
+ if (p1->version != p2->version)
+ goto exit;
+ if (p1->sigtype != p2->sigtype)
+ goto exit;
+ if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0)
+ goto exit;
+ if (p1->userid && p2->userid && strcmp(p1->userid, p2->userid) != 0)
+ goto exit;
+
+ /* Parameters match ... at least for our purposes */
+ rc = 0;
+ }
+exit:
+ return rc;
+}
+
+unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
+{
+ unsigned int algo = 0; /* assume failure */
+ if (digp) {
+ switch (algotype) {
+ case PGPVAL_PUBKEYALGO:
+ algo = digp->pubkey_algo;
+ break;
+ case PGPVAL_HASHALGO:
+ algo = digp->hash_algo;
+ break;
+ }
+ }
+ return algo;
+}
+
+const uint8_t *pgpDigParamsSignID(pgpDigParams digp)
+{
+ return digp->signid;
+}
+
+const char *pgpDigParamsUserID(pgpDigParams digp)
+{
+ return digp->userid;
+}
+
+int pgpDigParamsVersion(pgpDigParams digp)
+{
+ return digp->version;
+}
+
+uint32_t pgpDigParamsCreationTime(pgpDigParams digp)
+{
+ return digp->time;
+}
+
+static pgpDigParams pgpDigParamsNew(uint8_t tag)
+{
+ pgpDigParams digp = xcalloc(1, sizeof(*digp));
+ digp->tag = tag;
+ return digp;
+}
+
+static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag)
+{
+ int rc = -1;
+ if (pkt->tag == exptag) {
+ uint8_t head[] = {
+ 0x99,
+ (pkt->blen >> 8),
+ (pkt->blen ),
+ };
+
+ rpmDigestUpdate(hash, head, 3);
+ rpmDigestUpdate(hash, pkt->body, pkt->blen);
+ rc = 0;
+ }
+ return rc;
+}
+
+static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig,
+ const struct pgpPkt *all, int i)
+{
+ int rc = -1;
+ DIGEST_CTX hash = NULL;
+
+ switch (selfsig->sigtype) {
+ case PGPSIGTYPE_SUBKEY_BINDING:
+ hash = rpmDigestInit(selfsig->hash_algo, 0);
+ if (hash) {
+ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY);
+ if (!rc)
+ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY);
+ }
+ break;
+ default:
+ /* ignore types we can't handle */
+ rc = 0;
+ break;
+ }
+
+ if (hash && rc == 0)
+ rc = pgpVerifySignature(key, selfsig, hash);
+
+ rpmDigestFinal(hash, NULL, NULL, 0);
+
+ return rc;
+}
+
+static int parseSubkeySig(const struct pgpPkt *pkt, uint8_t tag,
+ pgpDigParams *params_p) {
+ pgpDigParams params = *params_p = NULL; /* assume failure */
+
+ if (pkt->tag != PGPTAG_SIGNATURE)
+ goto fail;
+
+ params = pgpDigParamsNew(tag);
+
+ if (pgpPrtSig(tag, pkt->body, pkt->blen, params))
+ goto fail;
+
+ if (params->sigtype != PGPSIGTYPE_SUBKEY_BINDING &&
+ params->sigtype != PGPSIGTYPE_SUBKEY_REVOKE)
+ {
+ goto fail;
+ }
+
+ *params_p = params;
+ return 0;
+fail:
+ pgpDigParamsFree(params);
+ return -1;
+}
+
+static const size_t RPM_MAX_OPENPGP_BYTES = 65535; /* max number of bytes in a key */
+
+int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
+ pgpDigParams * ret)
+{
+ const uint8_t *p = pkts;
+ const uint8_t *pend = pkts + pktlen;
+ pgpDigParams digp = NULL;
+ pgpDigParams selfsig = NULL;
+ int i = 0;
+ int alloced = 16; /* plenty for normal cases */
+ int rc = -1; /* assume failure */
+ int expect = 0;
+ int prevtag = 0;
+
+ if (pktlen > RPM_MAX_OPENPGP_BYTES)
+ return rc; /* reject absurdly large data */
+
+ struct pgpPkt *all = xmalloc(alloced * sizeof(*all));
+ while (p < pend) {
+ struct pgpPkt *pkt = &all[i];
+ if (decodePkt(p, (pend - p), pkt))
+ break;
+
+ if (digp == NULL) {
+ if (pkttype && pkt->tag != pkttype) {
+ break;
+ } else {
+ digp = pgpDigParamsNew(pkt->tag);
+ }
+ }
+
+ if (expect) {
+ if (pkt->tag != expect)
+ break;
+ selfsig = pgpDigParamsNew(pkt->tag);
+ }
+
+ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp))
+ break;
+
+ if (selfsig) {
+ /* subkeys must be followed by binding signature */
+ int xx = 1; /* assume failure */
+
+ if (!(prevtag == PGPTAG_PUBLIC_SUBKEY &&
+ selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING))
+ xx = pgpVerifySelf(digp, selfsig, all, i);
+
+ selfsig = pgpDigParamsFree(selfsig);
+ if (xx)
+ break;
+ expect = 0;
+ }
+
+ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY)
+ expect = PGPTAG_SIGNATURE;
+ prevtag = pkt->tag;
+
+ i++;
+ p += (pkt->body - pkt->head) + pkt->blen;
+ if (pkttype == PGPTAG_SIGNATURE)
+ break;
+
+ if (alloced <= i) {
+ alloced *= 2;
+ all = xrealloc(all, alloced * sizeof(*all));
+ }
+ }
+
+ rc = (digp && (p == pend) && expect == 0) ? 0 : -1;
+
+ free(all);
+ selfsig = pgpDigParamsFree(selfsig);
+ if (ret && rc == 0) {
+ *ret = digp;
+ } else {
+ pgpDigParamsFree(digp);
+ }
+ return rc;
+}
+
+int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen,
+ pgpDigParams mainkey, pgpDigParams **subkeys,
+ int *subkeysCount)
+{
+ const uint8_t *p = pkts;
+ const uint8_t *pend = pkts + pktlen;
+ pgpDigParams *digps = NULL;
+ int count = 0;
+ int alloced = 10;
+ struct pgpPkt pkt;
+ int rc, i;
+
+ digps = xmalloc(alloced * sizeof(*digps));
+
+ while (p < pend) {
+ if (decodePkt(p, (pend - p), &pkt))
+ break;
+
+ p += (pkt.body - pkt.head) + pkt.blen;
+
+ if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) {
+ if (count == alloced) {
+ alloced <<= 1;
+ digps = xrealloc(digps, alloced * sizeof(*digps));
+ }
+
+ digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY);
+ /* Copy UID from main key to subkey */
+ digps[count]->userid = xstrdup(mainkey->userid);
+
+ if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) {
+ pgpDigParamsFree(digps[count]);
+ continue;
+ }
+
+ if (pgpPrtKey(pkt.tag, pkt.body, pkt.blen, digps[count])) {
+ pgpDigParamsFree(digps[count]);
+ continue;
+ }
+
+ pgpDigParams subkey_sig = NULL;
+ if (decodePkt(p, pend - p, &pkt) ||
+ parseSubkeySig(&pkt, 0, &subkey_sig))
+ {
+ pgpDigParamsFree(digps[count]);
+ break;
+ }
+
+ /* Is the subkey revoked or incapable of signing? */
+ int ignore = subkey_sig->sigtype != PGPSIGTYPE_SUBKEY_BINDING ||
+ !((subkey_sig->saved & PGPDIG_SIG_HAS_KEY_FLAGS) &&
+ (subkey_sig->key_flags & 0x02));
+ if (ignore) {
+ pgpDigParamsFree(digps[count]);
+ } else {
+ digps[count]->key_flags = subkey_sig->key_flags;
+ digps[count]->saved |= PGPDIG_SIG_HAS_KEY_FLAGS;
+ count++;
+ }
+ p += (pkt.body - pkt.head) + pkt.blen;
+ pgpDigParamsFree(subkey_sig);
+ }
+ }
+ rc = (p == pend) ? 0 : -1;
+
+ if (rc == 0) {
+ *subkeys = xrealloc(digps, count * sizeof(*digps));
+ *subkeysCount = count;
+ } else {
+ for (i = 0; i < count; i++)
+ pgpDigParamsFree(digps[i]);
+ free(digps);
+ }
+
+ return rc;
+}
+
+rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
+{
+ DIGEST_CTX ctx = rpmDigestDup(hashctx);
+ uint8_t *hash = NULL;
+ size_t hashlen = 0;
+ rpmRC res = RPMRC_FAIL; /* assume failure */
+
+ if (sig == NULL || ctx == NULL)
+ goto exit;
+
+ if (sig->hash != NULL)
+ rpmDigestUpdate(ctx, sig->hash, sig->hashlen);
+
+ if (sig->version == 4) {
+ /* V4 trailer is six octets long (rfc4880) */
+ uint8_t trailer[6];
+ uint32_t nb = sig->hashlen;
+ nb = htonl(nb);
+ trailer[0] = sig->version;
+ trailer[1] = 0xff;
+ memcpy(trailer+2, &nb, 4);
+ rpmDigestUpdate(ctx, trailer, sizeof(trailer));
+ }
+
+ rpmDigestFinal(ctx, (void **)&hash, &hashlen, 0);
+ ctx = NULL;
+
+ /* Compare leading 16 bits of digest for quick check. */
+ if (hash == NULL || memcmp(hash, sig->signhash16, 2) != 0)
+ goto exit;
+
+ /*
+ * If we have a key, verify the signature for real. Otherwise we've
+ * done all we can, return NOKEY to indicate "looks okay but dunno."
+ */
+ if (key && key->alg) {
+ pgpDigAlg sa = sig->alg;
+ pgpDigAlg ka = key->alg;
+ if (sa && sa->verify) {
+ if (sa->verify(ka, sa, hash, hashlen, sig->hash_algo) == 0) {
+ res = RPMRC_OK;
+ }
+ }
+ } else {
+ res = RPMRC_NOKEY;
+ }
+
+exit:
+ free(hash);
+ rpmDigestFinal(ctx, NULL, NULL, 0);
+ return res;
+
+}
+
+static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen)
+{
+ const char * enc = NULL;
+ const char * crcenc = NULL;
+ uint8_t * dec;
+ uint8_t * 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 */
+
+#define TOKEQ(_s, _tok) (rstreqn((_s), (_tok), sizeof(_tok)-1))
+
+ for (t = (char *)b; t && *t; t = te) {
+ int rc;
+ 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 = pgpValStr(pgpArmorTbl, rc);
+ t += strlen(armortype);
+ if (!TOKEQ(t, "-----"))
+ continue;
+ t += sizeof("-----")-1;
+ if (*t != '\n' && *t != '\r')
+ continue;
+ *t = '\0';
+ pstate++;
+ break;
+ case 1:
+ enc = NULL;
+ rc = pgpValTok(pgpArmorKeyTbl, t, te);
+ if (rc >= 0)
+ continue;
+ if (*t != '\n' && *t != '\r') {
+ pstate = 0;
+ continue;
+ }
+ enc = te; /* Start of encoded packets */
+ pstate++;
+ break;
+ case 2:
+ crcenc = NULL;
+ if (*t != '=')
+ continue;
+ *t++ = '\0'; /* Terminate encoded packets */
+ crcenc = t; /* Start of encoded crc */
+ pstate++;
+ 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;
+ if (!rstreqn(t, armortype, strlen(armortype)))
+ continue;
+
+ t += strlen(armortype);
+ if (t >= te) continue;
+
+ if (!TOKEQ(t, "-----")) {
+ ec = PGPARMOR_ERR_NO_END_PGP;
+ goto exit;
+ }
+ t += (sizeof("-----")-1);
+ /* Handle EOF without EOL here, *t == '\0' at EOF */
+ if (*t && (t >= te)) continue;
+ /* XXX permitting \r here is not RFC-2440 compliant <shrug> */
+ if (!(*t == '\n' || *t == '\r' || *t == '\0')) continue;
+
+ crcdec = NULL;
+ crclen = 0;
+ if (rpmBase64Decode(crcenc, (void **)&crcdec, &crclen) != 0 || crclen != 3) {
+ crcdec = _free(crcdec);
+ ec = PGPARMOR_ERR_CRC_DECODE;
+ goto exit;
+ }
+ crcpkt = pgpGrab(crcdec, crclen);
+ crcdec = _free(crcdec);
+ dec = NULL;
+ declen = 0;
+ if (rpmBase64Decode(enc, (void **)&dec, &declen) != 0) {
+ ec = PGPARMOR_ERR_BODY_DECODE;
+ goto exit;
+ }
+ crc = pgpCRC(dec, declen);
+ if (crcpkt != crc) {
+ ec = PGPARMOR_ERR_CRC_CHECK;
+ _free(dec);
+ goto exit;
+ }
+ if (pkt)
+ *pkt = dec;
+ else
+ _free(dec);
+ if (pktlen) *pktlen = declen;
+ ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */
+ goto exit;
+ break;
+ }
+ }
+ ec = PGPARMOR_NONE;
+
+exit:
+ return ec;
+}
+
+
+pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen)
+{
+ pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */
+ if (armor && strlen(armor) > 0) {
+ uint8_t *b = (uint8_t*) xstrdup(armor);
+ ec = decodePkts(b, pkt, pktlen);
+ free(b);
+ }
+ return ec;
+}
+
+int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen)
+{
+ const uint8_t *p = pkts;
+ const uint8_t *pend = pkts + pktslen;
+ struct pgpPkt pkt;
+
+ while (p < pend) {
+ if (decodePkt(p, (pend - p), &pkt))
+ return -1;
+
+ if (pkt.tag == PGPTAG_PUBLIC_KEY && pkts != p) {
+ *certlen = p - pkts;
+ return 0;
+ }
+
+ p += (pkt.body - pkt.head) + pkt.blen;
+ }
+
+ *certlen = pktslen;
+
+ return 0;
+}
+
+char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
+{
+ char *buf = NULL, *val = NULL;
+ char *enc = rpmBase64Encode(s, ns, -1);
+ char *crc = rpmBase64CRC(s, ns);
+ const char *valstr = pgpValStr(pgpArmorTbl, atype);
+
+ if (crc != NULL && enc != NULL) {
+ rasprintf(&buf, "%s=%s", enc, crc);
+ }
+ free(crc);
+ free(enc);
+
+ rasprintf(&val, "-----BEGIN PGP %s-----\nVersion: rpm-" VERSION"\n\n"
+ "%s\n-----END PGP %s-----\n",
+ valstr, buf != NULL ? buf : "", valstr);
+
+ free(buf);
+ return val;
+}