diff options
author | Neal H. Walfield <neal@pep.foundation> | 2022-04-11 15:04:45 +0200 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2022-04-12 09:48:53 +0300 |
commit | d8bb57eeabe249c2c85bf46b1162d7e57a310e37 (patch) | |
tree | d9a2ed7b35cf391efebd31445f7c0ec212968319 /rpmio/rpmpgp.c | |
parent | eaf359f35c6433cfe80fc8814795081b92171be8 (diff) | |
download | rpm-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/rpmpgp.c')
-rw-r--r-- | rpmio/rpmpgp.c | 1504 |
1 files changed, 3 insertions, 1501 deletions
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; -} - |