summaryrefslogtreecommitdiff
path: root/rpmio
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2000-10-26 15:32:03 +0000
committerjbj <devnull@localhost>2000-10-26 15:32:03 +0000
commit12dd80dc37fef861ada690fa0c7ffcc8a47d4fa4 (patch)
treebfdc584518d0f8090d52ff37114cf6225dd8d807 /rpmio
parentf104a06fb09a071d9abae455b6d44473ef4be4f1 (diff)
downloadlibrpm-tizen-12dd80dc37fef861ada690fa0c7ffcc8a47d4fa4.tar.gz
librpm-tizen-12dd80dc37fef861ada690fa0c7ffcc8a47d4fa4.tar.bz2
librpm-tizen-12dd80dc37fef861ada690fa0c7ffcc8a47d4fa4.zip
Add base64 fiddles to get at signature contents to librpmio.a.
parsePrep.c: fix typo's. CVS patchset: 4227 CVS date: 2000/10/26 15:32:03
Diffstat (limited to 'rpmio')
-rw-r--r--rpmio/.cvsignore1
-rw-r--r--rpmio/Makefile.am7
-rw-r--r--rpmio/base64.c122
-rw-r--r--rpmio/base64.h33
-rw-r--r--rpmio/md5.c3
-rw-r--r--rpmio/tkey.c730
6 files changed, 893 insertions, 3 deletions
diff --git a/rpmio/.cvsignore b/rpmio/.cvsignore
index cdaf0e3fa..6e7833339 100644
--- a/rpmio/.cvsignore
+++ b/rpmio/.cvsignore
@@ -6,3 +6,4 @@ Makefile.in
*.la
*.lo
trpmio
+tkey
diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am
index 09e361ed5..d64b7cdea 100644
--- a/rpmio/Makefile.am
+++ b/rpmio/Makefile.am
@@ -7,10 +7,11 @@ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/build -I$(top_srcdir)/lib \
pkgincdir = $(pkgincludedir)
pkginc_HEADERS = rpmio.h rpmurl.h rpmmacro.h rpmlog.h rpmmessages.h rpmerr.h
-noinst_HEADERS = rpmio_internal.h ugid.h
+noinst_HEADERS = base64.h rpmio_internal.h ugid.h
lib_LTLIBRARIES = librpmio.la
-librpmio_la_SOURCES = rpmrpc.c rpmio.c rpmio_api.c url.c macro.c md5.c \
+librpmio_la_SOURCES = rpmrpc.c rpmio.c rpmio_api.c url.c macro.c \
+ base64.c md5.c \
ugid.c rpmmalloc.c rpmlog.c
# XXX Add internal libtool dependence
@@ -27,3 +28,5 @@ lclint:
trpmio: librpmio.la trpmio.o
$(LINK) -o $@ trpmio.o librpmio.la $(top_builddir)/popt/libpopt.la
+tkey: librpmio.la tkey.o
+ $(LINK) -o $@ tkey.o librpmio.la $(top_builddir)/popt/libpopt.la
diff --git a/rpmio/base64.c b/rpmio/base64.c
new file mode 100644
index 000000000..03e40c915
--- /dev/null
+++ b/rpmio/base64.c
@@ -0,0 +1,122 @@
+/** \ingroup signature
+ * \file rpmio/base64.c
+ *
+ */
+
+static int _debug = 0;
+
+#include "system.h"
+
+#include "base64.h"
+
+int B64decode (const char * s, void ** datap, size_t *lenp)
+{
+ static char * b64dec = NULL;
+ unsigned char *t, *te;
+ size_t ns, nt;
+ int a, b, c, d;
+
+ if (s == NULL) return 1;
+ ns = strlen(s);
+ if (ns & 0x3) return 2;
+
+ if (b64dec == NULL) {
+ b64dec = xmalloc(255);
+ memset(b64dec, 0x80, 255);
+ for (c = 'A'; c <= 'Z'; c++)
+ b64dec[ c ] = 0 + (c - 'A');
+ for (c = 'a'; c <= 'z'; c++)
+ b64dec[ c ] = 26 + (c - 'a');
+ for (c = '0'; c <= '9'; c++)
+ b64dec[ c ] = 52 + (c - '0');
+ b64dec['+'] = 62;
+ b64dec['/'] = 63;
+ b64dec['='] = 0;
+ }
+
+ nt = (ns / 4) * 3;
+ t = te = xmalloc(nt + 1);
+
+ while (ns > 0) {
+ if ((a = b64dec[ *s++ ]) == 0x80)
+ break;
+ if ((b = b64dec[ *s++ ]) == 0x80)
+ break;
+ if ((c = b64dec[ *s++ ]) == 0x80)
+ break;
+ if ((d = b64dec[ *s++ ]) == 0x80)
+ break;
+if (_debug)
+fprintf(stderr, "%7u %02x %02x %02x %02x -> %02x %02x %02x\n",
+(unsigned)ns, a, b, c, d,
+(((a << 2) | (b >> 4)) & 0xff),
+(((b << 4) | (c >> 2)) & 0xff),
+(((c << 6) | d) & 0xff));
+ ns -= 4;
+ *te++ = (a << 2) | (b >> 4);
+ if (s[-2] == '=') break;
+ *te++ = (b << 4) | (c >> 2);
+ if (s[-1] == '=') break;
+ *te++ = (c << 6) | d;
+ }
+
+ if (ns > 0) {
+ free(t);
+ return 3;
+ }
+ if (lenp)
+ *lenp = (te - t);
+ if (datap)
+ *datap = t;
+ else
+ free(t);
+
+ return 0;
+}
+
+char * B64encode (const void * str, size_t ns)
+{
+ static char b64enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const unsigned char *s = str;
+ unsigned char *t, *te;
+ size_t nt;
+ unsigned c;
+
+ if (s == NULL) return NULL;
+ if (*s == '\0') return xstrdup("");
+
+ if (ns == 0) ns = strlen(s);
+ nt = ((ns + 2) / 3) * 4;
+ t = te = xmalloc(nt + 1);
+
+ while (ns) {
+
+if (_debug)
+fprintf(stderr, "%7u %02x %02x %02x -> %02x %02x %02x %02x\n",
+(unsigned)ns, s[0], s[1], s[2],
+(s[0] >> 2),
+((s[0] & 0x3) << 4) | (s[1] >> 4),
+((s[1] & 0xf) << 2) | (s[2] >> 6),
+(s[2]& 0x3f));
+ c = *s++;
+ *te++ = b64enc[ (c >> 2) ];
+ *te++ = b64enc[ ((c & 0x3) << 4) | (*s >> 4) ];
+ if (--ns <= 0) {
+ *te++ = '=';
+ *te++ = '=';
+ continue;
+ }
+ c = *s++;
+ *te++ = b64enc[ ((c & 0xf) << 2) | (*s >> 6) ];
+ if (--ns <= 0) {
+ *te++ = '=';
+ continue;
+ }
+ *te++ = b64enc[ (*s & 0x3f) ];
+ s++;
+ --ns;
+ }
+ *te = '\0';
+ return t;
+}
diff --git a/rpmio/base64.h b/rpmio/base64.h
new file mode 100644
index 000000000..47092ecb4
--- /dev/null
+++ b/rpmio/base64.h
@@ -0,0 +1,33 @@
+#ifndef H_BASE64
+#define H_BASE64
+
+/** \ingroup rpmio
+ * \file rpmio/base64.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Decode chunks of 4 bytes of base64 input into 3 bytes of binary output.
+ * @param s base64 string
+ * @retval datap address of (malloc'd) binary data
+ * @retval lenp address of no. bytes of binary data
+ * @return 0 on success
+ */
+int B64decode (const char * s, /*@out@*/ void ** datap, /*@out@*/ size_t *lenp);
+
+/**
+ * Encode chunks of 3 bytes of binary input into 4 bytes of base64 output.
+ * @param data binary data
+ * @param ns no. bytes of data (0 uses strlen(data))
+ * @return (malloc'd) base64 string
+ */
+char * B64encode (const void * data, size_t ns);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_RPMURL */
diff --git a/rpmio/md5.c b/rpmio/md5.c
index 9a2ac8c1e..4cb54b312 100644
--- a/rpmio/md5.c
+++ b/rpmio/md5.c
@@ -1,5 +1,5 @@
/** \ingroup signature
- * \file rpmio/md5hash.c
+ * \file rpmio/md5.c
*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
@@ -54,6 +54,7 @@ static union _mendian { int i; char b[4]; } *_endian = (union _mendian *)&_ie;
* The core of the MD5 algorithm.
* This alters an existing MD5 hash to reflect the addition of 16 longwords
* of new data.
+ * @param private MD5 private data
*/
static void
MD5Transform(void * private)
diff --git a/rpmio/tkey.c b/rpmio/tkey.c
new file mode 100644
index 000000000..49b8871a5
--- /dev/null
+++ b/rpmio/tkey.c
@@ -0,0 +1,730 @@
+/** \ingroup signature
+ * \file rpmio/base64.c
+ *
+ */
+
+static int _debug = 0;
+
+#include "system.h"
+
+#include "base64.h"
+
+typedef unsigned char byte;
+
+static inline int grab(const byte *s, int nbytes)
+{
+ int i = 0;
+ int nb = (nbytes <= sizeof(i) ? nbytes : sizeof(i));
+ while (nb--)
+ i = (i << 8) | *s++;
+ return i;
+}
+
+#define GRAB(_a) grab((_a), sizeof(_a))
+
+typedef struct {
+ byte nbits[2];
+ byte bits[1];
+} MPI_t;
+
+static inline int mpi_nbits(const byte *p) { return ((p[0] << 8) | p[1]); }
+static inline int mpi_len(const byte *p) { return (2 + ((mpi_nbits(p)+7)>>3)); }
+
+static char * pr_pfmt(char *t, const byte *s, int nbytes)
+{
+ static char hex[] = "0123456789abcdef";
+ while (nbytes-- > 0) {
+ *t++ = hex[ (*s >> 4) & 0xf ];
+ *t++ = hex[ (*s++ ) & 0xf ];
+ }
+ *t = '\0';
+ return t;
+}
+
+static char prbuf[2048];
+
+static char * pr_hex(const byte *p, unsigned plen)
+{
+ char *t = prbuf;
+
+ t = pr_pfmt(t, p, plen);
+ return prbuf;
+}
+
+static const char * pr_mpi(const byte *p)
+{
+ char *t = prbuf;
+
+ sprintf(t, "[%d]: ", grab(p,2));
+ t += strlen(t);
+ t = pr_pfmt(t, p+2, mpi_len(p)-2);
+ return prbuf;
+}
+
+static const char * pr_sigtype(byte sigtype) {
+ switch (sigtype) {
+ case 0x00: return("Signature of a binary document"); break;
+ case 0x01: return("Signature of a canonical text document"); break;
+ case 0x02: return("Standalone signature"); break;
+ case 0x10: return("Generic certification of a User ID and Public Key"); break;
+ case 0x11: return("Persona certification of a User ID and Public Key"); break;
+ case 0x12: return("Casual certification of a User ID and Public Key"); break;
+ case 0x13: return("Positive certification of a User ID and Public Key"); break;
+ case 0x18: return("Subkey Binding Signature"); break;
+ case 0x1F: return("Signature directly on a key"); break;
+ case 0x20: return("Key revocation signature"); break;
+ case 0x28: return("Subkey revocation signature"); break;
+ case 0x30: return("Certification revocation signature"); break;
+ case 0x40: return("Timestamp signature"); break;
+ }
+ return "Unknown signature type";
+}
+
+static const char * pr_pubkey_algo(byte pubkey_algo) {
+ switch (pubkey_algo) {
+ case 1: return("RSA"); break;
+ case 2: return("RSA(Encrypt-Only)"); break;
+ case 3 : return("RSA(Sign-Only)"); break;
+ case 16: return("Elgamal(Encrypt-Only)"); break;
+ case 17: return("DSA"); break;
+ case 18: return("Elliptic Curve"); break;
+ case 19: return("ECDSA"); break;
+ case 20: return("Elgamal"); break;
+ case 21: return("Diffie-Hellman (X9.42)"); break;
+ }
+ return "Unknown public key algorithm";
+}
+
+static const char * pr_symkey_algo(byte symkey_algo) {
+ switch (symkey_algo) {
+ case 0: return("Plaintext"); break;
+ case 1: return("IDEA"); break;
+ case 2: return("DES-EDE"); break;
+ case 3: return("CAST5"); break;
+ case 4: return("BLOWFISH"); break;
+ case 5: return("SAFER"); break;
+ case 10: return("TWOFISH"); break;
+ }
+ return "Unknown symmetric key algorithm";
+};
+
+static const char * pr_compression_algo(byte compression_algo) {
+ switch (compression_algo) {
+ case 0: return("Uncompressed"); break;
+ case 1: return("ZIP"); break;
+ case 2: return("ZLIB"); break;
+ }
+ return "Unknown compression algorithm";
+};
+
+static const char * pr_hash_algo(byte hash_algo) {
+ switch (hash_algo) {
+ case 1: return("MD5"); break;
+ case 2: return("SHA1"); break;
+ case 3: return("RIPEMD160"); break;
+ case 5: return("MD2"); break;
+ case 6: return("TIGER192"); break;
+ case 7: return("HAVAL-5-160"); break;
+ }
+ return "Unknown hash algorithm";
+}
+
+static const char * pr_keyserv_pref (byte keyserv_pref) {
+ switch(keyserv_pref) {
+ case 0x80: return("No-modify"); break;
+ }
+ return "Unknown key server preference";
+};
+
+static const char * pr_sigsubkeytype (byte sigsubkeytype) {
+ switch(sigsubkeytype) {
+ case 2: return("signature creation time"); break;
+ case 3: return("signature expiration time"); break;
+ case 4: return("exportable certification"); break;
+ case 5: return("trust signature"); break;
+ case 6: return("regular expression"); break;
+ case 7: return("revocable"); break;
+ case 9: return("key expiration time"); break;
+ case 10: return("placeholder for backward compatibility"); break;
+ case 11: return("preferred symmetric algorithms"); break;
+ case 12: return("revocation key"); break;
+ case 16: return("issuer key ID"); break;
+ case 20: return("notation data"); break;
+ case 21: return("preferred hash algorithms"); break;
+ case 22: return("preferred compression algorithms"); break;
+ case 23: return("key server preferences"); break;
+ case 24: return("preferred key server"); break;
+ case 25: return("primary user id"); break;
+ case 26: return("policy URL"); break;
+ case 27: return("key flags"); break;
+ case 28: return("signer's user id"); break;
+ case 29: return("reason for revocation"); break;
+ }
+ return "Unknown signature subkey type";
+}
+
+const char *ptags[] = {
+ "Reserved - a packet tag must not have this value",
+ "Public-Key Encrypted Session Key",
+ "Signature",
+ "Symmetric-Key Encrypted Session Key",
+ "One-Pass Signature",
+ "Secret Key",
+ "Public Key",
+ "Secret Subkey",
+ "Compressed Data",
+ "Symmetrically Encrypted Data",
+ "Marker",
+ "Literal Data",
+ "Trust",
+ "User ID",
+ "Public Subkey",
+ "??? TAG15 ???",
+};
+
+typedef enum {
+ RPMKEYPKT_SIGNATURE = 2,
+ RPMKEYPKT_SECRET_KEY = 5,
+ RPMKEYPKT_PUBLIC_KEY = 6,
+ RPMKEYPKT_SECRET_SUBKEY = 7,
+ RPMKEYPKT_USER_ID = 13,
+ RPMKEYPKT_PUBLIC_SUBKEY = 14
+} rpmKeyPkt;
+
+/*
+5.2.2. Version 3 Signature Packet Format
+ The body of a version 3 Signature Packet contains:
+ - One-octet version number (3).
+ - One-octet length of following hashed material. MUST be 5.
+ - One-octet signature type.
+ - Four-octet creation time.
+ - Eight-octet key ID of signer.
+ - One-octet public key algorithm.
+ - One-octet hash algorithm.
+ - Two-octet field holding left 16 bits of signed hash value.
+ - One or more multi-precision integers comprising the signature.
+ This portion is algorithm specific, as described below.
+*/
+
+struct signature_v3 {
+ byte version; /*!< version number (3). */
+ byte hashlen; /*!< length of following hashed material. MUST be 5. */
+ byte sigtype; /*!< signature type. */
+ byte time[4]; /*!< 4 byte creation time. */
+ byte signer[8]; /*!< key ID of signer. */
+ byte pubkey_algo; /*!< public key algorithm. */
+ byte hash_algo; /*!< hash algorithm. */
+ byte signhash16[2]; /*!< left 16 bits of signed hash value. */
+ byte data[1]; /*!< One or more multi-precision integers. */
+};
+
+static int pr_signature_v3(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ struct signature_v3 *v = (struct signature_v3 *)h;
+ byte *p;
+ unsigned plen;
+ int i;
+
+fprintf(stderr, "%s(%d)", ptags[ptag], ptag);
+ if (v->version != 3) {
+ fprintf(stderr, " version(%d) != 3\n", v->version);
+ return 1;
+ }
+ if (v->hashlen != 5) {
+ fprintf(stderr, " hashlen(%d) != 5\n", v->hashlen);
+ return 1;
+ }
+fprintf(stderr, " %s(%d)", pr_pubkey_algo(v->pubkey_algo), v->pubkey_algo);
+fprintf(stderr, " %s(%d)", pr_hash_algo(v->hash_algo), v->hash_algo);
+
+fprintf(stderr, " %s(%d)", pr_sigtype(v->sigtype), v->sigtype);
+
+ plen = GRAB(v->time);
+fprintf(stderr, " time %08x", plen);
+fprintf(stderr, " signer keyid %02x%02x%02x%02x%02x%02x%02x%02x",
+ v->signer[0], v->signer[1], v->signer[2], v->signer[3],
+ v->signer[4], v->signer[5], v->signer[6], v->signer[7]);
+ plen = GRAB(v->signhash16);
+fprintf(stderr, " signhash16 %04x", plen);
+fprintf(stderr, "\n");
+
+ p = &v->data[0];
+ for (i = 0; p < &h[hlen]; i++, p += mpi_len(p))
+ fprintf(stderr, "%7d %s\n", i, pr_mpi(p));
+
+ return 0;
+}
+
+/*
+5.2.3.1. Signature Subpacket Specification
+
+ The subpacket fields consist of zero or more signature subpackets.
+ Each set of subpackets is preceded by a two-octet scalar count of the
+ length of the set of subpackets.
+
+ Each subpacket consists of a subpacket header and a body. The header
+ consists of:
+
+ - the subpacket length (1, 2, or 5 octets)
+
+ - the subpacket type (1 octet)
+
+ and is followed by the subpacket specific data.
+
+ The length includes the type octet but not this length. Its format is
+ similar to the "new" format packet header lengths, but cannot have
+ partial body lengths. That is:
+
+ if the 1st octet < 192, then
+ lengthOfLength = 1
+ subpacketLen = 1st_octet
+
+ if the 1st octet >= 192 and < 255, then
+ lengthOfLength = 2
+ subpacketLen = ((1st_octet - 192) << 8) + (2nd_octet) + 192
+
+ if the 1st octet = 255, then
+ lengthOfLength = 5
+ subpacket length = [four-octet scalar starting at 2nd_octet]
+
+*/
+
+static int pr_sigsubkeys(const byte *h, unsigned hlen)
+{
+ const byte *p = h;
+ unsigned plen;
+ int i;
+
+ while (hlen > 0) {
+ if (*p < 192) {
+ plen = *p++;
+ hlen -= 1;
+ } else if (*p < 255) {
+ plen = ((p[0] - 192) << 8) + p[1] + 192;
+ p += 2;
+ hlen -= 2;
+ } else {
+ p++;
+ plen = grab(p, 4);
+ p += 4;
+ hlen -= 5;
+ }
+fprintf(stderr, " %s(%d)", pr_sigsubkeytype(*p), *p);
+ switch (*p) {
+ case 11: /* preferred symmetric algorithms */
+ for (i = 1; i < plen; i++)
+ fprintf(stderr, " %s(%d)", pr_symkey_algo(p[i]), p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case 21: /* preferred hash algorithms */
+ for (i = 1; i < plen; i++)
+ fprintf(stderr, " %s(%d)", pr_hash_algo(p[i]), p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case 22: /* preferred compression algorithms */
+ for (i = 1; i < plen; i++)
+ fprintf(stderr, " %s(%d)", pr_compression_algo(p[i]), p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case 23: /* key server preferences */
+ for (i = 1; i < plen; i++)
+ fprintf(stderr, " %s(%d)", pr_keyserv_pref(p[i]), p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case 16: /* issuer key ID */
+ default:
+ fprintf(stderr, " %s", pr_hex(p+1, plen-1));
+ fprintf(stderr, "\n");
+ break;
+ }
+ p += plen;
+ hlen -= plen;
+ }
+ return 0;
+}
+
+/*
+5.2.3. Version 4 Signature Packet Format
+ The body of a version 4 Signature Packet contains:
+ - One-octet version number (4).
+ - One-octet signature type.
+ - One-octet public key algorithm.
+ - One-octet hash algorithm.
+ - Two-octet scalar octet count for following hashed subpacket
+ data. Note that this is the length in octets of all of the hashed
+ subpackets; a pointer incremented by this number will skip over
+ the hashed subpackets.
+ - Hashed subpacket data. (zero or more subpackets)
+ - Two-octet scalar octet count for following unhashed subpacket
+ data. Note that this is the length in octets of all of the
+ unhashed subpackets; a pointer incremented by this number will
+ skip over the unhashed subpackets.
+ - Unhashed subpacket data. (zero or more subpackets)
+ - Two-octet field holding left 16 bits of signed hash value.
+ - One or more multi-precision integers comprising the signature.
+ This portion is algorithm specific, as described above.
+*/
+
+struct signature_v4 {
+ byte version; /*!< version number (4). */
+ byte sigtype; /*!< signature type. */
+ byte pubkey_algo; /*!< public key algorithm. */
+ byte hash_algo; /*!< hash algorithm. */
+ byte hashlen[2]; /*!< length of following hashed material. */
+ byte data[1]; /*!< Hashed subpacket data. (zero or more subpackets) */
+};
+
+static int pr_signature_v4(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ struct signature_v4 *v = (struct signature_v4 *)h;
+ byte * p;
+ unsigned plen;
+ int i;
+
+fprintf(stderr, "%s(%d)", ptags[ptag], ptag);
+ if (v->version != 4) {
+ fprintf(stderr, " version(%d) != 4\n", v->version);
+ return 1;
+ }
+fprintf(stderr, " %s(%d)", pr_pubkey_algo(v->pubkey_algo), v->pubkey_algo);
+fprintf(stderr, " %s(%d)", pr_hash_algo(v->hash_algo), v->hash_algo);
+
+fprintf(stderr, " %s(%d)", pr_sigtype(v->sigtype), v->sigtype);
+fprintf(stderr, "\n");
+
+ p = &v->hashlen[0];
+ plen = GRAB(v->hashlen);
+ p += 2;
+fprintf(stderr, " hash[%d] -- %s\n", plen, pr_hex(p, plen));
+ pr_sigsubkeys(p, plen);
+ p += plen;
+ plen = grab(p,2);
+ p += 2;
+fprintf(stderr, " unhash[%d] -- %s\n", plen, pr_hex(p, plen));
+ pr_sigsubkeys(p, plen);
+ p += plen;
+ plen = grab(p,2);
+ p += 2;
+fprintf(stderr, " signhash16 %04x\n", plen);
+
+ for (i = 0; p < &h[hlen]; i++, p += mpi_len(p))
+ fprintf(stderr, "%7d %s\n", i, pr_mpi(p));
+
+ return 0;
+}
+
+static int pr_signature(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ byte version = *h;
+ switch (version) {
+ case 3:
+ pr_signature_v3(ptag, h, hlen);
+ break;
+ case 4:
+ pr_signature_v4(ptag, h, hlen);
+ break;
+ }
+ return 0;
+}
+
+/*
+ A version 3 public key or public subkey packet contains:
+ - A one-octet version number (3).
+ - A four-octet number denoting the time that the key was created.
+ - A two-octet number denoting the time in days that this key is
+ valid. If this number is zero, then it does not expire.
+ - A one-octet number denoting the public key algorithm of this key
+ - A series of multi-precision integers comprising the key
+ material:
+ - MPI of RSA public modulus n;
+ - MPI of RSA public encryption exponent e.
+
+ Algorithm Specific Fields for RSA signatures:
+ - multiprecision integer (MPI) of RSA signature value m**d.
+
+ Algorithm Specific Fields for DSA signatures:
+ - MPI of DSA value r.
+ - MPI of DSA value s.
+
+*/
+
+struct key_v3 {
+ byte version; /*!< version number (3). */
+ byte time[4]; /*!< time that the key was created. */
+ byte valid[2]; /*!< time in days that this key is valid. */
+ byte pubkey_algo; /*!< public key algorithm. */
+ byte data[1]; /*!< One or more multi-precision integers. */
+};
+
+static int pr_key_v3(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ struct key_v3 *v = (struct key_v3 *)h;
+ byte * p;
+ unsigned plen;
+ int i;
+
+fprintf(stderr, "%s(%d)", ptags[ptag], ptag);
+ if (v->version != 3) {
+ fprintf(stderr, " version(%d) != 3\n", v->version);
+ return 1;
+ }
+ plen = GRAB(v->time);
+fprintf(stderr, " time %08x", plen);
+fprintf(stderr, " %s(%d)", pr_pubkey_algo(v->pubkey_algo), v->pubkey_algo);
+
+ plen = GRAB(v->valid);
+ if (plen != 0)
+ fprintf(stderr, " valid %d days", plen);
+
+fprintf(stderr, "\n");
+
+ p = &v->data[0];
+ for (i = 0; p < &h[hlen]; i++, p += mpi_len(p))
+ fprintf(stderr, "%7d %s\n", i, pr_mpi(p));
+
+ return 0;
+}
+
+/*
+ A version 4 packet contains:
+ - A one-octet version number (4).
+ - A four-octet number denoting the time that the key was created.
+ - A one-octet number denoting the public key algorithm of this key
+ - A series of multi-precision integers comprising the key
+ material. This algorithm-specific portion is:
+
+ Algorithm Specific Fields for RSA public keys:
+ - MPI of RSA public modulus n;
+ - MPI of RSA public encryption exponent e.
+
+ Algorithm Specific Fields for DSA public keys:
+ - MPI of DSA prime p;
+ - MPI of DSA group order q (q is a prime divisor of p-1);
+ - MPI of DSA group generator g;
+ - MPI of DSA public key value y (= g**x where x is secret).
+
+ Algorithm Specific Fields for Elgamal public keys:
+ - MPI of Elgamal prime p;
+ - MPI of Elgamal group generator g;
+ - MPI of Elgamal public key value y (= g**x where x is
+ secret).
+*/
+
+struct key_v4 {
+ byte version; /*!< version number (4). */
+ byte time[4]; /*!< time that the key was created. */
+ byte pubkey_algo; /*!< public key algorithm. */
+ byte data[1]; /*!< One or more multi-precision integers. */
+};
+
+static int pr_key_v4(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ struct key_v4 *v = (struct key_v4 *)h;
+ byte * p;
+ unsigned plen;
+ int i;
+
+fprintf(stderr, "%s(%d)", ptags[ptag], ptag);
+ if (v->version != 4) {
+ fprintf(stderr, " version(%d) != 4\n", v->version);
+ return 1;
+ }
+ plen = GRAB(v->time);
+fprintf(stderr, " time %08x", plen);
+fprintf(stderr, " %s(%d)", pr_pubkey_algo(v->pubkey_algo), v->pubkey_algo);
+fprintf(stderr, "\n");
+
+ p = &v->data[0];
+ for (i = 0; p < &h[hlen]; i++, p += mpi_len(p))
+ fprintf(stderr, "%7d %s\n", i, pr_mpi(p));
+
+ return 0;
+}
+
+static int pr_key(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+ byte version = *h;
+ switch (version) {
+ case 3:
+ pr_key_v3(ptag, h, hlen);
+ break;
+ case 4:
+ pr_key_v4(ptag, h, hlen);
+ break;
+ }
+ return 0;
+}
+
+/*
+5.11. User ID Packet (Tag 13)
+
+ A User ID packet consists of data that is intended to represent the
+ name and email address of the key holder. By convention, it includes
+ an RFC 822 mail name, but there are no restrictions on its content.
+ The packet length in the header specifies the length of the user id.
+ If it is text, it is encoded in UTF-8.
+*/
+
+static int pr_user_id(rpmKeyPkt ptag, const byte *h, unsigned hlen)
+{
+fprintf(stderr, "%s(%d)", ptags[ptag], ptag);
+fprintf(stderr, " \"%*s\"\n", hlen, h);
+ return 0;
+}
+
+static int pr_keypkt(const byte *p)
+{
+ unsigned int val = *p;
+ unsigned int mark = (val >> 7) & 0x1;
+ unsigned int new = (val >> 6) & 0x1;
+ rpmKeyPkt ptag = (val >> 2) & 0xf;
+ unsigned int plen = (1 << (val & 0x3));
+ const byte *h;
+ unsigned int hlen = 0;
+ unsigned int i;
+
+ /* XXX can't deal with these. */
+ if (!mark || new || plen > 8)
+ return -1;
+
+ for (i = 1; i <= plen; i++)
+ hlen = (hlen << 8) | p[i];
+
+ h = p + plen + 1;
+ switch (ptag) {
+ case RPMKEYPKT_SIGNATURE:
+ pr_signature(ptag, h, hlen);
+ break;
+ case RPMKEYPKT_PUBLIC_KEY:
+ case RPMKEYPKT_PUBLIC_SUBKEY:
+ case RPMKEYPKT_SECRET_KEY:
+ case RPMKEYPKT_SECRET_SUBKEY:
+ pr_key(ptag, h, hlen);
+ break;
+ case RPMKEYPKT_USER_ID:
+ pr_user_id(ptag, h, hlen);
+ break;
+ default:
+ fprintf(stderr, "%s(%d) plen %02x hlen %x\n",
+ ptags[ptag], ptag, plen, hlen);
+ break;
+ }
+
+ return plen+hlen+1;
+}
+
+/* This is the unarmored RPM-GPG-KEY public key. */
+const char * gpgsig = "\
+mQGiBDfqVDgRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8\
+HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSWShLabR3N1KXdXQYYcowTOM\
+GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbWJbyjkg5Z3P7BlUOUJmrx3wCgobNV\
+EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS\
+ZVG7rKANEK2mxg1VB+vc/uUc4k49UxJJfCZg1gu1sPFV3GSa+Y/7jsiLktQvCiLP\
+lncQt1dV+ENmHR5BdIDPWDzKBVbgWnSDnqQ6KrZ7T6AlZ74VMpjGxxkWU6vV2xsW\
+XCLPA/9P/vtImA8CZN3jxGgtK5GGtDNJ/cMhhuv5tnfwFg4b/VGo2Jr8mhLUqoIb\
+E6zeGAmZbUpdckDco8D5fiFmqTf5+++pCEpJLJkkzel/32N2w4qzPrcRMCiBURES\
+PjCLd4Y5rPoU8E4kOHc/4BuHN903tiCsCPloCrWsQZ7UdxfQ5LQiUmVkIEhhdCwg\
+SW5jIDxzZWN1cml0eUByZWRoYXQuY29tPohVBBMRAgAVBQI36lQ4AwsKAwMVAwID\
+FgIBAheAAAoJECGRgM3bQqYOsBQAnRVtg7B25Hm11PHcpa8FpeddKiq2AJ9aO8sB\
+XmLDmPOEFI75mpTrKYHF6rkCDQQ36lRyEAgAokgI2xJ+3bZsk8jRA8ORIX8DH05U\
+lMH27qFYzLbT6npXwXYIOtVn0K2/iMDj+oEB1Aa2au4OnddYaLWp06v3d+XyS0t+\
+5ab2ZfIQzdh7wCwxqRkzR+/H5TLYbMG+hvtTdylfqIX0WEfoOXMtWEGSVwyUsnM3\
+Jy3LOi48rQQSCKtCAUdV20FoIGWhwnb/gHU1BnmES6UdQujFBE6EANqPhp0coYoI\
+hHJ2oIO8ujQItvvNaU88j/s/izQv5e7MXOgVSjKe/WX3s2JtB/tW7utpy12wh1J+\
+JsFdbLV/t8CozUTpJgx5mVA3RKlxjTA+On+1IEUWioB+iVfT7Ov/0kcAzwADBQf9\
+E4SKCWRand8K0XloMYgmipxMhJNnWDMLkokvbMNTUoNpSfRoQJ9EheXDxwMpTPwK\
+ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8\
+BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5\
+4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdRCCE+Y7YVP6IUf/w6YPQFQriWY\
+FiA6fD10eB+BlIUqIw80VgjsBKmCwvKkn4jg8kibXgj4/TzQSx77uYokw1EqQ2wk\
+OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h\
+VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==\
+";
+
+/* This is the unarmored RPM-PGP-KEY public key. */
+const char * pgpsig = "\
+mQCNAzEpXjUAAAEEAKG4/V9oUSiDc9wIge6Bmg6erDGCLzmFyioAho8kDIJSrcmi\
+F9qTdPq+fj726pgW1iSb0Y7syZn9Y2lgQm5HkPODfNi8eWyTFSxbr8ygosLRClTP\
+xqHVhtInGrfZNLoSpv1LdWOme0yOpOQJnghdOMzKXpgf5g84vaUg6PHLopv5AAUR\
+tCpSZWQgSGF0IFNvZnR3YXJlLCBJbmMuIDxyZWRoYXRAcmVkaGF0LmNvbT6JAJUD\
+BRAyA5tUoyDApfg4JKEBAUzSA/9QdcVsu955vVyZDk8uvOXWV0X3voT9B3aYMFvj\
+UNHUD6F1VFruwQHVKbGJEq1o5MOA6OXKR3vJZStXEMF47TWXJfQaflgl8ywZTH5W\
++eMlKau6Nr0labUV3lmsAE4Vsgu8NCkzIrp2wNVbeW2ZAXtrKswV+refLquUhp7l\
+wMpH9IkAdQMFEDGttkRNdXhbO1TgGQEBAGoC/j6C22PqXIyqZc6fG6J6Jl/T5kFG\
+xH1pKIzua5WCDDugAgnuOJgywa4pegT4UqwEZiMTAlwT6dmG1CXgKB+5V7lnCjDc\
+JZLni0iztoe08ig6fJrjNGXljf7KYXzgwBftQokAlQMFEDMQzo2MRVM9rfPulQEB\
+pLoD/1/MWv3u0Paiu14XRvDrBaJ7BmG2/48bA5vKOzpvvoNRO95YS7ZEtqErXA7Y\
+DRO8+C8f6PAILMk7kCk4lNMscS/ZRzu5+J8cv4ejsFvxgJBBU3Zgp8AWdWOpvZ0I\
+wW//HoDUGhOxlEtymljIMFBkj4SysHWhCBUfA9Xy86kouTJQiQCVAwUQMxDOQ50a\
+feTWLUSJAQFnYQQAkt9nhMTeioREB1DvJt+vsFyOj//o3ThqK5ySEP3dgj62iaQp\
+JrBmAe5XZPw25C/TXAf+x27H8h2QbKgq49VtsElFexc6wO+uq85fAPDdyE+2XyNE\
+njGZkY/TP2F/jTB0sAwJO+xFCHmSYkcBjzxK/2LMD+O7rwp2UCUhhl9QhhqJAJUD\
+BRAx5na6pSDo8cuim/kBARmjA/4lDVnV2h9KiNabp9oE38wmGgu5m5XgUHW8L6du\
+iQDnwO5IgXN2vDpKGxbgtwv6iYYmGd8IRQ66uJvOsxSv3OR7J7LkCHuI2b/s0AZn\
+c79DZaJ2ChUCZlbNQBMeEdrFWif9NopY+d5+2tby1onu9XOFMMvomxL3NhctElYR\
+HC8Xw4kAlQMFEDHmdTtURTdEKY1MpQEBEtEEAMZbp1ZFrjiHkj2aLFC1S8dGRbSH\
+GUdnLP9qLPFgmWekp9E0o8ZztALGVdqPfPF3N/JJ+AL4IMrfojd7+eZKw36Mdvtg\
+dPI+Oz4sxHDbDynZ2qspD9Om5yYuxuz/Xq+9nO2IlsAnEYw3ag3cxat0kvxpOPRe\
+Yy+vFpgfDNizr3MgiQBVAwUQMXNMXCjtrosVMemRAQEDnwH7BsJrnnh91nI54LAK\
+Gcq3pr8ld0PAtWJmNRGQvUlpEMXUSnu59j2P1ogPNjL3PqKdVxk5Jqgcr8TPQMf3\
+V4fqXokAlQMFEDFy+8YiEmsRQ3LyzQEB+TwD/03QDslXLg5F3zj4zf0yI6ikT0be\
+5OhZv2pnkb80qgdHzFRxBOYmSoueRKdQJASd8F9ue4b3bmf/Y7ikiY0DblvxcXB2\
+sz1Pu8i2Zn9u8SKuxNIoVvM8/STRVkgPfvL5QjAWMHT9Wvg81XcI2yXJzrt/2f2g\
+mNpWIvVOOT85rVPIiQCVAwUQMVPRlBlzviMjNHElAQG1nwP/fpVX6nKRWJCSFeB7\
+leZ4lb+y1uMsMVv0n7agjJVw13SXaA267y7VWCBlnhsCemxEugqEIkI4lu/1mgtw\
+WPWSE0BOIVjj0AA8zp2T0H3ZCCMbiFAFJ1P2Gq2rKr8QrOb/08oH1lEzyz0j/jKh\
+qiXAxdlB1wojQB6yLbHvTIe3rZGJAHUDBRAxKetfzauiKSJ6LJEBAed/AvsEiGgj\
+TQzhsZcUuRNrQpV0cDGH9Mpril7P7K7yFIzju8biB+Cu6nEknSOHlMLl8usObVlk\
+d8Wf14soHC7SjItiGSKtI8JhauzBJPl6fDDeyHGsJKo9f9adKeBMCipCFOuJAJUD\
+BRAxKeqWRHFTaIK/x+0BAY6eA/4m5X4gs1UwOUIRnljo9a0cVs6ITL554J9vSCYH\
+Zzd87kFwdf5W1Vd82HIkRzcr6cp33E3IDkRzaQCMVw2me7HePP7+4Ry2q3EeZMbm\
+NE++VzkxjikzpRb2+F5nGB2UdsElkgbXinswebiuOwOrocLbz6JFdDsJPcT5gVfi\
+z15FuA==\
+";
+
+int
+main (int argc, char *argv[])
+{
+ const char *sig = gpgsig;
+ unsigned char * dec;
+ unsigned char * d;
+ size_t declen;
+ char * enc;
+ int rc;
+ int len = 0;
+ int i;
+
+if (_debug)
+fprintf(stderr, "*** sig is\n%s\n", sig);
+
+ if ((rc = B64decode(sig, (void **)&dec, &declen)) != 0) {
+ fprintf(stderr, "*** B64decode returns %d\n", rc);
+ exit(rc);
+ }
+
+ for (d = dec; d < (dec + declen); d += len) {
+ len = pr_keypkt(d);
+ if (len <= 0)
+ exit(len);
+ }
+
+ if ((enc = B64encode(dec, declen)) == NULL) {
+ fprintf(stderr, "*** B64encode returns %d\n", rc);
+ exit(4);
+ }
+
+if (_debug)
+fprintf(stderr, "*** enc is\n%s\n", enc);
+
+len = strlen(sig);
+for (i = 0; i < len; i++) {
+ if (sig[i] == enc[i]) continue;
+fprintf(stderr, "??? %5d %02x %02x\n", i, (sig[i] & 0xff), (enc[i] & 0xff));
+}
+
+ if (strcmp(sig, enc)) {
+ fprintf(stderr, "*** BAD\n");
+ exit(5);
+ }
+ return 0;
+}