Turn rpmioSlurp() length argument to unsigned size_t, fix up uses.
[platform/upstream/rpm.git] / rpmio / rpmpgp.c
1 /*@-boundsread@*/
2 /** \ingroup rpmio signature
3  * \file rpmio/rpmpgp.c
4  * Routines to handle RFC-2440 detached signatures.
5  */
6
7 #include "system.h"
8 #include "rpmio_internal.h"
9 #include "debug.h"
10
11 /*@access pgpDig @*/
12 /*@access pgpDigParams @*/
13
14 /*@unchecked@*/
15 static int _debug = 0;
16
17 /*@unchecked@*/
18 static int _print = 0;
19
20 /*@unchecked@*/ /*@null@*/
21 static pgpDig _dig = NULL;
22
23 /*@unchecked@*/ /*@null@*/
24 static pgpDigParams _digp = NULL;
25
26 struct pgpValTbl_s pgpSigTypeTbl[] = {
27     { PGPSIGTYPE_BINARY,        "Binary document signature" },
28     { PGPSIGTYPE_TEXT,          "Text document signature" },
29     { PGPSIGTYPE_STANDALONE,    "Standalone signature" },
30     { PGPSIGTYPE_GENERIC_CERT,  "Generic certification of a User ID and Public Key" },
31     { PGPSIGTYPE_PERSONA_CERT,  "Persona certification of a User ID and Public Key" },
32     { PGPSIGTYPE_CASUAL_CERT,   "Casual certification of a User ID and Public Key" },
33     { PGPSIGTYPE_POSITIVE_CERT, "Positive certification of a User ID and Public Key" },
34     { PGPSIGTYPE_SUBKEY_BINDING,"Subkey Binding Signature" },
35     { PGPSIGTYPE_SIGNED_KEY,    "Signature directly on a key" },
36     { PGPSIGTYPE_KEY_REVOKE,    "Key revocation signature" },
37     { PGPSIGTYPE_SUBKEY_REVOKE, "Subkey revocation signature" },
38     { PGPSIGTYPE_CERT_REVOKE,   "Certification revocation signature" },
39     { PGPSIGTYPE_TIMESTAMP,     "Timestamp signature" },
40     { -1,                       "Unknown signature type" },
41 };
42
43 struct pgpValTbl_s pgpPubkeyTbl[] = {
44     { PGPPUBKEYALGO_RSA,        "RSA" },
45     { PGPPUBKEYALGO_RSA_ENCRYPT,"RSA(Encrypt-Only)" },
46     { PGPPUBKEYALGO_RSA_SIGN,   "RSA(Sign-Only)" },
47     { PGPPUBKEYALGO_ELGAMAL_ENCRYPT,"Elgamal(Encrypt-Only)" },
48     { PGPPUBKEYALGO_DSA,        "DSA" },
49     { PGPPUBKEYALGO_EC,         "Elliptic Curve" },
50     { PGPPUBKEYALGO_ECDSA,      "ECDSA" },
51     { PGPPUBKEYALGO_ELGAMAL,    "Elgamal" },
52     { PGPPUBKEYALGO_DH,         "Diffie-Hellman (X9.42)" },
53     { -1,                       "Unknown public key algorithm" },
54 };
55
56 struct pgpValTbl_s pgpSymkeyTbl[] = {
57     { PGPSYMKEYALGO_PLAINTEXT,  "Plaintext" },
58     { PGPSYMKEYALGO_IDEA,       "IDEA" },
59     { PGPSYMKEYALGO_TRIPLE_DES, "3DES" },
60     { PGPSYMKEYALGO_CAST5,      "CAST5" },
61     { PGPSYMKEYALGO_BLOWFISH,   "BLOWFISH" },
62     { PGPSYMKEYALGO_SAFER,      "SAFER" },
63     { PGPSYMKEYALGO_DES_SK,     "DES/SK" },
64     { PGPSYMKEYALGO_AES_128,    "AES(128-bit key)" },
65     { PGPSYMKEYALGO_AES_192,    "AES(192-bit key)" },
66     { PGPSYMKEYALGO_AES_256,    "AES(256-bit key)" },
67     { PGPSYMKEYALGO_TWOFISH,    "TWOFISH(256-bit key)" },
68     { PGPSYMKEYALGO_NOENCRYPT,  "no encryption" },
69     { -1,                       "Unknown symmetric key algorithm" },
70 };
71
72 struct pgpValTbl_s pgpCompressionTbl[] = {
73     { PGPCOMPRESSALGO_NONE,     "Uncompressed" },
74     { PGPCOMPRESSALGO_ZIP,      "ZIP" },
75     { PGPCOMPRESSALGO_ZLIB,     "ZLIB" },
76     { PGPCOMPRESSALGO_BZIP2,    "BZIP2" },
77     { -1,                       "Unknown compression algorithm" },
78 };
79
80 struct pgpValTbl_s pgpHashTbl[] = {
81     { PGPHASHALGO_MD5,          "MD5" },
82     { PGPHASHALGO_SHA1,         "SHA1" },
83     { PGPHASHALGO_RIPEMD160,    "RIPEMD160" },
84     { PGPHASHALGO_MD2,          "MD2" },
85     { PGPHASHALGO_TIGER192,     "TIGER192" },
86     { PGPHASHALGO_HAVAL_5_160,  "HAVAL-5-160" },
87     { PGPHASHALGO_SHA256,       "SHA256" },
88     { PGPHASHALGO_SHA384,       "SHA384" },
89     { PGPHASHALGO_SHA512,       "SHA512" },
90     { -1,                       "Unknown hash algorithm" },
91 };
92
93 /*@-exportlocal -exportheadervar@*/
94 /*@observer@*/ /*@unchecked@*/
95 struct pgpValTbl_s pgpKeyServerPrefsTbl[] = {
96     { 0x80,                     "No-modify" },
97     { -1,                       "Unknown key server preference" },
98 };
99 /*@=exportlocal =exportheadervar@*/
100
101 struct pgpValTbl_s pgpSubTypeTbl[] = {
102     { PGPSUBTYPE_SIG_CREATE_TIME,"signature creation time" },
103     { PGPSUBTYPE_SIG_EXPIRE_TIME,"signature expiration time" },
104     { PGPSUBTYPE_EXPORTABLE_CERT,"exportable certification" },
105     { PGPSUBTYPE_TRUST_SIG,     "trust signature" },
106     { PGPSUBTYPE_REGEX,         "regular expression" },
107     { PGPSUBTYPE_REVOCABLE,     "revocable" },
108     { PGPSUBTYPE_KEY_EXPIRE_TIME,"key expiration time" },
109     { PGPSUBTYPE_ARR,           "additional recipient request" },
110     { PGPSUBTYPE_PREFER_SYMKEY, "preferred symmetric algorithms" },
111     { PGPSUBTYPE_REVOKE_KEY,    "revocation key" },
112     { PGPSUBTYPE_ISSUER_KEYID,  "issuer key ID" },
113     { PGPSUBTYPE_NOTATION,      "notation data" },
114     { PGPSUBTYPE_PREFER_HASH,   "preferred hash algorithms" },
115     { PGPSUBTYPE_PREFER_COMPRESS,"preferred compression algorithms" },
116     { PGPSUBTYPE_KEYSERVER_PREFERS,"key server preferences" },
117     { PGPSUBTYPE_PREFER_KEYSERVER,"preferred key server" },
118     { PGPSUBTYPE_PRIMARY_USERID,"primary user id" },
119     { PGPSUBTYPE_POLICY_URL,    "policy URL" },
120     { PGPSUBTYPE_KEY_FLAGS,     "key flags" },
121     { PGPSUBTYPE_SIGNER_USERID, "signer's user id" },
122     { PGPSUBTYPE_REVOKE_REASON, "reason for revocation" },
123     { PGPSUBTYPE_FEATURES,      "features" },
124     { PGPSUBTYPE_EMBEDDED_SIG,  "embedded signature" },
125
126     { PGPSUBTYPE_INTERNAL_100,  "internal subpkt type 100" },
127     { PGPSUBTYPE_INTERNAL_101,  "internal subpkt type 101" },
128     { PGPSUBTYPE_INTERNAL_102,  "internal subpkt type 102" },
129     { PGPSUBTYPE_INTERNAL_103,  "internal subpkt type 103" },
130     { PGPSUBTYPE_INTERNAL_104,  "internal subpkt type 104" },
131     { PGPSUBTYPE_INTERNAL_105,  "internal subpkt type 105" },
132     { PGPSUBTYPE_INTERNAL_106,  "internal subpkt type 106" },
133     { PGPSUBTYPE_INTERNAL_107,  "internal subpkt type 107" },
134     { PGPSUBTYPE_INTERNAL_108,  "internal subpkt type 108" },
135     { PGPSUBTYPE_INTERNAL_109,  "internal subpkt type 109" },
136     { PGPSUBTYPE_INTERNAL_110,  "internal subpkt type 110" },
137     { -1,                       "Unknown signature subkey type" },
138 };
139
140 struct pgpValTbl_s pgpTagTbl[] = {
141     { PGPTAG_PUBLIC_SESSION_KEY,"Public-Key Encrypted Session Key" },
142     { PGPTAG_SIGNATURE,         "Signature" },
143     { PGPTAG_SYMMETRIC_SESSION_KEY,"Symmetric-Key Encrypted Session Key" },
144     { PGPTAG_ONEPASS_SIGNATURE, "One-Pass Signature" },
145     { PGPTAG_SECRET_KEY,        "Secret Key" },
146     { PGPTAG_PUBLIC_KEY,        "Public Key" },
147     { PGPTAG_SECRET_SUBKEY,     "Secret Subkey" },
148     { PGPTAG_COMPRESSED_DATA,   "Compressed Data" },
149     { PGPTAG_SYMMETRIC_DATA,    "Symmetrically Encrypted Data" },
150     { PGPTAG_MARKER,            "Marker" },
151     { PGPTAG_LITERAL_DATA,      "Literal Data" },
152     { PGPTAG_TRUST,             "Trust" },
153     { PGPTAG_USER_ID,           "User ID" },
154     { PGPTAG_PUBLIC_SUBKEY,     "Public Subkey" },
155     { PGPTAG_COMMENT_OLD,       "Comment (from OpenPGP draft)" },
156     { PGPTAG_PHOTOID,           "PGP's photo ID" },
157     { PGPTAG_ENCRYPTED_MDC,     "Integrity protected encrypted data" },
158     { PGPTAG_MDC,               "Manipulaion detection code packet" },
159     { PGPTAG_PRIVATE_60,        "Private #60" },
160     { PGPTAG_COMMENT,           "Comment" },
161     { PGPTAG_PRIVATE_62,        "Private #62" },
162     { PGPTAG_CONTROL,           "Control (GPG)" },
163     { -1,                       "Unknown packet tag" },
164 };
165
166 struct pgpValTbl_s pgpArmorTbl[] = {
167     { PGPARMOR_MESSAGE,         "MESSAGE" },
168     { PGPARMOR_PUBKEY,          "PUBLIC KEY BLOCK" },
169     { PGPARMOR_SIGNATURE,       "SIGNATURE" },
170     { PGPARMOR_SIGNED_MESSAGE,  "SIGNED MESSAGE" },
171     { PGPARMOR_FILE,            "ARMORED FILE" },
172     { PGPARMOR_PRIVKEY,         "PRIVATE KEY BLOCK" },
173     { PGPARMOR_SECKEY,          "SECRET KEY BLOCK" },
174     { -1,                       "Unknown armor block" }
175 };
176
177 struct pgpValTbl_s pgpArmorKeyTbl[] = {
178     { PGPARMORKEY_VERSION,      "Version: " },
179     { PGPARMORKEY_COMMENT,      "Comment: " },
180     { PGPARMORKEY_MESSAGEID,    "MessageID: " },
181     { PGPARMORKEY_HASH,         "Hash: " },
182     { PGPARMORKEY_CHARSET,      "Charset: " },
183     { -1,                       "Unknown armor key" }
184 };
185
186 /**
187  * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
188  * @param p             memory to free
189  * @return              NULL always
190  */
191 /*@unused@*/ static inline /*@null@*/ void *
192 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p)
193         /*@modifies p @*/
194 {
195     if (p != NULL)      free((void *)p);
196     return NULL;
197 }
198
199 static void pgpPrtNL(void)
200         /*@globals fileSystem @*/
201         /*@modifies fileSystem @*/
202 {
203     if (!_print) return;
204     fprintf(stderr, "\n");
205 }
206
207 static void pgpPrtInt(const char *pre, int i)
208         /*@globals fileSystem @*/
209         /*@modifies fileSystem @*/
210 {
211     if (!_print) return;
212     if (pre && *pre)
213         fprintf(stderr, "%s", pre);
214     fprintf(stderr, " %d", i);
215 }
216
217 static void pgpPrtStr(const char *pre, const char *s)
218         /*@globals fileSystem @*/
219         /*@modifies fileSystem @*/
220 {
221     if (!_print) return;
222     if (pre && *pre)
223         fprintf(stderr, "%s", pre);
224     fprintf(stderr, " %s", s);
225 }
226
227 static void pgpPrtHex(const char *pre, const byte *p, unsigned int plen)
228         /*@globals fileSystem @*/
229         /*@modifies fileSystem @*/
230 {
231     if (!_print) return;
232     if (pre && *pre)
233         fprintf(stderr, "%s", pre);
234     fprintf(stderr, " %s", pgpHexStr(p, plen));
235 }
236
237 void pgpPrtVal(const char * pre, pgpValTbl vs, byte val)
238         /*@globals fileSystem @*/
239         /*@modifies fileSystem @*/
240 {
241     if (!_print) return;
242     if (pre && *pre)
243         fprintf(stderr, "%s", pre);
244     fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
245 }
246
247 /**
248  */
249 /*@unused@*/ static /*@observer@*/
250 const char * pgpMpiHex(const byte *p)
251         /*@*/
252 {
253     static char prbuf[2048];
254     char *t = prbuf;
255     t = pgpHexCvt(t, p+2, pgpMpiLen(p)-2);
256     return prbuf;
257 }
258
259 /*@-boundswrite@*/
260 /**
261  * @return              0 on success
262  */
263 static int pgpHexSet(const char * pre, int lbits,
264                 /*@out@*/ mpnumber * mpn, const byte * p, const byte * pend)
265         /*@globals fileSystem @*/
266         /*@modifies mpn, fileSystem @*/
267 {
268     unsigned int mbits = pgpMpiBits(p);
269     unsigned int nbits;
270     unsigned int nbytes;
271     char * t;
272     unsigned int ix;
273
274     if ((p + ((mbits+7) >> 3)) > pend)
275         return 1;
276
277     nbits = (lbits > mbits ? lbits : mbits);
278     nbytes = ((nbits + 7) >> 3);
279     t = xmalloc(2*nbytes+1);
280     ix = 2 * ((nbits - mbits) >> 3);
281
282 if (_debug)
283 fprintf(stderr, "*** mbits %u nbits %u nbytes %u t %p[%d] ix %u\n", mbits, nbits, nbytes, t, (2*nbytes+1), ix);
284     if (ix > 0) memset(t, (int)'0', ix);
285     strcpy(t+ix, pgpMpiHex(p));
286 if (_debug)
287 fprintf(stderr, "*** %s %s\n", pre, t);
288     (void) mpnsethex(mpn, t);
289     t = _free(t);
290 if (_debug && _print)
291 fprintf(stderr, "\t %s ", pre), mpfprintln(stderr, mpn->size, mpn->data);
292     return 0;
293 }
294 /*@=boundswrite@*/
295
296 int pgpPrtSubType(const byte *h, unsigned int hlen, pgpSigType sigtype)
297 {
298     const byte *p = h;
299     unsigned plen;
300     int i;
301
302     while (hlen > 0) {
303         i = pgpLen(p, &plen);
304         p += i;
305         hlen -= i;
306
307         pgpPrtVal("    ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL)));
308         if (p[0] & PGPSUBTYPE_CRITICAL)
309             if (_print)
310                 fprintf(stderr, " *CRITICAL*");
311         switch (*p) {
312         case PGPSUBTYPE_PREFER_SYMKEY:  /* preferred symmetric algorithms */
313             for (i = 1; i < plen; i++)
314                 pgpPrtVal(" ", pgpSymkeyTbl, p[i]);
315             /*@switchbreak@*/ break;
316         case PGPSUBTYPE_PREFER_HASH:    /* preferred hash algorithms */
317             for (i = 1; i < plen; i++)
318                 pgpPrtVal(" ", pgpHashTbl, p[i]);
319             /*@switchbreak@*/ break;
320         case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */
321             for (i = 1; i < plen; i++)
322                 pgpPrtVal(" ", pgpCompressionTbl, p[i]);
323             /*@switchbreak@*/ break;
324         case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */
325             for (i = 1; i < plen; i++)
326                 pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
327             /*@switchbreak@*/ break;
328         case PGPSUBTYPE_SIG_CREATE_TIME:
329 /*@-mods -mayaliasunique @*/
330             if (_digp && !(_digp->saved & PGPDIG_SAVED_TIME) &&
331                 (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
332             {
333                 _digp->saved |= PGPDIG_SAVED_TIME;
334                 memcpy(_digp->time, p+1, sizeof(_digp->time));
335             }
336 /*@=mods =mayaliasunique @*/
337             /*@fallthrough@*/
338         case PGPSUBTYPE_SIG_EXPIRE_TIME:
339         case PGPSUBTYPE_KEY_EXPIRE_TIME:
340             if ((plen - 1) == 4) {
341                 time_t t = pgpGrab(p+1, plen-1);
342                 if (_print)
343                    fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
344             } else
345                 pgpPrtHex("", p+1, plen-1);
346             /*@switchbreak@*/ break;
347
348         case PGPSUBTYPE_ISSUER_KEYID:   /* issuer key ID */
349 /*@-mods -mayaliasunique @*/
350             if (_digp && !(_digp->saved & PGPDIG_SAVED_ID) &&
351                 (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
352             {
353                 _digp->saved |= PGPDIG_SAVED_ID;
354                 memcpy(_digp->signid, p+1, sizeof(_digp->signid));
355             }
356 /*@=mods =mayaliasunique @*/
357             /*@fallthrough@*/
358         case PGPSUBTYPE_EXPORTABLE_CERT:
359         case PGPSUBTYPE_TRUST_SIG:
360         case PGPSUBTYPE_REGEX:
361         case PGPSUBTYPE_REVOCABLE:
362         case PGPSUBTYPE_ARR:
363         case PGPSUBTYPE_REVOKE_KEY:
364         case PGPSUBTYPE_NOTATION:
365         case PGPSUBTYPE_PREFER_KEYSERVER:
366         case PGPSUBTYPE_PRIMARY_USERID:
367         case PGPSUBTYPE_POLICY_URL:
368         case PGPSUBTYPE_KEY_FLAGS:
369         case PGPSUBTYPE_SIGNER_USERID:
370         case PGPSUBTYPE_REVOKE_REASON:
371         case PGPSUBTYPE_FEATURES:
372         case PGPSUBTYPE_EMBEDDED_SIG:
373         case PGPSUBTYPE_INTERNAL_100:
374         case PGPSUBTYPE_INTERNAL_101:
375         case PGPSUBTYPE_INTERNAL_102:
376         case PGPSUBTYPE_INTERNAL_103:
377         case PGPSUBTYPE_INTERNAL_104:
378         case PGPSUBTYPE_INTERNAL_105:
379         case PGPSUBTYPE_INTERNAL_106:
380         case PGPSUBTYPE_INTERNAL_107:
381         case PGPSUBTYPE_INTERNAL_108:
382         case PGPSUBTYPE_INTERNAL_109:
383         case PGPSUBTYPE_INTERNAL_110:
384         default:
385             pgpPrtHex("", p+1, plen-1);
386             /*@switchbreak@*/ break;
387         }
388         pgpPrtNL();
389         p += plen;
390         hlen -= plen;
391     }
392     return 0;
393 }
394
395 /*@-varuse =readonlytrans @*/
396 /*@observer@*/ /*@unchecked@*/
397 static const char * pgpSigRSA[] = {
398     " m**d =",
399     NULL,
400 };
401
402 /*@observer@*/ /*@unchecked@*/
403 static const char * pgpSigDSA[] = {
404     "    r =",
405     "    s =",
406     NULL,
407 };
408 /*@=varuse =readonlytrans @*/
409
410 static int pgpPrtSigParams(/*@unused@*/ pgpTag tag, byte pubkey_algo, byte sigtype,
411                 const byte *p, const byte *h, unsigned int hlen)
412         /*@globals fileSystem @*/
413         /*@modifies fileSystem @*/
414 {
415     const byte * pend = h + hlen;
416     int i;
417
418     for (i = 0; p < pend; i++, p += pgpMpiLen(p)) {
419         if (pubkey_algo == PGPPUBKEYALGO_RSA) {
420             if (i >= 1) break;
421             if (_dig &&
422         (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT))
423             {
424                 switch (i) {
425                 case 0:         /* m**d */
426                     (void) mpnsethex(&_dig->c, pgpMpiHex(p));
427 if (_debug && _print)
428 fprintf(stderr, "\t  m**d = "),  mpfprintln(stderr, _dig->c.size, _dig->c.data);
429                     /*@switchbreak@*/ break;
430                 default:
431                     /*@switchbreak@*/ break;
432                 }
433             }
434             pgpPrtStr("", pgpSigRSA[i]);
435         } else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
436             if (i >= 2) break;
437             if (_dig &&
438         (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT))
439             {
440                 int xx;
441                 xx = 0;
442                 switch (i) {
443                 case 0:         /* r */
444                     xx = pgpHexSet(pgpSigDSA[i], 160, &_dig->r, p, pend);
445                     /*@switchbreak@*/ break;
446                 case 1:         /* s */
447                     xx = pgpHexSet(pgpSigDSA[i], 160, &_dig->s, p, pend);
448                     /*@switchbreak@*/ break;
449                 default:
450                     xx = 1;
451                     /*@switchbreak@*/ break;
452                 }
453                 if (xx) return xx;
454             }
455             pgpPrtStr("", pgpSigDSA[i]);
456         } else {
457             if (_print)
458                 fprintf(stderr, "%7d", i);
459         }
460         pgpPrtStr("", pgpMpiStr(p));
461         pgpPrtNL();
462     }
463
464     return 0;
465 }
466
467 int pgpPrtSig(pgpTag tag, const byte *h, unsigned int hlen)
468         /*@globals _digp @*/
469         /*@modifies *_digp @*/
470 {
471     byte version = h[0];
472     byte * p;
473     unsigned plen;
474     int rc;
475
476     switch (version) {
477     case 3:
478     {   pgpPktSigV3 v = (pgpPktSigV3)h;
479         time_t t;
480
481         if (v->hashlen != 5)
482             return 1;
483
484         pgpPrtVal("V3 ", pgpTagTbl, tag);
485         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
486         pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
487         pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
488         pgpPrtNL();
489         t = pgpGrab(v->time, sizeof(v->time));
490         if (_print)
491             fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
492         pgpPrtNL();
493         pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid));
494         plen = pgpGrab(v->signhash16, sizeof(v->signhash16));
495         pgpPrtHex(" signhash16", v->signhash16, sizeof(v->signhash16));
496         pgpPrtNL();
497
498         if (_digp && _digp->pubkey_algo == 0) {
499             _digp->version = v->version;
500             _digp->hashlen = v->hashlen;
501             _digp->sigtype = v->sigtype;
502             _digp->hash = memcpy(xmalloc(v->hashlen), &v->sigtype, v->hashlen);
503             memcpy(_digp->time, v->time, sizeof(_digp->time));
504             memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
505             _digp->pubkey_algo = v->pubkey_algo;
506             _digp->hash_algo = v->hash_algo;
507             memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16));
508         }
509
510         p = ((byte *)v) + sizeof(*v);
511         rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen);
512     }   break;
513     case 4:
514     {   pgpPktSigV4 v = (pgpPktSigV4)h;
515
516         pgpPrtVal("V4 ", pgpTagTbl, tag);
517         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
518         pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
519         pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
520         pgpPrtNL();
521
522         p = &v->hashlen[0];
523         plen = pgpGrab(v->hashlen, sizeof(v->hashlen));
524         p += sizeof(v->hashlen);
525
526         if ((p + plen) > (h + hlen))
527             return 1;
528
529 if (_debug && _print)
530 fprintf(stderr, "   hash[%u] -- %s\n", plen, pgpHexStr(p, plen));
531         if (_digp && _digp->pubkey_algo == 0) {
532             _digp->hashlen = sizeof(*v) + plen;
533             _digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
534         }
535         (void) pgpPrtSubType(p, plen, v->sigtype);
536         p += plen;
537
538         plen = pgpGrab(p,2);
539         p += 2;
540
541         if ((p + plen) > (h + hlen))
542             return 1;
543
544 if (_debug && _print)
545 fprintf(stderr, " unhash[%u] -- %s\n", plen, pgpHexStr(p, plen));
546         (void) pgpPrtSubType(p, plen, v->sigtype);
547         p += plen;
548
549         plen = pgpGrab(p,2);
550         pgpPrtHex(" signhash16", p, 2);
551         pgpPrtNL();
552
553         if (_digp && _digp->pubkey_algo == 0) {
554             _digp->version = v->version;
555             _digp->sigtype = v->sigtype;
556             _digp->pubkey_algo = v->pubkey_algo;
557             _digp->hash_algo = v->hash_algo;
558             memcpy(_digp->signhash16, p, sizeof(_digp->signhash16));
559         }
560
561         p += 2;
562         if (p > (h + hlen))
563             return 1;
564
565         rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen);
566     }   break;
567     default:
568         rc = 1;
569         break;
570     }
571     return rc;
572 }
573
574 /*@-varuse =readonlytrans @*/
575 /*@observer@*/ /*@unchecked@*/
576 static const char * pgpPublicRSA[] = {
577     "    n =",
578     "    e =",
579     NULL,
580 };
581
582 #ifdef NOTYET
583 /*@observer@*/ /*@unchecked@*/
584 static const char * pgpSecretRSA[] = {
585     "    d =",
586     "    p =",
587     "    q =",
588     "    u =",
589     NULL,
590 };
591 #endif
592
593 /*@observer@*/ /*@unchecked@*/
594 static const char * pgpPublicDSA[] = {
595     "    p =",
596     "    q =",
597     "    g =",
598     "    y =",
599     NULL,
600 };
601
602 #ifdef NOTYET
603 /*@observer@*/ /*@unchecked@*/
604 static const char * pgpSecretDSA[] = {
605     "    x =",
606     NULL,
607 };
608 #endif
609
610 /*@observer@*/ /*@unchecked@*/
611 static const char * pgpPublicELGAMAL[] = {
612     "    p =",
613     "    g =",
614     "    y =",
615     NULL,
616 };
617
618 #ifdef NOTYET
619 /*@observer@*/ /*@unchecked@*/
620 static const char * pgpSecretELGAMAL[] = {
621     "    x =",
622     NULL,
623 };
624 #endif
625 /*@=varuse =readonlytrans @*/
626
627 static const byte * pgpPrtPubkeyParams(byte pubkey_algo,
628                 /*@returned@*/ const byte *p, const byte *h, unsigned int hlen)
629         /*@globals fileSystem, internalState @*/
630         /*@modifies fileSystem, internalState @*/
631 {
632     int i;
633
634     for (i = 0; p < &h[hlen]; i++, p += pgpMpiLen(p)) {
635         if (pubkey_algo == PGPPUBKEYALGO_RSA) {
636             if (i >= 2) break;
637             if (_dig) {
638                 switch (i) {
639                 case 0:         /* n */
640                     (void) mpbsethex(&_dig->rsa_pk.n, pgpMpiHex(p));
641 if (_debug && _print)
642 fprintf(stderr, "\t     n = "),  mpfprintln(stderr, _dig->rsa_pk.n.size, _dig->rsa_pk.n.modl);
643                     /*@switchbreak@*/ break;
644                 case 1:         /* e */
645                     (void) mpnsethex(&_dig->rsa_pk.e, pgpMpiHex(p));
646 if (_debug && _print)
647 fprintf(stderr, "\t     e = "),  mpfprintln(stderr, _dig->rsa_pk.e.size, _dig->rsa_pk.e.data);
648                     /*@switchbreak@*/ break;
649                 default:
650                     /*@switchbreak@*/ break;
651                 }
652             }
653             pgpPrtStr("", pgpPublicRSA[i]);
654         } else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
655             if (i >= 4) break;
656             if (_dig) {
657                 switch (i) {
658                 case 0:         /* p */
659                     (void) mpbsethex(&_dig->p, pgpMpiHex(p));
660 if (_debug && _print)
661 fprintf(stderr, "\t     p = "),  mpfprintln(stderr, _dig->p.size, _dig->p.modl);
662                     /*@switchbreak@*/ break;
663                 case 1:         /* q */
664                     (void) mpbsethex(&_dig->q, pgpMpiHex(p));
665 if (_debug && _print)
666 fprintf(stderr, "\t     q = "),  mpfprintln(stderr, _dig->q.size, _dig->q.modl);
667                     /*@switchbreak@*/ break;
668                 case 2:         /* g */
669                     (void) mpnsethex(&_dig->g, pgpMpiHex(p));
670 if (_debug && _print)
671 fprintf(stderr, "\t     g = "),  mpfprintln(stderr, _dig->g.size, _dig->g.data);
672                     /*@switchbreak@*/ break;
673                 case 3:         /* y */
674                     (void) mpnsethex(&_dig->y, pgpMpiHex(p));
675 if (_debug && _print)
676 fprintf(stderr, "\t     y = "),  mpfprintln(stderr, _dig->y.size, _dig->y.data);
677                     /*@switchbreak@*/ break;
678                 default:
679                     /*@switchbreak@*/ break;
680                 }
681             }
682             pgpPrtStr("", pgpPublicDSA[i]);
683         } else if (pubkey_algo == PGPPUBKEYALGO_ELGAMAL_ENCRYPT) {
684             if (i >= 3) break;
685             pgpPrtStr("", pgpPublicELGAMAL[i]);
686         } else {
687             if (_print)
688                 fprintf(stderr, "%7d", i);
689         }
690         pgpPrtStr("", pgpMpiStr(p));
691         pgpPrtNL();
692     }
693
694     return p;
695 }
696
697 static const byte * pgpPrtSeckeyParams(/*@unused@*/ byte pubkey_algo,
698                 /*@returned@*/ const byte *p, const byte *h, unsigned int hlen)
699         /*@globals fileSystem @*/
700         /*@modifies fileSystem @*/
701 {
702     int i;
703
704     switch (*p) {
705     case 0:
706         pgpPrtVal(" ", pgpSymkeyTbl, *p);
707         break;
708     case 255:
709         p++;
710         pgpPrtVal(" ", pgpSymkeyTbl, *p);
711         switch (p[1]) {
712         case 0x00:
713             pgpPrtVal(" simple ", pgpHashTbl, p[2]);
714             p += 2;
715             /*@innerbreak@*/ break;
716         case 0x01:
717             pgpPrtVal(" salted ", pgpHashTbl, p[2]);
718             pgpPrtHex("", p+3, 8);
719             p += 10;
720             /*@innerbreak@*/ break;
721         case 0x03:
722             pgpPrtVal(" iterated/salted ", pgpHashTbl, p[2]);
723             /*@-shiftnegative -shiftimplementation @*/ /* FIX: unsigned cast */
724             i = (16 + (p[11] & 0xf)) << ((p[11] >> 4) + 6);
725             /*@=shiftnegative =shiftimplementation @*/
726             pgpPrtHex("", p+3, 8);
727             pgpPrtInt(" iter", i);
728             p += 11;
729             /*@innerbreak@*/ break;
730         }
731         break;
732     default:
733         pgpPrtVal(" ", pgpSymkeyTbl, *p);
734         pgpPrtHex(" IV", p+1, 8);
735         p += 8;
736         break;
737     }
738     pgpPrtNL();
739
740     p++;
741
742 #ifdef  NOTYET  /* XXX encrypted MPI's need to be handled. */
743     for (i = 0; p < &h[hlen]; i++, p += pgpMpiLen(p)) {
744         if (pubkey_algo == PGPPUBKEYALGO_RSA) {
745             if (pgpSecretRSA[i] == NULL) break;
746             pgpPrtStr("", pgpSecretRSA[i]);
747         } else if (pubkey_algo == PGPPUBKEYALGO_DSA) {
748             if (pgpSecretDSA[i] == NULL) break;
749             pgpPrtStr("", pgpSecretDSA[i]);
750         } else if (pubkey_algo == PGPPUBKEYALGO_ELGAMAL_ENCRYPT) {
751             if (pgpSecretELGAMAL[i] == NULL) break;
752             pgpPrtStr("", pgpSecretELGAMAL[i]);
753         } else {
754             if (_print)
755                 fprintf(stderr, "%7d", i);
756         }
757         pgpPrtStr("", pgpMpiStr(p));
758         pgpPrtNL();
759     }
760 #else
761     pgpPrtHex(" secret", p, (hlen - (p - h) - 2));
762     pgpPrtNL();
763     p += (hlen - (p - h) - 2);
764 #endif
765     pgpPrtHex(" checksum", p, 2);
766     pgpPrtNL();
767
768     return p;
769 }
770
771 int pgpPrtKey(pgpTag tag, const byte *h, unsigned int hlen)
772         /*@globals _digp @*/
773         /*@modifies *_digp @*/
774 {
775     byte version = *h;
776     const byte * p;
777     unsigned plen;
778     time_t t;
779     int rc;
780
781     switch (version) {
782     case 3:
783     {   pgpPktKeyV3 v = (pgpPktKeyV3)h;
784         pgpPrtVal("V3 ", pgpTagTbl, tag);
785         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
786         t = pgpGrab(v->time, sizeof(v->time));
787         if (_print)
788             fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
789         plen = pgpGrab(v->valid, sizeof(v->valid));
790         if (plen != 0)
791             fprintf(stderr, " valid %u days", plen);
792         pgpPrtNL();
793
794         if (_digp && _digp->tag == tag) {
795             _digp->version = v->version;
796             memcpy(_digp->time, v->time, sizeof(_digp->time));
797             _digp->pubkey_algo = v->pubkey_algo;
798         }
799
800         p = ((byte *)v) + sizeof(*v);
801         p = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen);
802         rc = 0;
803     }   break;
804     case 4:
805     {   pgpPktKeyV4 v = (pgpPktKeyV4)h;
806         pgpPrtVal("V4 ", pgpTagTbl, tag);
807         pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
808         t = pgpGrab(v->time, sizeof(v->time));
809         if (_print)
810             fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
811         pgpPrtNL();
812
813         if (_digp && _digp->tag == tag) {
814             _digp->version = v->version;
815             memcpy(_digp->time, v->time, sizeof(_digp->time));
816             _digp->pubkey_algo = v->pubkey_algo;
817         }
818
819         p = ((byte *)v) + sizeof(*v);
820         p = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen);
821         if (!(tag == PGPTAG_PUBLIC_KEY || tag == PGPTAG_PUBLIC_SUBKEY))
822             p = pgpPrtSeckeyParams(v->pubkey_algo, p, h, hlen);
823         rc = 0;
824     }   break;
825     default:
826         rc = 1;
827         break;
828     }
829     return rc;
830 }
831
832 /*@-boundswrite@*/
833 int pgpPrtUserID(pgpTag tag, const byte *h, unsigned int hlen)
834         /*@globals _digp @*/
835         /*@modifies *_digp @*/
836 {
837     pgpPrtVal("", pgpTagTbl, tag);
838     if (_print)
839         fprintf(stderr, " \"%.*s\"", (int)hlen, (const char *)h);
840     pgpPrtNL();
841     if (_digp) {
842         char * t;
843         _digp->userid = t = memcpy(xmalloc(hlen+1), h, hlen);
844         t[hlen] = '\0';
845     }
846     return 0;
847 }
848 /*@=boundswrite@*/
849
850 int pgpPrtComment(pgpTag tag, const byte *h, unsigned int hlen)
851 {
852     int i = hlen;
853
854     pgpPrtVal("", pgpTagTbl, tag);
855     if (_print)
856         fprintf(stderr, " ");
857     while (i > 0) {
858         int j;
859         if (*h >= ' ' && *h <= 'z') {
860             if (_print)
861                 fprintf(stderr, "%s", (const char *)h);
862             j = strlen((const char*)h);
863             while (h[j] == '\0')
864                 j++;
865         } else {
866             pgpPrtHex("", h, i);
867             j = i;
868         }
869         i -= j;
870         h += j;
871     }
872     pgpPrtNL();
873     return 0;
874 }
875
876 int pgpPubkeyFingerprint(const byte * pkt, /*@unused@*/ unsigned int pktlen,
877                 byte * keyid)
878 {
879     const byte *s = pkt;
880     DIGEST_CTX ctx;
881     byte version;
882     int rc = -1;        /* assume failure. */
883
884     if (pkt[0] != 0x99)
885         return rc;
886     version = pkt[3];
887
888     switch (version) {
889     case 3:
890       { pgpPktKeyV3 v = (pgpPktKeyV3) (pkt + 3);
891
892         s += sizeof(pkt[0]) + sizeof(pkt[1]) + sizeof(pkt[2]) + sizeof(*v);
893         switch (v->pubkey_algo) {
894         case PGPPUBKEYALGO_RSA:
895             s += (pgpMpiLen(s) - 8);
896 /*@-boundswrite@*/
897             memmove(keyid, s, 8);
898 /*@=boundswrite@*/
899             rc = 0;
900             /*@innerbreak@*/ break;
901         default:        /* TODO: md5 of mpi bodies (i.e. no length) */
902             /*@innerbreak@*/ break;
903         }
904       } break;
905     case 4:
906       { pgpPktKeyV4 v = (pgpPktKeyV4) (pkt + 3);
907         byte * SHA1 = NULL;
908         int i;
909
910         s += sizeof(pkt[0]) + sizeof(pkt[1]) + sizeof(pkt[2]) + sizeof(*v);
911         switch (v->pubkey_algo) {
912         case PGPPUBKEYALGO_RSA:
913             for (i = 0; i < 2; i++)
914                 s += pgpMpiLen(s);
915             /*@innerbreak@*/ break;
916         case PGPPUBKEYALGO_DSA:
917             for (i = 0; i < 4; i++)
918                 s += pgpMpiLen(s);
919             /*@innerbreak@*/ break;
920         }
921
922         ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
923         (void) rpmDigestUpdate(ctx, pkt, (s-pkt));
924         (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 0);
925
926         s = SHA1 + 12;
927 /*@-boundswrite@*/
928         memmove(keyid, s, 8);
929 /*@=boundswrite@*/
930         rc = 0;
931
932         if (SHA1) free(SHA1);
933       } break;
934     }
935     return rc;
936 }
937
938 int pgpPrtPkt(const byte *pkt, unsigned int pleft)
939 {
940     unsigned int val = *pkt;
941     unsigned int pktlen;
942     pgpTag tag;
943     unsigned int plen;
944     const byte *h;
945     unsigned int hlen = 0;
946     int rc = 0;
947
948     /* XXX can't deal with these. */
949     if (!(val & 0x80))
950         return -1;
951
952     if (val & 0x40) {
953         tag = (val & 0x3f);
954         plen = pgpLen(pkt+1, &hlen);
955     } else {
956         tag = (val >> 2) & 0xf;
957         plen = (1 << (val & 0x3));
958         hlen = pgpGrab(pkt+1, plen);
959     }
960
961     pktlen = 1 + plen + hlen;
962     if (pktlen > pleft)
963         return -1;
964
965     h = pkt + 1 + plen;
966     switch (tag) {
967     case PGPTAG_SIGNATURE:
968         rc = pgpPrtSig(tag, h, hlen);
969         break;
970     case PGPTAG_PUBLIC_KEY:
971         /* Get the public key fingerprint. */
972         if (_digp) {
973 /*@-mods@*/
974             if (!pgpPubkeyFingerprint(pkt, pktlen, _digp->signid))
975                 _digp->saved |= PGPDIG_SAVED_ID;
976             else
977                 memset(_digp->signid, 0, sizeof(_digp->signid));
978 /*@=mods@*/
979         }
980         /*@fallthrough@*/
981     case PGPTAG_PUBLIC_SUBKEY:
982         rc = pgpPrtKey(tag, h, hlen);
983         break;
984     case PGPTAG_SECRET_KEY:
985     case PGPTAG_SECRET_SUBKEY:
986         rc = pgpPrtKey(tag, h, hlen);
987         break;
988     case PGPTAG_USER_ID:
989         rc = pgpPrtUserID(tag, h, hlen);
990         break;
991     case PGPTAG_COMMENT:
992     case PGPTAG_COMMENT_OLD:
993         rc = pgpPrtComment(tag, h, hlen);
994         break;
995
996     case PGPTAG_RESERVED:
997     case PGPTAG_PUBLIC_SESSION_KEY:
998     case PGPTAG_SYMMETRIC_SESSION_KEY:
999     case PGPTAG_COMPRESSED_DATA:
1000     case PGPTAG_SYMMETRIC_DATA:
1001     case PGPTAG_MARKER:
1002     case PGPTAG_LITERAL_DATA:
1003     case PGPTAG_TRUST:
1004     case PGPTAG_PHOTOID:
1005     case PGPTAG_ENCRYPTED_MDC:
1006     case PGPTAG_MDC:
1007     case PGPTAG_PRIVATE_60:
1008     case PGPTAG_PRIVATE_62:
1009     case PGPTAG_CONTROL:
1010     default:
1011         pgpPrtVal("", pgpTagTbl, tag);
1012         pgpPrtHex("", h, hlen);
1013         pgpPrtNL();
1014         break;
1015     }
1016
1017     return (rc ? -1 : pktlen);
1018 }
1019
1020 pgpDig pgpNewDig(void)
1021 {
1022     pgpDig dig = xcalloc(1, sizeof(*dig));
1023     return dig;
1024 }
1025
1026 /*@-boundswrite@*/
1027 void pgpCleanDig(pgpDig dig)
1028 {
1029     if (dig != NULL) {
1030         int i;
1031         dig->signature.userid = _free(dig->signature.userid);
1032         dig->pubkey.userid = _free(dig->pubkey.userid);
1033         dig->signature.hash = _free(dig->signature.hash);
1034         dig->pubkey.hash = _free(dig->pubkey.hash);
1035         /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1036         for (i = 0; i < 4; i++) {
1037             dig->signature.params[i] = _free(dig->signature.params[i]);
1038             dig->pubkey.params[i] = _free(dig->pubkey.params[i]);
1039         }
1040         /*@=unqualifiedtrans@*/
1041
1042         memset(&dig->signature, 0, sizeof(dig->signature));
1043         memset(&dig->pubkey, 0, sizeof(dig->pubkey));
1044
1045         dig->md5 = _free(dig->md5);
1046         dig->sha1 = _free(dig->sha1);
1047         mpnfree(&dig->hm);
1048         mpnfree(&dig->r);
1049         mpnfree(&dig->s);
1050
1051         (void) rsapkFree(&dig->rsa_pk);
1052         mpnfree(&dig->m);
1053         mpnfree(&dig->c);
1054         mpnfree(&dig->rsahm);
1055     }
1056 /*@-nullstate@*/
1057     return;
1058 /*@=nullstate@*/
1059 }
1060 /*@=boundswrite@*/
1061
1062 pgpDig pgpFreeDig(/*@only@*/ /*@null@*/ pgpDig dig)
1063         /*@modifies dig @*/
1064 {
1065     if (dig != NULL) {
1066
1067         /* DUmp the signature/pubkey data. */
1068         pgpCleanDig(dig);
1069
1070         /*@-branchstate@*/
1071         if (dig->hdrsha1ctx != NULL)
1072             (void) rpmDigestFinal(dig->hdrsha1ctx, NULL, NULL, 0);
1073         /*@=branchstate@*/
1074         dig->hdrsha1ctx = NULL;
1075
1076         /*@-branchstate@*/
1077         if (dig->sha1ctx != NULL)
1078             (void) rpmDigestFinal(dig->sha1ctx, NULL, NULL, 0);
1079         /*@=branchstate@*/
1080         dig->sha1ctx = NULL;
1081
1082         mpbfree(&dig->p);
1083         mpbfree(&dig->q);
1084         mpnfree(&dig->g);
1085         mpnfree(&dig->y);
1086         mpnfree(&dig->hm);
1087         mpnfree(&dig->r);
1088         mpnfree(&dig->s);
1089
1090 #ifdef  NOTYET
1091         /*@-branchstate@*/
1092         if (dig->hdrmd5ctx != NULL)
1093             (void) rpmDigestFinal(dig->hdrmd5ctx, NULL, NULL, 0);
1094         /*@=branchstate@*/
1095         dig->hdrmd5ctx = NULL;
1096 #endif
1097
1098         /*@-branchstate@*/
1099         if (dig->md5ctx != NULL)
1100             (void) rpmDigestFinal(dig->md5ctx, NULL, NULL, 0);
1101         /*@=branchstate@*/
1102         dig->md5ctx = NULL;
1103
1104         mpbfree(&dig->rsa_pk.n);
1105         mpnfree(&dig->rsa_pk.e);
1106         mpnfree(&dig->m);
1107         mpnfree(&dig->c);
1108         mpnfree(&dig->hm);
1109
1110         dig = _free(dig);
1111     }
1112     return dig;
1113 }
1114
1115 int pgpPrtPkts(const byte * pkts, unsigned int pktlen, pgpDig dig, int printing)
1116         /*@globals _dig, _digp, _print @*/
1117         /*@modifies _dig, _digp, *_digp, _print @*/
1118 {
1119     unsigned int val = *pkts;
1120     const byte *p;
1121     unsigned int pleft;
1122     int len;
1123
1124     _print = printing;
1125     _dig = dig;
1126     if (dig != NULL && (val & 0x80)) {
1127         pgpTag tag = (val & 0x40) ? (val & 0x3f) : ((val >> 2) & 0xf);
1128         _digp = (tag == PGPTAG_SIGNATURE) ? &_dig->signature : &_dig->pubkey;
1129         _digp->tag = tag;
1130     } else
1131         _digp = NULL;
1132
1133     for (p = pkts, pleft = pktlen; p < (pkts + pktlen); p += len, pleft -= len) {
1134         len = pgpPrtPkt(p, pleft);
1135         if (len <= 0)
1136             return len;
1137         if (len > pleft)        /* XXX shouldn't happen */
1138             break;
1139     }
1140     return 0;
1141 }
1142
1143 /*@-boundswrite@*/
1144 pgpArmor pgpReadPkts(const char * fn, const byte ** pkt, size_t * pktlen)
1145 {
1146     const byte * b = NULL;
1147     size_t blen;
1148     const char * enc = NULL;
1149     const char * crcenc = NULL;
1150     byte * dec;
1151     byte * crcdec;
1152     size_t declen;
1153     size_t crclen;
1154     uint32_t crcpkt, crc;
1155     const char * armortype = NULL;
1156     char * t, * te;
1157     int pstate = 0;
1158     pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP;    /* XXX assume failure */
1159     int rc;
1160
1161     rc = rpmioSlurp(fn, &b, &blen);
1162     if (rc || b == NULL || blen <= 0) {
1163         goto exit;
1164     }
1165
1166     if (pgpIsPkt(b)) {
1167 #ifdef NOTYET   /* XXX ASCII Pubkeys only, please. */
1168         ec = 0; /* XXX fish out pkt type. */
1169 #endif
1170         goto exit;
1171     }
1172
1173 #define TOKEQ(_s, _tok) (!strncmp((_s), (_tok), sizeof(_tok)-1))
1174
1175     for (t = (char *)b; t && *t; t = te) {
1176         if ((te = strchr(t, '\n')) == NULL)
1177             te = t + strlen(t);
1178         else
1179             te++;
1180
1181         switch (pstate) {
1182         case 0:
1183             armortype = NULL;
1184             if (!TOKEQ(t, "-----BEGIN PGP "))
1185                 continue;
1186             t += sizeof("-----BEGIN PGP ")-1;
1187
1188             rc = pgpValTok(pgpArmorTbl, t, te);
1189             if (rc < 0) {
1190                 ec = PGPARMOR_ERR_UNKNOWN_ARMOR_TYPE;
1191                 goto exit;
1192             }
1193             if (rc != PGPARMOR_PUBKEY)  /* XXX ASCII Pubkeys only, please. */
1194                 continue;
1195             armortype = t;
1196
1197             t = te - (sizeof("-----\n")-1);
1198             if (!TOKEQ(t, "-----\n"))
1199                 continue;
1200             *t = '\0';
1201             pstate++;
1202             /*@switchbreak@*/ break;
1203         case 1:
1204             enc = NULL;
1205             rc = pgpValTok(pgpArmorKeyTbl, t, te);
1206             if (rc >= 0)
1207                 continue;
1208             if (*t != '\n') {
1209                 pstate = 0;
1210                 continue;
1211             }
1212             enc = te;           /* Start of encoded packets */
1213             pstate++;
1214             /*@switchbreak@*/ break;
1215         case 2:
1216             crcenc = NULL;
1217             if (*t != '=')
1218                 continue;
1219             *t++ = '\0';        /* Terminate encoded packets */
1220             crcenc = t;         /* Start of encoded crc */
1221             pstate++;
1222             /*@switchbreak@*/ break;
1223         case 3:
1224             pstate = 0;
1225             if (!TOKEQ(t, "-----END PGP ")) {
1226                 ec = PGPARMOR_ERR_NO_END_PGP;
1227                 goto exit;
1228             }
1229             *t = '\0';          /* Terminate encoded crc */
1230             t += sizeof("-----END PGP ")-1;
1231             if (t >= te) continue;
1232
1233             if (armortype == NULL) /* XXX can't happen */
1234                 continue;
1235             rc = strncmp(t, armortype, strlen(armortype));
1236             if (rc)
1237                 continue;
1238
1239             t += strlen(armortype);
1240             if (t >= te) continue;
1241
1242             if (!TOKEQ(t, "-----")) {
1243                 ec = PGPARMOR_ERR_NO_END_PGP;
1244                 goto exit;
1245             }
1246             t += (sizeof("-----")-1);
1247             if (t >= te) continue;
1248             /* XXX permitting \r here is not RFC-2440 compliant <shrug> */
1249             if (!(*t == '\n' || *t == '\r')) continue;
1250
1251             crcdec = NULL;
1252             crclen = 0;
1253             if (b64decode(crcenc, (void **)&crcdec, &crclen) != 0) {
1254                 ec = PGPARMOR_ERR_CRC_DECODE;
1255                 goto exit;
1256             }
1257             crcpkt = pgpGrab(crcdec, crclen);
1258             crcdec = _free(crcdec);
1259             dec = NULL;
1260             declen = 0;
1261             if (b64decode(enc, (void **)&dec, &declen) != 0) {
1262                 ec = PGPARMOR_ERR_BODY_DECODE;
1263                 goto exit;
1264             }
1265             crc = pgpCRC(dec, declen);
1266             if (crcpkt != crc) {
1267                 ec = PGPARMOR_ERR_CRC_CHECK;
1268                 goto exit;
1269             }
1270             b = _free(b);
1271             b = dec;
1272             blen = declen;
1273             ec = PGPARMOR_PUBKEY;       /* XXX ASCII Pubkeys only, please. */
1274             goto exit;
1275             /*@notreached@*/ /*@switchbreak@*/ break;
1276         }
1277     }
1278     ec = PGPARMOR_NONE;
1279
1280 exit:
1281     if (ec > PGPARMOR_NONE && pkt)
1282         *pkt = b;
1283     else if (b != NULL)
1284         b = _free(b);
1285     if (pktlen)
1286         *pktlen = blen;
1287     return ec;
1288 }
1289 /*@=boundswrite@*/
1290
1291 char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
1292 {
1293     const char * enc;
1294     char * t;
1295     size_t nt;
1296     char * val;
1297     int lc;
1298
1299     nt = ((ns + 2) / 3) * 4;
1300     /*@-globs@*/
1301     /* Add additional bytes necessary for eol string(s). */
1302     if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
1303         lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
1304        if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
1305         ++lc;
1306         nt += lc * strlen(b64encode_eolstr);
1307     }
1308     /*@=globs@*/
1309
1310     nt += 512;  /* XXX slop for armor and crc */
1311
1312 /*@-boundswrite@*/
1313     val = t = xmalloc(nt + 1);
1314     *t = '\0';
1315     t = stpcpy(t, "-----BEGIN PGP ");
1316     t = stpcpy(t, pgpValStr(pgpArmorTbl, atype));
1317     /*@-globs@*/
1318     t = stpcpy( stpcpy(t, "-----\nVersion: rpm-"), VERSION);
1319     /*@=globs@*/
1320     t = stpcpy(t, " (beecrypt-4.1.2)\n\n");
1321
1322     if ((enc = b64encode(s, ns)) != NULL) {
1323         t = stpcpy(t, enc);
1324         enc = _free(enc);
1325         if ((enc = b64crc(s, ns)) != NULL) {
1326             *t++ = '=';
1327             t = stpcpy(t, enc);
1328             enc = _free(enc);
1329         }
1330     }
1331         
1332     t = stpcpy(t, "-----END PGP ");
1333     t = stpcpy(t, pgpValStr(pgpArmorTbl, atype));
1334     t = stpcpy(t, "-----\n");
1335 /*@=boundswrite@*/
1336
1337     return val;
1338 }
1339
1340 /*@=boundsread@*/