Make base64 encoding/decoding part of rpmio public API
[platform/upstream/rpm.git] / rpmio / rpmpgp.c
1 /** \ingroup rpmio signature
2  * \file rpmio/rpmpgp.c
3  * Routines to handle RFC-2440 detached signatures.
4  */
5
6 #include "system.h"
7
8 #include <time.h>
9 #include <netinet/in.h>
10 #include <rpm/rpmstring.h>
11 #include <rpm/rpmlog.h>
12
13 #include "rpmio/digest.h"
14 #include "rpmio/rpmio_internal.h"       /* XXX rpmioSlurp */
15
16 #include "debug.h"
17
18 static int _print = 0;
19
20 /** \ingroup rpmio
21  * Container for values parsed from an OpenPGP signature and public key.
22  */
23 struct pgpDig_s {
24     struct pgpDigParams_s * signature;
25     struct pgpDigParams_s * pubkey;
26 };
27
28 typedef const struct pgpValTbl_s {
29     int val;
30     char const * const str;
31 } * pgpValTbl;
32  
33 static struct pgpValTbl_s const pgpSigTypeTbl[] = {
34     { PGPSIGTYPE_BINARY,        "Binary document signature" },
35     { PGPSIGTYPE_TEXT,          "Text document signature" },
36     { PGPSIGTYPE_STANDALONE,    "Standalone signature" },
37     { PGPSIGTYPE_GENERIC_CERT,  "Generic certification of a User ID and Public Key" },
38     { PGPSIGTYPE_PERSONA_CERT,  "Persona certification of a User ID and Public Key" },
39     { PGPSIGTYPE_CASUAL_CERT,   "Casual certification of a User ID and Public Key" },
40     { PGPSIGTYPE_POSITIVE_CERT, "Positive certification of a User ID and Public Key" },
41     { PGPSIGTYPE_SUBKEY_BINDING,"Subkey Binding Signature" },
42     { PGPSIGTYPE_SIGNED_KEY,    "Signature directly on a key" },
43     { PGPSIGTYPE_KEY_REVOKE,    "Key revocation signature" },
44     { PGPSIGTYPE_SUBKEY_REVOKE, "Subkey revocation signature" },
45     { PGPSIGTYPE_CERT_REVOKE,   "Certification revocation signature" },
46     { PGPSIGTYPE_TIMESTAMP,     "Timestamp signature" },
47     { -1,                       "Unknown signature type" },
48 };
49
50 static struct pgpValTbl_s const pgpPubkeyTbl[] = {
51     { PGPPUBKEYALGO_RSA,        "RSA" },
52     { PGPPUBKEYALGO_RSA_ENCRYPT,"RSA(Encrypt-Only)" },
53     { PGPPUBKEYALGO_RSA_SIGN,   "RSA(Sign-Only)" },
54     { PGPPUBKEYALGO_ELGAMAL_ENCRYPT,"Elgamal(Encrypt-Only)" },
55     { PGPPUBKEYALGO_DSA,        "DSA" },
56     { PGPPUBKEYALGO_EC,         "Elliptic Curve" },
57     { PGPPUBKEYALGO_ECDSA,      "ECDSA" },
58     { PGPPUBKEYALGO_ELGAMAL,    "Elgamal" },
59     { PGPPUBKEYALGO_DH,         "Diffie-Hellman (X9.42)" },
60     { -1,                       "Unknown public key algorithm" },
61 };
62
63 static struct pgpValTbl_s const pgpSymkeyTbl[] = {
64     { PGPSYMKEYALGO_PLAINTEXT,  "Plaintext" },
65     { PGPSYMKEYALGO_IDEA,       "IDEA" },
66     { PGPSYMKEYALGO_TRIPLE_DES, "3DES" },
67     { PGPSYMKEYALGO_CAST5,      "CAST5" },
68     { PGPSYMKEYALGO_BLOWFISH,   "BLOWFISH" },
69     { PGPSYMKEYALGO_SAFER,      "SAFER" },
70     { PGPSYMKEYALGO_DES_SK,     "DES/SK" },
71     { PGPSYMKEYALGO_AES_128,    "AES(128-bit key)" },
72     { PGPSYMKEYALGO_AES_192,    "AES(192-bit key)" },
73     { PGPSYMKEYALGO_AES_256,    "AES(256-bit key)" },
74     { PGPSYMKEYALGO_TWOFISH,    "TWOFISH(256-bit key)" },
75     { PGPSYMKEYALGO_NOENCRYPT,  "no encryption" },
76     { -1,                       "Unknown symmetric key algorithm" },
77 };
78
79 static struct pgpValTbl_s const pgpCompressionTbl[] = {
80     { PGPCOMPRESSALGO_NONE,     "Uncompressed" },
81     { PGPCOMPRESSALGO_ZIP,      "ZIP" },
82     { PGPCOMPRESSALGO_ZLIB,     "ZLIB" },
83     { PGPCOMPRESSALGO_BZIP2,    "BZIP2" },
84     { -1,                       "Unknown compression algorithm" },
85 };
86
87 static struct pgpValTbl_s const pgpHashTbl[] = {
88     { PGPHASHALGO_MD5,          "MD5" },
89     { PGPHASHALGO_SHA1,         "SHA1" },
90     { PGPHASHALGO_RIPEMD160,    "RIPEMD160" },
91     { PGPHASHALGO_MD2,          "MD2" },
92     { PGPHASHALGO_TIGER192,     "TIGER192" },
93     { PGPHASHALGO_HAVAL_5_160,  "HAVAL-5-160" },
94     { PGPHASHALGO_SHA256,       "SHA256" },
95     { PGPHASHALGO_SHA384,       "SHA384" },
96     { PGPHASHALGO_SHA512,       "SHA512" },
97     { PGPHASHALGO_SHA224,       "SHA224" },
98     { -1,                       "Unknown hash algorithm" },
99 };
100
101 static struct pgpValTbl_s const pgpKeyServerPrefsTbl[] = {
102     { 0x80,                     "No-modify" },
103     { -1,                       "Unknown key server preference" },
104 };
105
106 static struct pgpValTbl_s const pgpSubTypeTbl[] = {
107     { PGPSUBTYPE_SIG_CREATE_TIME,"signature creation time" },
108     { PGPSUBTYPE_SIG_EXPIRE_TIME,"signature expiration time" },
109     { PGPSUBTYPE_EXPORTABLE_CERT,"exportable certification" },
110     { PGPSUBTYPE_TRUST_SIG,     "trust signature" },
111     { PGPSUBTYPE_REGEX,         "regular expression" },
112     { PGPSUBTYPE_REVOCABLE,     "revocable" },
113     { PGPSUBTYPE_KEY_EXPIRE_TIME,"key expiration time" },
114     { PGPSUBTYPE_ARR,           "additional recipient request" },
115     { PGPSUBTYPE_PREFER_SYMKEY, "preferred symmetric algorithms" },
116     { PGPSUBTYPE_REVOKE_KEY,    "revocation key" },
117     { PGPSUBTYPE_ISSUER_KEYID,  "issuer key ID" },
118     { PGPSUBTYPE_NOTATION,      "notation data" },
119     { PGPSUBTYPE_PREFER_HASH,   "preferred hash algorithms" },
120     { PGPSUBTYPE_PREFER_COMPRESS,"preferred compression algorithms" },
121     { PGPSUBTYPE_KEYSERVER_PREFERS,"key server preferences" },
122     { PGPSUBTYPE_PREFER_KEYSERVER,"preferred key server" },
123     { PGPSUBTYPE_PRIMARY_USERID,"primary user id" },
124     { PGPSUBTYPE_POLICY_URL,    "policy URL" },
125     { PGPSUBTYPE_KEY_FLAGS,     "key flags" },
126     { PGPSUBTYPE_SIGNER_USERID, "signer's user id" },
127     { PGPSUBTYPE_REVOKE_REASON, "reason for revocation" },
128     { PGPSUBTYPE_FEATURES,      "features" },
129     { PGPSUBTYPE_EMBEDDED_SIG,  "embedded signature" },
130
131     { PGPSUBTYPE_INTERNAL_100,  "internal subpkt type 100" },
132     { PGPSUBTYPE_INTERNAL_101,  "internal subpkt type 101" },
133     { PGPSUBTYPE_INTERNAL_102,  "internal subpkt type 102" },
134     { PGPSUBTYPE_INTERNAL_103,  "internal subpkt type 103" },
135     { PGPSUBTYPE_INTERNAL_104,  "internal subpkt type 104" },
136     { PGPSUBTYPE_INTERNAL_105,  "internal subpkt type 105" },
137     { PGPSUBTYPE_INTERNAL_106,  "internal subpkt type 106" },
138     { PGPSUBTYPE_INTERNAL_107,  "internal subpkt type 107" },
139     { PGPSUBTYPE_INTERNAL_108,  "internal subpkt type 108" },
140     { PGPSUBTYPE_INTERNAL_109,  "internal subpkt type 109" },
141     { PGPSUBTYPE_INTERNAL_110,  "internal subpkt type 110" },
142     { -1,                       "Unknown signature subkey type" },
143 };
144
145 static struct pgpValTbl_s const pgpTagTbl[] = {
146     { PGPTAG_PUBLIC_SESSION_KEY,"Public-Key Encrypted Session Key" },
147     { PGPTAG_SIGNATURE,         "Signature" },
148     { PGPTAG_SYMMETRIC_SESSION_KEY,"Symmetric-Key Encrypted Session Key" },
149     { PGPTAG_ONEPASS_SIGNATURE, "One-Pass Signature" },
150     { PGPTAG_SECRET_KEY,        "Secret Key" },
151     { PGPTAG_PUBLIC_KEY,        "Public Key" },
152     { PGPTAG_SECRET_SUBKEY,     "Secret Subkey" },
153     { PGPTAG_COMPRESSED_DATA,   "Compressed Data" },
154     { PGPTAG_SYMMETRIC_DATA,    "Symmetrically Encrypted Data" },
155     { PGPTAG_MARKER,            "Marker" },
156     { PGPTAG_LITERAL_DATA,      "Literal Data" },
157     { PGPTAG_TRUST,             "Trust" },
158     { PGPTAG_USER_ID,           "User ID" },
159     { PGPTAG_PUBLIC_SUBKEY,     "Public Subkey" },
160     { PGPTAG_COMMENT_OLD,       "Comment (from OpenPGP draft)" },
161     { PGPTAG_PHOTOID,           "PGP's photo ID" },
162     { PGPTAG_ENCRYPTED_MDC,     "Integrity protected encrypted data" },
163     { PGPTAG_MDC,               "Manipulaion detection code packet" },
164     { PGPTAG_PRIVATE_60,        "Private #60" },
165     { PGPTAG_COMMENT,           "Comment" },
166     { PGPTAG_PRIVATE_62,        "Private #62" },
167     { PGPTAG_CONTROL,           "Control (GPG)" },
168     { -1,                       "Unknown packet tag" },
169 };
170
171 static struct pgpValTbl_s const pgpArmorTbl[] = {
172     { PGPARMOR_MESSAGE,         "MESSAGE" },
173     { PGPARMOR_PUBKEY,          "PUBLIC KEY BLOCK" },
174     { PGPARMOR_SIGNATURE,       "SIGNATURE" },
175     { PGPARMOR_SIGNED_MESSAGE,  "SIGNED MESSAGE" },
176     { PGPARMOR_FILE,            "ARMORED FILE" },
177     { PGPARMOR_PRIVKEY,         "PRIVATE KEY BLOCK" },
178     { PGPARMOR_SECKEY,          "SECRET KEY BLOCK" },
179     { -1,                       "Unknown armor block" }
180 };
181
182 static struct pgpValTbl_s const pgpArmorKeyTbl[] = {
183     { PGPARMORKEY_VERSION,      "Version: " },
184     { PGPARMORKEY_COMMENT,      "Comment: " },
185     { PGPARMORKEY_MESSAGEID,    "MessageID: " },
186     { PGPARMORKEY_HASH,         "Hash: " },
187     { PGPARMORKEY_CHARSET,      "Charset: " },
188     { -1,                       "Unknown armor key" }
189 };
190
191 static void pgpPrtNL(void)
192 {
193     if (!_print) return;
194     fprintf(stderr, "\n");
195 }
196
197 static const char * pgpValStr(pgpValTbl vs, uint8_t val)
198 {
199     do {
200         if (vs->val == val)
201             break;
202     } while ((++vs)->val != -1);
203     return vs->str;
204 }
205
206 static pgpValTbl pgpValTable(pgpValType type)
207 {
208     switch (type) {
209     case PGPVAL_TAG:            return pgpTagTbl;
210     case PGPVAL_ARMORBLOCK:     return pgpArmorTbl;
211     case PGPVAL_ARMORKEY:       return pgpArmorKeyTbl;
212     case PGPVAL_SIGTYPE:        return pgpSigTypeTbl;
213     case PGPVAL_SUBTYPE:        return pgpSubTypeTbl;
214     case PGPVAL_PUBKEYALGO:     return pgpPubkeyTbl;
215     case PGPVAL_SYMKEYALGO:     return pgpSymkeyTbl;
216     case PGPVAL_COMPRESSALGO:   return pgpCompressionTbl;
217     case PGPVAL_HASHALGO:       return pgpHashTbl;
218     case PGPVAL_SERVERPREFS:    return pgpKeyServerPrefsTbl;
219     default:
220         break;
221     }
222     return NULL;
223 }
224
225 const char * pgpValString(pgpValType type, uint8_t val)
226 {
227     pgpValTbl tbl = pgpValTable(type);
228     return (tbl != NULL) ? pgpValStr(tbl, val) : NULL;
229 }
230
231 static void pgpPrtHex(const char *pre, const uint8_t *p, size_t plen)
232 {
233     char *hex = NULL;
234     if (!_print) return;
235     if (pre && *pre)
236         fprintf(stderr, "%s", pre);
237     hex = pgpHexStr(p, plen);
238     fprintf(stderr, " %s", hex);
239     free(hex);
240 }
241
242 static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val)
243 {
244     if (!_print) return;
245     if (pre && *pre)
246         fprintf(stderr, "%s", pre);
247     fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
248 }
249
250 /** \ingroup rpmpgp
251  * Return hex formatted representation of a multiprecision integer.
252  * @param p             bytes
253  * @return              hex formatted string (malloc'ed)
254  */
255 static inline
256 char * pgpMpiStr(const uint8_t *p)
257 {
258     char *str = NULL;
259     char *hex = pgpHexStr(p+2, pgpMpiLen(p)-2);
260     rasprintf(&str, "[%4u]: %s", pgpGrab(p, (size_t) 2), hex);
261     free(hex);
262     return str;
263 }
264
265 /** \ingroup rpmpgp
266  * Return value of an OpenPGP string.
267  * @param vs            table of (string,value) pairs
268  * @param s             string token to lookup
269  * @param se            end-of-string address
270  * @return              byte value
271  */
272 static inline
273 int pgpValTok(pgpValTbl vs, const char * s, const char * se)
274 {
275     do {
276         size_t vlen = strlen(vs->str);
277         if (vlen <= (se-s) && rstreqn(s, vs->str, vlen))
278             break;
279     } while ((++vs)->val != -1);
280     return vs->val;
281 }
282
283 /** \ingroup rpmpgp
284  * Decode length from 1, 2, or 5 octet body length encoding, used in
285  * new format packet headers and V4 signature subpackets.
286  * @param s             pointer to length encoding buffer
287  * @param slen          buffer size
288  * @retval *lenp        decoded length
289  * @return              no. of bytes used to encode the length, 0 on error
290  */
291 static inline
292 size_t pgpLen(const uint8_t *s, size_t slen, size_t * lenp)
293 {
294     size_t dlen = 0;
295     size_t lenlen = 0;
296
297     /*
298      * Callers can only ensure we'll always have the first byte, beyond
299      * that the required size is not known until we decode it so we need
300      * to check if we have enough bytes to read the size as we go.
301      */
302     if (*s < 192) {
303         lenlen = 1;
304         dlen = *s;
305     } else if (*s < 255 && slen > 2) {
306         lenlen = 2;
307         dlen = (((s[0]) - 192) << 8) + s[1] + 192;
308     } else if (slen > 5) {
309         lenlen = 5;
310         dlen = pgpGrab(s+1, 4);
311     }
312
313     if (lenlen)
314         *lenp = dlen;
315
316     return lenlen;
317 }
318
319 struct pgpPkt {
320     uint8_t tag;                /* decoded PGP tag */
321     const uint8_t *head;        /* pointer to start of packet (header) */
322     const uint8_t *body;        /* pointer to packet body */
323     size_t blen;                /* length of body in bytes */
324 };
325
326 static int decodePkt(const uint8_t *p, size_t plen, struct pgpPkt *pkt)
327 {
328     int rc = -1; /* assume failure */
329
330     /* Valid PGP packet header must always have two or more bytes in it */
331     if (p && plen >= 2 && p[0] & 0x80) {
332         size_t lenlen = 0;
333         size_t hlen = 0;
334
335         if (p[0] & 0x40) {
336             /* New format packet, body length encoding in second byte */
337             lenlen = pgpLen(p+1, plen-1, &pkt->blen);
338             pkt->tag = (p[0] & 0x3f);
339         } else {
340             /* Old format packet, body length encoding in tag byte */
341             lenlen = (1 << (p[0] & 0x3));
342             if (plen > lenlen) {
343                 pkt->blen = pgpGrab(p+1, lenlen);
344             }
345             pkt->tag = (p[0] >> 2) & 0xf;
346         }
347         hlen = lenlen + 1;
348
349         /* Does the packet header and its body fit in our boundaries? */
350         if (lenlen && (hlen + pkt->blen <= plen)) {
351             pkt->head = p;
352             pkt->body = pkt->head + hlen;
353             rc = 0;
354         }
355     }
356
357     return rc;
358 }
359
360 #define CRC24_INIT      0xb704ce
361 #define CRC24_POLY      0x1864cfb
362
363 /** \ingroup rpmpgp
364  * Return CRC of a buffer.
365  * @param octets        bytes
366  * @param len           no. of bytes
367  * @return              crc of buffer
368  */
369 static inline
370 unsigned int pgpCRC(const uint8_t *octets, size_t len)
371 {
372     unsigned int crc = CRC24_INIT;
373     size_t i;
374
375     while (len--) {
376         crc ^= (*octets++) << 16;
377         for (i = 0; i < 8; i++) {
378             crc <<= 1;
379             if (crc & 0x1000000)
380                 crc ^= CRC24_POLY;
381         }
382     }
383     return crc & 0xffffff;
384 }
385
386 static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype, 
387                          pgpDigParams _digp)
388 {
389     const uint8_t *p = h;
390     size_t plen, i;
391
392     while (hlen > 0) {
393         i = pgpLen(p, hlen, &plen);
394         if (i == 0 || i + plen > hlen)
395             break;
396
397         p += i;
398         hlen -= i;
399
400         pgpPrtVal("    ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL)));
401         if (p[0] & PGPSUBTYPE_CRITICAL)
402             if (_print)
403                 fprintf(stderr, " *CRITICAL*");
404         switch (*p) {
405         case PGPSUBTYPE_PREFER_SYMKEY:  /* preferred symmetric algorithms */
406             for (i = 1; i < plen; i++)
407                 pgpPrtVal(" ", pgpSymkeyTbl, p[i]);
408             break;
409         case PGPSUBTYPE_PREFER_HASH:    /* preferred hash algorithms */
410             for (i = 1; i < plen; i++)
411                 pgpPrtVal(" ", pgpHashTbl, p[i]);
412             break;
413         case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */
414             for (i = 1; i < plen; i++)
415                 pgpPrtVal(" ", pgpCompressionTbl, p[i]);
416             break;
417         case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */
418             for (i = 1; i < plen; i++)
419                 pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
420             break;
421         case PGPSUBTYPE_SIG_CREATE_TIME:
422             if (!(_digp->saved & PGPDIG_SAVED_TIME) &&
423                 (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
424             {
425                 _digp->saved |= PGPDIG_SAVED_TIME;
426                 memcpy(_digp->time, p+1, sizeof(_digp->time));
427             }
428         case PGPSUBTYPE_SIG_EXPIRE_TIME:
429         case PGPSUBTYPE_KEY_EXPIRE_TIME:
430             if ((plen - 1) == 4) {
431                 time_t t = pgpGrab(p+1, plen-1);
432                 if (_print)
433                    fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
434             } else
435                 pgpPrtHex("", p+1, plen-1);
436             break;
437
438         case PGPSUBTYPE_ISSUER_KEYID:   /* issuer key ID */
439             if (!(_digp->saved & PGPDIG_SAVED_ID) &&
440                 (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
441             {
442                 _digp->saved |= PGPDIG_SAVED_ID;
443                 memcpy(_digp->signid, p+1, sizeof(_digp->signid));
444             }
445         case PGPSUBTYPE_EXPORTABLE_CERT:
446         case PGPSUBTYPE_TRUST_SIG:
447         case PGPSUBTYPE_REGEX:
448         case PGPSUBTYPE_REVOCABLE:
449         case PGPSUBTYPE_ARR:
450         case PGPSUBTYPE_REVOKE_KEY:
451         case PGPSUBTYPE_NOTATION:
452         case PGPSUBTYPE_PREFER_KEYSERVER:
453         case PGPSUBTYPE_PRIMARY_USERID:
454         case PGPSUBTYPE_POLICY_URL:
455         case PGPSUBTYPE_KEY_FLAGS:
456         case PGPSUBTYPE_SIGNER_USERID:
457         case PGPSUBTYPE_REVOKE_REASON:
458         case PGPSUBTYPE_FEATURES:
459         case PGPSUBTYPE_EMBEDDED_SIG:
460         case PGPSUBTYPE_INTERNAL_100:
461         case PGPSUBTYPE_INTERNAL_101:
462         case PGPSUBTYPE_INTERNAL_102:
463         case PGPSUBTYPE_INTERNAL_103:
464         case PGPSUBTYPE_INTERNAL_104:
465         case PGPSUBTYPE_INTERNAL_105:
466         case PGPSUBTYPE_INTERNAL_106:
467         case PGPSUBTYPE_INTERNAL_107:
468         case PGPSUBTYPE_INTERNAL_108:
469         case PGPSUBTYPE_INTERNAL_109:
470         case PGPSUBTYPE_INTERNAL_110:
471         default:
472             pgpPrtHex("", p+1, plen-1);
473             break;
474         }
475         pgpPrtNL();
476         p += plen;
477         hlen -= plen;
478     }
479     return (hlen != 0); /* non-zero hlen is an error */
480 }
481
482 pgpDigAlg pgpDigAlgFree(pgpDigAlg alg)
483 {
484     if (alg) {
485         if (alg->free)
486             alg->free(alg);
487         free(alg);
488     }
489     return NULL;
490 }
491
492 static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype,
493                 const uint8_t *p, const uint8_t *h, size_t hlen,
494                 pgpDigParams sigp)
495 {
496     int rc = 1; /* assume failure */
497     const uint8_t * pend = h + hlen;
498     int i;
499     pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo);
500
501     for (i = 0; p < pend && i < sigalg->mpis; i++, p += pgpMpiLen(p)) {
502         if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) {
503             if (sigalg->setmpi(sigalg, i, p, pend))
504                 break;
505         }
506     }
507
508     /* Does the size and number of MPI's match our expectations? */
509     if (p == pend && i == sigalg->mpis)
510         rc = 0;
511     
512     /* We can't handle more than one sig at a time */
513     if (rc == 0 && sigp->alg == NULL && sigp->tag == PGPTAG_SIGNATURE)
514         sigp->alg = sigalg;
515     else
516         pgpDigAlgFree(sigalg);
517
518     return rc;
519 }
520
521 static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
522                      pgpDigParams _digp)
523 {
524     uint8_t version = h[0];
525     uint8_t * p;
526     size_t plen;
527     int rc;
528
529     switch (version) {
530     case 3:
531     {   pgpPktSigV3 v = (pgpPktSigV3)h;
532         time_t t;
533
534         if (hlen <= sizeof(*v) || v->hashlen != 5)
535             return 1;
536
537         pgpPrtVal("V3 ", pgpTagTbl, tag);
538         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
539         pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
540         pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
541         pgpPrtNL();
542         t = pgpGrab(v->time, sizeof(v->time));
543         if (_print)
544             fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
545         pgpPrtNL();
546         pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid));
547         plen = pgpGrab(v->signhash16, sizeof(v->signhash16));
548         pgpPrtHex(" signhash16", v->signhash16, sizeof(v->signhash16));
549         pgpPrtNL();
550
551         if (_digp->pubkey_algo == 0) {
552             _digp->version = v->version;
553             _digp->hashlen = v->hashlen;
554             _digp->sigtype = v->sigtype;
555             _digp->hash = memcpy(xmalloc(v->hashlen), &v->sigtype, v->hashlen);
556             memcpy(_digp->time, v->time, sizeof(_digp->time));
557             memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
558             _digp->pubkey_algo = v->pubkey_algo;
559             _digp->hash_algo = v->hash_algo;
560             memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16));
561         }
562
563         p = ((uint8_t *)v) + sizeof(*v);
564         rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp);
565     }   break;
566     case 4:
567     {   pgpPktSigV4 v = (pgpPktSigV4)h;
568
569         if (hlen <= sizeof(*v))
570             return 1;
571
572         pgpPrtVal("V4 ", pgpTagTbl, tag);
573         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
574         pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
575         pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
576         pgpPrtNL();
577
578         p = &v->hashlen[0];
579         plen = pgpGrab(v->hashlen, sizeof(v->hashlen));
580         p += sizeof(v->hashlen);
581
582         if ((p + plen) > (h + hlen))
583             return 1;
584
585         if (_digp->pubkey_algo == 0) {
586             _digp->hashlen = sizeof(*v) + plen;
587             _digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
588         }
589         if (pgpPrtSubType(p, plen, v->sigtype, _digp))
590             return 1;
591         p += plen;
592
593         plen = pgpGrab(p,2);
594         p += 2;
595
596         if ((p + plen) > (h + hlen))
597             return 1;
598
599         if (pgpPrtSubType(p, plen, v->sigtype, _digp))
600             return 1;
601         p += plen;
602
603         plen = pgpGrab(p,2);
604         pgpPrtHex(" signhash16", p, 2);
605         pgpPrtNL();
606
607         if (_digp->pubkey_algo == 0) {
608             _digp->version = v->version;
609             _digp->sigtype = v->sigtype;
610             _digp->pubkey_algo = v->pubkey_algo;
611             _digp->hash_algo = v->hash_algo;
612             memcpy(_digp->signhash16, p, sizeof(_digp->signhash16));
613         }
614
615         p += 2;
616         if (p > (h + hlen))
617             return 1;
618
619         rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp);
620     }   break;
621     default:
622         rc = 1;
623         break;
624     }
625     return rc;
626 }
627
628 char * pgpHexStr(const uint8_t *p, size_t plen)
629 {
630     char *t, *str;
631     str = t = xmalloc(plen * 2 + 1);
632     static char const hex[] = "0123456789abcdef";
633     while (plen-- > 0) {
634         size_t i;
635         i = *p++;
636         *t++ = hex[ (i >> 4) & 0xf ];
637         *t++ = hex[ (i     ) & 0xf ];
638     }
639     *t = '\0';
640     return str;
641 }
642
643 static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
644                 const uint8_t *p, const uint8_t *h, size_t hlen,
645                 pgpDigParams keyp)
646 {
647     int rc = 1;
648     const uint8_t *pend = h + hlen;
649     int i;
650     pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo);
651
652     for (i = 0; p < pend && i < keyalg->mpis; i++, p += pgpMpiLen(p)) {
653         if (keyalg->setmpi(keyalg, i, p, pend))
654             break;
655     }
656
657     /* Does the size and number of MPI's match our expectations? */
658     if (p == pend && i == keyalg->mpis)
659         rc = 0;
660
661     /* We can't handle more than one key at a time */
662     if (rc == 0 && keyp->alg == NULL && keyp->tag == PGPTAG_PUBLIC_KEY)
663         keyp->alg = keyalg;
664     else
665         pgpDigAlgFree(keyalg);
666
667     return rc;
668 }
669
670 static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
671                      pgpDigParams _digp)
672 {
673     uint8_t version = *h;
674     const uint8_t * p = NULL;
675     time_t t;
676     int rc = 1;
677
678     /* We only permit V4 keys, V3 keys are long long since deprecated */
679     switch (version) {
680     case 4:
681     {   pgpPktKeyV4 v = (pgpPktKeyV4)h;
682
683         if (hlen > sizeof(*v)) {
684             pgpPrtVal("V4 ", pgpTagTbl, tag);
685             pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
686             t = pgpGrab(v->time, sizeof(v->time));
687             if (_print)
688                 fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
689             pgpPrtNL();
690
691             if (_digp->tag == tag) {
692                 _digp->version = v->version;
693                 memcpy(_digp->time, v->time, sizeof(_digp->time));
694                 _digp->pubkey_algo = v->pubkey_algo;
695             }
696
697             p = ((uint8_t *)v) + sizeof(*v);
698             rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp);
699         }
700     }   break;
701     }
702     return rc;
703 }
704
705 static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen,
706                         pgpDigParams _digp)
707 {
708     pgpPrtVal("", pgpTagTbl, tag);
709     if (_print)
710         fprintf(stderr, " \"%.*s\"", (int)hlen, (const char *)h);
711     pgpPrtNL();
712     free(_digp->userid);
713     _digp->userid = memcpy(xmalloc(hlen+1), h, hlen);
714     _digp->userid[hlen] = '\0';
715     return 0;
716 }
717
718 static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
719 {
720     int rc = -1; /* assume failure */
721     const uint8_t *se;
722     const uint8_t *pend = h + hlen;
723
724     /* We only permit V4 keys, V3 keys are long long since deprecated */
725     switch (h[0]) {
726     case 4:
727       { pgpPktKeyV4 v = (pgpPktKeyV4) (h);
728         int mpis = -1;
729
730         /* Packet must be larger than v to have room for the required MPIs */
731         if (hlen > sizeof(*v)) {
732             switch (v->pubkey_algo) {
733             case PGPPUBKEYALGO_RSA:
734                 mpis = 2;
735                 break;
736             case PGPPUBKEYALGO_DSA:
737                 mpis = 4;
738                 break;
739             }
740         }
741
742         se = (uint8_t *)(v + 1);
743         while (se < pend && mpis-- > 0)
744             se += pgpMpiLen(se);
745
746         /* Does the size and number of MPI's match our expectations? */
747         if (se == pend && mpis == 0) {
748             DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
749             uint8_t * d = NULL;
750             size_t dlen;
751             int i = se - h;
752             uint8_t in[3] = { 0x99, (i >> 8), i };
753
754             (void) rpmDigestUpdate(ctx, in, 3);
755             (void) rpmDigestUpdate(ctx, h, i);
756             (void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0);
757
758             if (d) {
759                 memcpy(keyid, (d + (dlen-sizeof(keyid))), sizeof(keyid));
760                 free(d);
761                 rc = 0;
762             }
763         }
764
765       } break;
766     }
767     return rc;
768 }
769
770 int pgpPubkeyFingerprint(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid)
771 {
772     struct pgpPkt p;
773
774     if (decodePkt(pkt, pktlen, &p))
775         return -1;
776     
777     return getFingerprint(p.body, p.blen, keyid);
778 }
779
780 int pgpExtractPubkeyFingerprint(const char * b64pkt, pgpKeyID_t keyid)
781 {
782     uint8_t * pkt;
783     size_t pktlen;
784     int rc = -1; /* assume failure */
785
786     if (rpmBase64Decode(b64pkt, (void **)&pkt, &pktlen) == 0) {
787         if (pgpPubkeyFingerprint(pkt, pktlen, keyid) == 0) {
788             /* if there ever was a bizarre return code for success... */
789             rc = sizeof(keyid);
790         }
791         free(pkt);
792     }
793     return rc;
794 }
795
796 static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
797 {
798     int rc = 0;
799
800     switch (p->tag) {
801     case PGPTAG_SIGNATURE:
802         rc = pgpPrtSig(p->tag, p->body, p->blen, _digp);
803         break;
804     case PGPTAG_PUBLIC_KEY:
805         /* Get the public key fingerprint. */
806         if (!getFingerprint(p->body, p->blen, _digp->signid))
807             _digp->saved |= PGPDIG_SAVED_ID;
808         else
809             memset(_digp->signid, 0, sizeof(_digp->signid));
810         rc = pgpPrtKey(p->tag, p->body, p->blen, _digp);
811         break;
812     case PGPTAG_USER_ID:
813         rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp);
814         break;
815     case PGPTAG_COMMENT:
816     case PGPTAG_COMMENT_OLD:
817     case PGPTAG_PUBLIC_SUBKEY:
818     case PGPTAG_SECRET_KEY:
819     case PGPTAG_SECRET_SUBKEY:
820     case PGPTAG_RESERVED:
821     case PGPTAG_PUBLIC_SESSION_KEY:
822     case PGPTAG_SYMMETRIC_SESSION_KEY:
823     case PGPTAG_COMPRESSED_DATA:
824     case PGPTAG_SYMMETRIC_DATA:
825     case PGPTAG_MARKER:
826     case PGPTAG_LITERAL_DATA:
827     case PGPTAG_TRUST:
828     case PGPTAG_PHOTOID:
829     case PGPTAG_ENCRYPTED_MDC:
830     case PGPTAG_MDC:
831     case PGPTAG_PRIVATE_60:
832     case PGPTAG_PRIVATE_62:
833     case PGPTAG_CONTROL:
834     default:
835         pgpPrtVal("", pgpTagTbl, p->tag);
836         pgpPrtHex("", p->body, p->blen);
837         pgpPrtNL();
838         break;
839     }
840
841     return rc;
842 }
843
844 pgpDig pgpNewDig(void)
845 {
846     pgpDig dig = xcalloc(1, sizeof(*dig));
847
848     return dig;
849 }
850
851 pgpDigParams pgpDigParamsFree(pgpDigParams digp)
852 {
853     if (digp) {
854         pgpDigAlgFree(digp->alg);
855         free(digp->userid);
856         free(digp->hash);
857         memset(digp, 0, sizeof(*digp));
858         free(digp);
859     }
860     return NULL;
861 }
862
863 void pgpCleanDig(pgpDig dig)
864 {
865     if (dig != NULL) {
866         pgpDigParamsFree(dig->signature);
867         pgpDigParamsFree(dig->pubkey);
868         memset(dig, 0, sizeof(*dig));
869     }
870     return;
871 }
872
873 pgpDig pgpFreeDig(pgpDig dig)
874 {
875     if (dig != NULL) {
876
877         /* DUmp the signature/pubkey data. */
878         pgpCleanDig(dig);
879         dig = _free(dig);
880     }
881     return dig;
882 }
883
884 pgpDigParams pgpDigGetParams(pgpDig dig, unsigned int pkttype)
885 {
886     pgpDigParams params = NULL;
887     if (dig) {
888         switch (pkttype) {
889         case PGPTAG_SIGNATURE:
890             params = dig->signature;
891             break;
892         case PGPTAG_PUBLIC_KEY:
893             params = dig->pubkey;
894             break;
895         }
896     }
897     return params;
898 }
899
900 int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2)
901 {
902     int rc = 1; /* assume different, eg if either is NULL */
903     if (p1 && p2) {
904         /* XXX Should we compare something else too? */
905         if (p1->hash_algo != p2->hash_algo)
906             goto exit;
907         if (p1->pubkey_algo != p2->pubkey_algo)
908             goto exit;
909         if (p1->version != p2->version)
910             goto exit;
911         if (p1->sigtype != p2->sigtype)
912             goto exit;
913         if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0)
914             goto exit;
915
916         /* Parameters match ... at least for our purposes */
917         rc = 0;
918     }
919 exit:
920     return rc;
921 }
922
923 unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
924 {
925     unsigned int algo = 0; /* assume failure */
926     if (digp) {
927         switch (algotype) {
928         case PGPVAL_PUBKEYALGO:
929             algo = digp->pubkey_algo;
930             break;
931         case PGPVAL_HASHALGO:
932             algo = digp->hash_algo;
933             break;
934         }
935     }
936     return algo;
937 }
938
939 int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
940                  pgpDigParams * ret)
941 {
942     const uint8_t *p = pkts;
943     const uint8_t *pend = pkts + pktlen;
944     pgpDigParams digp = NULL;
945     struct pgpPkt pkt;
946     int rc = -1; /* assume failure */
947
948     while (p < pend) {
949         if (decodePkt(p, (pend - p), &pkt))
950             break;
951
952         if (digp == NULL) {
953             if (pkttype && pkt.tag != pkttype) {
954                 break;
955             } else {
956                 digp = xcalloc(1, sizeof(*digp));
957                 digp->tag = pkt.tag;
958             }
959         }
960
961         if (pgpPrtPkt(&pkt, digp))
962             break;
963
964         p += (pkt.body - pkt.head) + pkt.blen;
965     }
966
967     rc = (digp && (p == pend)) ? 0 : -1;
968
969     if (ret && rc == 0) {
970         *ret = digp;
971     } else {
972         pgpDigParamsFree(digp);
973     }
974     return rc;
975 }
976
977 int pgpPrtPkts(const uint8_t * pkts, size_t pktlen, pgpDig dig, int printing)
978 {
979     int rc;
980     pgpDigParams digp = NULL;
981
982     _print = printing;
983
984     rc = pgpPrtParams(pkts, pktlen, 0, &digp);
985
986     if (dig && rc == 0) {
987         if (digp->tag == PGPTAG_SIGNATURE) {
988             pgpDigParamsFree(dig->signature);
989             dig->signature = digp;
990         } else {
991             pgpDigParamsFree(dig->pubkey);
992             dig->pubkey = digp;
993         }
994     } else {
995         pgpDigParamsFree(digp);
996     }
997
998     return rc;
999 }
1000
1001 char *pgpIdentItem(pgpDigParams digp)
1002 {
1003     char *id = NULL;
1004     if (digp) {
1005         
1006         char *signid = pgpHexStr(digp->signid+4, sizeof(digp->signid)-4);
1007         rasprintf(&id, _("V%d %s/%s %s, key ID %s"),
1008                         digp->version,
1009                         pgpValStr(pgpPubkeyTbl, digp->pubkey_algo),
1010                         pgpValStr(pgpHashTbl, digp->hash_algo),
1011                         pgpValStr(pgpTagTbl, digp->tag),
1012                         signid);
1013         free(signid);
1014     } else {
1015         id = xstrdup(_("(none)"));
1016     }
1017     return id;
1018 }
1019
1020 rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
1021 {
1022     DIGEST_CTX ctx = rpmDigestDup(hashctx);
1023     uint8_t *hash = NULL;
1024     size_t hashlen = 0;
1025     rpmRC res = RPMRC_FAIL; /* assume failure */
1026
1027     if (sig == NULL || ctx == NULL)
1028         goto exit;
1029
1030     if (sig->hash != NULL)
1031         rpmDigestUpdate(ctx, sig->hash, sig->hashlen);
1032
1033     if (sig->version == 4) {
1034         /* V4 trailer is six octets long (rfc4880) */
1035         uint8_t trailer[6];
1036         uint32_t nb = sig->hashlen;
1037         nb = htonl(nb);
1038         trailer[0] = sig->version;
1039         trailer[1] = 0xff;
1040         memcpy(trailer+2, &nb, 4);
1041         rpmDigestUpdate(ctx, trailer, sizeof(trailer));
1042     }
1043
1044     rpmDigestFinal(ctx, (void **)&hash, &hashlen, 0);
1045
1046     /* Compare leading 16 bits of digest for quick check. */
1047     if (hash == NULL || memcmp(hash, sig->signhash16, 2) != 0)
1048         goto exit;
1049
1050     /*
1051      * If we have a key, verify the signature for real. Otherwise we've
1052      * done all we can, return NOKEY to indicate "looks okay but dunno."
1053      */
1054     if (key && key->alg) {
1055         pgpDigAlg sa = sig->alg;
1056         pgpDigAlg ka = key->alg;
1057         if (sa && sa->verify) {
1058             if (sa->verify(ka, sa, hash, hashlen, sig->hash_algo) == 0) {
1059                 res = RPMRC_OK;
1060             }
1061         }
1062     } else {
1063         res = RPMRC_NOKEY;
1064     }
1065
1066 exit:
1067     free(hash);
1068     return res;
1069
1070 }
1071
1072 rpmRC pgpVerifySig(pgpDig dig, DIGEST_CTX hashctx)
1073 {
1074     if (dig == NULL || hashctx == NULL)
1075         return RPMRC_FAIL;
1076
1077     return pgpVerifySignature(pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY),
1078                               pgpDigGetParams(dig, PGPTAG_SIGNATURE), hashctx);
1079 }
1080
1081 static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen)
1082 {
1083     const char * enc = NULL;
1084     const char * crcenc = NULL;
1085     uint8_t * dec;
1086     uint8_t * crcdec;
1087     size_t declen;
1088     size_t crclen;
1089     uint32_t crcpkt, crc;
1090     const char * armortype = NULL;
1091     char * t, * te;
1092     int pstate = 0;
1093     pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP;    /* XXX assume failure */
1094
1095 #define TOKEQ(_s, _tok) (rstreqn((_s), (_tok), sizeof(_tok)-1))
1096
1097     for (t = (char *)b; t && *t; t = te) {
1098         int rc;
1099         if ((te = strchr(t, '\n')) == NULL)
1100             te = t + strlen(t);
1101         else
1102             te++;
1103
1104         switch (pstate) {
1105         case 0:
1106             armortype = NULL;
1107             if (!TOKEQ(t, "-----BEGIN PGP "))
1108                 continue;
1109             t += sizeof("-----BEGIN PGP ")-1;
1110
1111             rc = pgpValTok(pgpArmorTbl, t, te);
1112             if (rc < 0) {
1113                 ec = PGPARMOR_ERR_UNKNOWN_ARMOR_TYPE;
1114                 goto exit;
1115             }
1116             if (rc != PGPARMOR_PUBKEY)  /* XXX ASCII Pubkeys only, please. */
1117                 continue;
1118
1119             armortype = pgpValStr(pgpArmorTbl, rc);
1120             t += strlen(armortype);
1121             if (!TOKEQ(t, "-----"))
1122                 continue;
1123             t += sizeof("-----")-1;
1124             if (*t != '\n' && *t != '\r')
1125                 continue;
1126             *t = '\0';
1127             pstate++;
1128             break;
1129         case 1:
1130             enc = NULL;
1131             rc = pgpValTok(pgpArmorKeyTbl, t, te);
1132             if (rc >= 0)
1133                 continue;
1134             if (*t != '\n' && *t != '\r') {
1135                 pstate = 0;
1136                 continue;
1137             }
1138             enc = te;           /* Start of encoded packets */
1139             pstate++;
1140             break;
1141         case 2:
1142             crcenc = NULL;
1143             if (*t != '=')
1144                 continue;
1145             *t++ = '\0';        /* Terminate encoded packets */
1146             crcenc = t;         /* Start of encoded crc */
1147             pstate++;
1148             break;
1149         case 3:
1150             pstate = 0;
1151             if (!TOKEQ(t, "-----END PGP ")) {
1152                 ec = PGPARMOR_ERR_NO_END_PGP;
1153                 goto exit;
1154             }
1155             *t = '\0';          /* Terminate encoded crc */
1156             t += sizeof("-----END PGP ")-1;
1157             if (t >= te) continue;
1158
1159             if (armortype == NULL) /* XXX can't happen */
1160                 continue;
1161             if (!rstreqn(t, armortype, strlen(armortype)))
1162                 continue;
1163
1164             t += strlen(armortype);
1165             if (t >= te) continue;
1166
1167             if (!TOKEQ(t, "-----")) {
1168                 ec = PGPARMOR_ERR_NO_END_PGP;
1169                 goto exit;
1170             }
1171             t += (sizeof("-----")-1);
1172             if (t >= te) continue;
1173             /* XXX permitting \r here is not RFC-2440 compliant <shrug> */
1174             if (!(*t == '\n' || *t == '\r')) continue;
1175
1176             crcdec = NULL;
1177             crclen = 0;
1178             if (rpmBase64Decode(crcenc, (void **)&crcdec, &crclen) != 0) {
1179                 ec = PGPARMOR_ERR_CRC_DECODE;
1180                 goto exit;
1181             }
1182             crcpkt = pgpGrab(crcdec, crclen);
1183             crcdec = _free(crcdec);
1184             dec = NULL;
1185             declen = 0;
1186             if (rpmBase64Decode(enc, (void **)&dec, &declen) != 0) {
1187                 ec = PGPARMOR_ERR_BODY_DECODE;
1188                 goto exit;
1189             }
1190             crc = pgpCRC(dec, declen);
1191             if (crcpkt != crc) {
1192                 ec = PGPARMOR_ERR_CRC_CHECK;
1193                 goto exit;
1194             }
1195             if (pkt) *pkt = dec;
1196             if (pktlen) *pktlen = declen;
1197             ec = PGPARMOR_PUBKEY;       /* XXX ASCII Pubkeys only, please. */
1198             goto exit;
1199             break;
1200         }
1201     }
1202     ec = PGPARMOR_NONE;
1203
1204 exit:
1205     return ec;
1206 }
1207
1208 pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen)
1209 {
1210     uint8_t * b = NULL;
1211     ssize_t blen;
1212     pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP;    /* XXX assume failure */
1213     int rc = rpmioSlurp(fn, &b, &blen);
1214     if (rc == 0 && b != NULL && blen > 0) {
1215         ec = decodePkts(b, pkt, pktlen);
1216     }
1217     free(b);
1218     return ec;
1219 }
1220
1221 pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen)
1222 {
1223     pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP;    /* XXX assume failure */
1224     if (armor && strlen(armor) > 0) {
1225         uint8_t *b = (uint8_t*) xstrdup(armor);
1226         ec = decodePkts(b, pkt, pktlen);
1227         free(b);
1228     }
1229     return ec;
1230 }
1231
1232 char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
1233 {
1234     char *buf = NULL, *val = NULL;
1235     char *enc = rpmBase64Encode(s, ns, -1);
1236     char *crc = rpmBase64CRC(s, ns);
1237     const char *valstr = pgpValStr(pgpArmorTbl, atype);
1238
1239     if (crc != NULL && enc != NULL) {
1240         rasprintf(&buf, "%s=%s", enc, crc);
1241     }
1242     free(crc);
1243     free(enc);
1244
1245     rasprintf(&val, "-----BEGIN PGP %s-----\nVersion: rpm-" VERSION " (NSS-3)\n\n"
1246                     "%s\n-----END PGP %s-----\n",
1247                     valstr, buf != NULL ? buf : "", valstr);
1248
1249     free(buf);
1250     return val;
1251 }
1252