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