File: | rpmio/rpmpgp.c |
Warning: | line 364, column 22 The right operand of '+' is a garbage value |
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(stderrstderr, "\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((void*)0); | |||
224 | } | |||
225 | ||||
226 | const char * pgpValString(pgpValType type, uint8_t val) | |||
227 | { | |||
228 | pgpValTbl tbl = pgpValTable(type); | |||
229 | return (tbl != NULL((void*)0)) ? pgpValStr(tbl, val) : NULL((void*)0); | |||
230 | } | |||
231 | ||||
232 | static void pgpPrtHex(const char *pre, const uint8_t *p, size_t plen) | |||
233 | { | |||
234 | char *hex = NULL((void*)0); | |||
235 | if (!_print) return; | |||
236 | if (pre && *pre) | |||
237 | fprintf(stderrstderr, "%s", pre); | |||
238 | hex = pgpHexStr(p, plen); | |||
239 | fprintf(stderrstderr, " %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(stderrstderr, "%s", pre); | |||
248 | fprintf(stderrstderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val); | |||
249 | } | |||
250 | ||||
251 | static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen) | |||
252 | { | |||
253 | if (!_print) return; | |||
254 | if (pre && *pre) | |||
255 | fprintf(stderrstderr, "%s", pre); | |||
256 | if (plen == 4) { | |||
257 | time_t t = pgpGrab(p, plen); | |||
258 | fprintf(stderrstderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t); | |||
259 | } else { | |||
260 | pgpPrtHex("", p+1, plen-1); | |||
261 | } | |||
262 | } | |||
263 | ||||
264 | /** \ingroup rpmpgp | |||
265 | * Return hex formatted representation of a multiprecision integer. | |||
266 | * @param p bytes | |||
267 | * @return hex formatted string (malloc'ed) | |||
268 | */ | |||
269 | static inline | |||
270 | char * pgpMpiStr(const uint8_t *p) | |||
271 | { | |||
272 | char *str = NULL((void*)0); | |||
273 | char *hex = pgpHexStr(p+2, pgpMpiLen(p)-2); | |||
274 | rasprintf(&str, "[%4u]: %s", pgpGrab(p, (size_t) 2), hex); | |||
275 | free(hex); | |||
276 | return str; | |||
277 | } | |||
278 | ||||
279 | /** \ingroup rpmpgp | |||
280 | * Return value of an OpenPGP string. | |||
281 | * @param vs table of (string,value) pairs | |||
282 | * @param s string token to lookup | |||
283 | * @param se end-of-string address | |||
284 | * @return byte value | |||
285 | */ | |||
286 | static inline | |||
287 | int pgpValTok(pgpValTbl vs, const char * s, const char * se) | |||
288 | { | |||
289 | do { | |||
290 | size_t vlen = strlen(vs->str); | |||
291 | if (vlen <= (se-s) && rstreqn(s, vs->str, vlen)) | |||
292 | break; | |||
293 | } while ((++vs)->val != -1); | |||
294 | return vs->val; | |||
295 | } | |||
296 | ||||
297 | /** \ingroup rpmpgp | |||
298 | * Decode length from 1, 2, or 5 octet body length encoding, used in | |||
299 | * new format packet headers and V4 signature subpackets. | |||
300 | * @param s pointer to length encoding buffer | |||
301 | * @param slen buffer size | |||
302 | * @retval *lenp decoded length | |||
303 | * @return no. of bytes used to encode the length, 0 on error | |||
304 | */ | |||
305 | static inline | |||
306 | size_t pgpLen(const uint8_t *s, size_t slen, size_t * lenp) | |||
307 | { | |||
308 | size_t dlen = 0; | |||
309 | size_t lenlen = 0; | |||
310 | ||||
311 | /* | |||
312 | * Callers can only ensure we'll always have the first byte, beyond | |||
313 | * that the required size is not known until we decode it so we need | |||
314 | * to check if we have enough bytes to read the size as we go. | |||
315 | */ | |||
316 | if (*s < 192) { | |||
317 | lenlen = 1; | |||
318 | dlen = *s; | |||
319 | } else if (*s < 255 && slen > 2) { | |||
320 | lenlen = 2; | |||
321 | dlen = (((s[0]) - 192) << 8) + s[1] + 192; | |||
322 | } else if (slen > 5) { | |||
323 | lenlen = 5; | |||
324 | dlen = pgpGrab(s+1, 4); | |||
325 | } | |||
326 | ||||
327 | if (lenlen) | |||
328 | *lenp = dlen; | |||
329 | ||||
330 | return lenlen; | |||
331 | } | |||
332 | ||||
333 | struct pgpPkt { | |||
334 | uint8_t tag; /* decoded PGP tag */ | |||
335 | const uint8_t *head; /* pointer to start of packet (header) */ | |||
336 | const uint8_t *body; /* pointer to packet body */ | |||
337 | size_t blen; /* length of body in bytes */ | |||
338 | }; | |||
339 | ||||
340 | static int decodePkt(const uint8_t *p, size_t plen, struct pgpPkt *pkt) | |||
341 | { | |||
342 | int rc = -1; /* assume failure */ | |||
343 | ||||
344 | /* Valid PGP packet header must always have two or more bytes in it */ | |||
345 | if (p && plen >= 2 && p[0] & 0x80) { | |||
346 | size_t lenlen = 0; | |||
347 | size_t hlen = 0; | |||
348 | ||||
349 | if (p[0] & 0x40) { | |||
350 | /* New format packet, body length encoding in second byte */ | |||
351 | lenlen = pgpLen(p+1, plen-1, &pkt->blen); | |||
352 | pkt->tag = (p[0] & 0x3f); | |||
353 | } else { | |||
354 | /* Old format packet, body length encoding in tag byte */ | |||
355 | lenlen = (1 << (p[0] & 0x3)); | |||
356 | if (plen > lenlen) { | |||
357 | pkt->blen = pgpGrab(p+1, lenlen); | |||
358 | } | |||
359 | pkt->tag = (p[0] >> 2) & 0xf; | |||
360 | } | |||
361 | hlen = lenlen + 1; | |||
362 | ||||
363 | /* Does the packet header and its body fit in our boundaries? */ | |||
364 | if (lenlen && (hlen + pkt->blen <= plen)) { | |||
| ||||
365 | pkt->head = p; | |||
366 | pkt->body = pkt->head + hlen; | |||
367 | rc = 0; | |||
368 | } | |||
369 | } | |||
370 | ||||
371 | return rc; | |||
372 | } | |||
373 | ||||
374 | #define CRC24_INIT0xb704ce 0xb704ce | |||
375 | #define CRC24_POLY0x1864cfb 0x1864cfb | |||
376 | ||||
377 | /** \ingroup rpmpgp | |||
378 | * Return CRC of a buffer. | |||
379 | * @param octets bytes | |||
380 | * @param len no. of bytes | |||
381 | * @return crc of buffer | |||
382 | */ | |||
383 | static inline | |||
384 | unsigned int pgpCRC(const uint8_t *octets, size_t len) | |||
385 | { | |||
386 | unsigned int crc = CRC24_INIT0xb704ce; | |||
387 | size_t i; | |||
388 | ||||
389 | while (len--) { | |||
390 | crc ^= (*octets++) << 16; | |||
391 | for (i = 0; i < 8; i++) { | |||
392 | crc <<= 1; | |||
393 | if (crc & 0x1000000) | |||
394 | crc ^= CRC24_POLY0x1864cfb; | |||
395 | } | |||
396 | } | |||
397 | return crc & 0xffffff; | |||
398 | } | |||
399 | ||||
400 | static int pgpVersion(const uint8_t *h, size_t hlen, uint8_t *version) | |||
401 | { | |||
402 | if (hlen < 1) | |||
403 | return -1; | |||
404 | ||||
405 | *version = h[0]; | |||
406 | return 0; | |||
407 | } | |||
408 | ||||
409 | static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype, | |||
410 | pgpDigParams _digp) | |||
411 | { | |||
412 | const uint8_t *p = h; | |||
413 | size_t plen = 0, i; | |||
414 | ||||
415 | while (hlen > 0) { | |||
416 | i = pgpLen(p, hlen, &plen); | |||
417 | if (i == 0 || plen < 1 || i + plen > hlen) | |||
418 | break; | |||
419 | ||||
420 | p += i; | |||
421 | hlen -= i; | |||
422 | ||||
423 | pgpPrtVal(" ", pgpSubTypeTbl, (p[0]&(~PGPSUBTYPE_CRITICAL))); | |||
424 | if (p[0] & PGPSUBTYPE_CRITICAL) | |||
425 | if (_print) | |||
426 | fprintf(stderrstderr, " *CRITICAL*"); | |||
427 | switch (*p) { | |||
428 | case PGPSUBTYPE_PREFER_SYMKEY: /* preferred symmetric algorithms */ | |||
429 | for (i = 1; i < plen; i++) | |||
430 | pgpPrtVal(" ", pgpSymkeyTbl, p[i]); | |||
431 | break; | |||
432 | case PGPSUBTYPE_PREFER_HASH: /* preferred hash algorithms */ | |||
433 | for (i = 1; i < plen; i++) | |||
434 | pgpPrtVal(" ", pgpHashTbl, p[i]); | |||
435 | break; | |||
436 | case PGPSUBTYPE_PREFER_COMPRESS:/* preferred compression algorithms */ | |||
437 | for (i = 1; i < plen; i++) | |||
438 | pgpPrtVal(" ", pgpCompressionTbl, p[i]); | |||
439 | break; | |||
440 | case PGPSUBTYPE_KEYSERVER_PREFERS:/* key server preferences */ | |||
441 | for (i = 1; i < plen; i++) | |||
442 | pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]); | |||
443 | break; | |||
444 | case PGPSUBTYPE_SIG_CREATE_TIME: | |||
445 | if (!(_digp->saved & PGPDIG_SAVED_TIME(1 << 0)) && | |||
446 | (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE)) | |||
447 | { | |||
448 | if (plen-1 != sizeof(_digp->time)) | |||
449 | break; | |||
450 | _digp->saved |= PGPDIG_SAVED_TIME(1 << 0); | |||
451 | _digp->time = pgpGrab(p+1, sizeof(_digp->time)); | |||
452 | } | |||
453 | case PGPSUBTYPE_SIG_EXPIRE_TIME: | |||
454 | case PGPSUBTYPE_KEY_EXPIRE_TIME: | |||
455 | pgpPrtTime(" ", p+1, plen-1); | |||
456 | break; | |||
457 | ||||
458 | case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */ | |||
459 | if (!(_digp->saved & PGPDIG_SAVED_ID(1 << 1)) && | |||
460 | (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE)) | |||
461 | { | |||
462 | if (plen-1 != sizeof(_digp->signid)) | |||
463 | break; | |||
464 | _digp->saved |= PGPDIG_SAVED_ID(1 << 1); | |||
465 | memcpy(_digp->signid, p+1, sizeof(_digp->signid)); | |||
466 | } | |||
467 | case PGPSUBTYPE_EXPORTABLE_CERT: | |||
468 | case PGPSUBTYPE_TRUST_SIG: | |||
469 | case PGPSUBTYPE_REGEX: | |||
470 | case PGPSUBTYPE_REVOCABLE: | |||
471 | case PGPSUBTYPE_ARR: | |||
472 | case PGPSUBTYPE_REVOKE_KEY: | |||
473 | case PGPSUBTYPE_NOTATION: | |||
474 | case PGPSUBTYPE_PREFER_KEYSERVER: | |||
475 | case PGPSUBTYPE_PRIMARY_USERID: | |||
476 | case PGPSUBTYPE_POLICY_URL: | |||
477 | case PGPSUBTYPE_KEY_FLAGS: | |||
478 | case PGPSUBTYPE_SIGNER_USERID: | |||
479 | case PGPSUBTYPE_REVOKE_REASON: | |||
480 | case PGPSUBTYPE_FEATURES: | |||
481 | case PGPSUBTYPE_EMBEDDED_SIG: | |||
482 | case PGPSUBTYPE_INTERNAL_100: | |||
483 | case PGPSUBTYPE_INTERNAL_101: | |||
484 | case PGPSUBTYPE_INTERNAL_102: | |||
485 | case PGPSUBTYPE_INTERNAL_103: | |||
486 | case PGPSUBTYPE_INTERNAL_104: | |||
487 | case PGPSUBTYPE_INTERNAL_105: | |||
488 | case PGPSUBTYPE_INTERNAL_106: | |||
489 | case PGPSUBTYPE_INTERNAL_107: | |||
490 | case PGPSUBTYPE_INTERNAL_108: | |||
491 | case PGPSUBTYPE_INTERNAL_109: | |||
492 | case PGPSUBTYPE_INTERNAL_110: | |||
493 | default: | |||
494 | pgpPrtHex("", p+1, plen-1); | |||
495 | break; | |||
496 | } | |||
497 | pgpPrtNL(); | |||
498 | p += plen; | |||
499 | hlen -= plen; | |||
500 | } | |||
501 | return (hlen != 0); /* non-zero hlen is an error */ | |||
502 | } | |||
503 | ||||
504 | pgpDigAlg pgpDigAlgFree(pgpDigAlg alg) | |||
505 | { | |||
506 | if (alg) { | |||
507 | if (alg->free) | |||
508 | alg->free(alg); | |||
509 | free(alg); | |||
510 | } | |||
511 | return NULL((void*)0); | |||
512 | } | |||
513 | ||||
514 | static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, | |||
515 | const uint8_t *p, const uint8_t *h, size_t hlen, | |||
516 | pgpDigParams sigp) | |||
517 | { | |||
518 | int rc = 1; /* assume failure */ | |||
519 | const uint8_t * pend = h + hlen; | |||
520 | int i; | |||
521 | pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo); | |||
522 | ||||
523 | for (i = 0; i < sigalg->mpis && p + 2 <= pend; i++) { | |||
524 | int mpil = pgpMpiLen(p); | |||
525 | if (p + mpil > pend) | |||
526 | break; | |||
527 | if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) { | |||
528 | if (sigalg->setmpi(sigalg, i, p)) | |||
529 | break; | |||
530 | } | |||
531 | p += mpil; | |||
532 | } | |||
533 | ||||
534 | /* Does the size and number of MPI's match our expectations? */ | |||
535 | if (p == pend && i == sigalg->mpis) | |||
536 | rc = 0; | |||
537 | ||||
538 | /* We can't handle more than one sig at a time */ | |||
539 | if (rc == 0 && sigp->alg == NULL((void*)0) && sigp->tag == PGPTAG_SIGNATURE) | |||
540 | sigp->alg = sigalg; | |||
541 | else | |||
542 | pgpDigAlgFree(sigalg); | |||
543 | ||||
544 | return rc; | |||
545 | } | |||
546 | ||||
547 | static int pgpGet(const uint8_t *s, size_t nbytes, const uint8_t *send, | |||
548 | unsigned int *valp) | |||
549 | { | |||
550 | int rc = -1; | |||
551 | ||||
552 | if (s + nbytes <= send) { | |||
553 | *valp = pgpGrab(s, nbytes); | |||
554 | rc = 0; | |||
555 | } | |||
556 | ||||
557 | return rc; | |||
558 | } | |||
559 | ||||
560 | static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, | |||
561 | pgpDigParams _digp) | |||
562 | { | |||
563 | uint8_t version = 0; | |||
564 | uint8_t * p; | |||
565 | unsigned int plen; | |||
566 | int rc = 1; | |||
567 | ||||
568 | if (pgpVersion(h, hlen, &version)) | |||
569 | return rc; | |||
570 | ||||
571 | switch (version) { | |||
572 | case 3: | |||
573 | { pgpPktSigV3 v = (pgpPktSigV3)h; | |||
574 | ||||
575 | if (hlen <= sizeof(*v) || v->hashlen != 5) | |||
576 | return 1; | |||
577 | ||||
578 | pgpPrtVal("V3 ", pgpTagTbl, tag); | |||
579 | pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo); | |||
580 | pgpPrtVal(" ", pgpHashTbl, v->hash_algo); | |||
581 | pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype); | |||
582 | pgpPrtNL(); | |||
583 | pgpPrtTime(" ", v->time, sizeof(v->time)); | |||
584 | pgpPrtNL(); | |||
585 | pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid)); | |||
586 | plen = pgpGrab(v->signhash16, sizeof(v->signhash16)); | |||
587 | pgpPrtHex(" signhash16", v->signhash16, sizeof(v->signhash16)); | |||
588 | pgpPrtNL(); | |||
589 | ||||
590 | if (_digp->pubkey_algo == 0) { | |||
591 | _digp->version = v->version; | |||
592 | _digp->hashlen = v->hashlen; | |||
593 | _digp->sigtype = v->sigtype; | |||
594 | _digp->hash = memcpy(xmalloc(v->hashlen)rmalloc((v->hashlen)), &v->sigtype, v->hashlen); | |||
595 | _digp->time = pgpGrab(v->time, sizeof(v->time)); | |||
596 | memcpy(_digp->signid, v->signid, sizeof(_digp->signid)); | |||
597 | _digp->pubkey_algo = v->pubkey_algo; | |||
598 | _digp->hash_algo = v->hash_algo; | |||
599 | memcpy(_digp->signhash16, v->signhash16, sizeof(_digp->signhash16)); | |||
600 | } | |||
601 | ||||
602 | p = ((uint8_t *)v) + sizeof(*v); | |||
603 | rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); | |||
604 | } break; | |||
605 | case 4: | |||
606 | { pgpPktSigV4 v = (pgpPktSigV4)h; | |||
607 | ||||
608 | if (hlen <= sizeof(*v)) | |||
609 | return 1; | |||
610 | ||||
611 | pgpPrtVal("V4 ", pgpTagTbl, tag); | |||
612 | pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo); | |||
613 | pgpPrtVal(" ", pgpHashTbl, v->hash_algo); | |||
614 | pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype); | |||
615 | pgpPrtNL(); | |||
616 | ||||
617 | p = &v->hashlen[0]; | |||
618 | if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen)) | |||
619 | return 1; | |||
620 | p += sizeof(v->hashlen); | |||
621 | ||||
622 | if ((p + plen) > (h + hlen)) | |||
623 | return 1; | |||
624 | ||||
625 | if (_digp->pubkey_algo == 0) { | |||
626 | _digp->hashlen = sizeof(*v) + plen; | |||
627 | _digp->hash = memcpy(xmalloc(_digp->hashlen)rmalloc((_digp->hashlen)), v, _digp->hashlen); | |||
628 | } | |||
629 | if (pgpPrtSubType(p, plen, v->sigtype, _digp)) | |||
630 | return 1; | |||
631 | p += plen; | |||
632 | ||||
633 | if (pgpGet(p, 2, h + hlen, &plen)) | |||
634 | return 1; | |||
635 | p += 2; | |||
636 | ||||
637 | if ((p + plen) > (h + hlen)) | |||
638 | return 1; | |||
639 | ||||
640 | if (pgpPrtSubType(p, plen, v->sigtype, _digp)) | |||
641 | return 1; | |||
642 | p += plen; | |||
643 | ||||
644 | if (pgpGet(p, 2, h + hlen, &plen)) | |||
645 | return 1; | |||
646 | pgpPrtHex(" signhash16", p, 2); | |||
647 | pgpPrtNL(); | |||
648 | ||||
649 | if (_digp->pubkey_algo == 0) { | |||
650 | _digp->version = v->version; | |||
651 | _digp->sigtype = v->sigtype; | |||
652 | _digp->pubkey_algo = v->pubkey_algo; | |||
653 | _digp->hash_algo = v->hash_algo; | |||
654 | memcpy(_digp->signhash16, p, sizeof(_digp->signhash16)); | |||
655 | } | |||
656 | ||||
657 | p += 2; | |||
658 | if (p > (h + hlen)) | |||
659 | return 1; | |||
660 | ||||
661 | rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); | |||
662 | } break; | |||
663 | default: | |||
664 | rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n")dcgettext ("rpm", "Unsupported version of key: V%d\n", 5), version); | |||
665 | rc = 1; | |||
666 | break; | |||
667 | } | |||
668 | return rc; | |||
669 | } | |||
670 | ||||
671 | char * pgpHexStr(const uint8_t *p, size_t plen) | |||
672 | { | |||
673 | char *t, *str; | |||
674 | str = t = xmalloc(plen * 2 + 1)rmalloc((plen * 2 + 1)); | |||
675 | static char const hex[] = "0123456789abcdef"; | |||
676 | while (plen-- > 0) { | |||
677 | size_t i; | |||
678 | i = *p++; | |||
679 | *t++ = hex[ (i >> 4) & 0xf ]; | |||
680 | *t++ = hex[ (i ) & 0xf ]; | |||
681 | } | |||
682 | *t = '\0'; | |||
683 | return str; | |||
684 | } | |||
685 | ||||
686 | static int pgpPrtPubkeyParams(uint8_t pubkey_algo, | |||
687 | const uint8_t *p, const uint8_t *h, size_t hlen, | |||
688 | pgpDigParams keyp) | |||
689 | { | |||
690 | int rc = 1; | |||
691 | const uint8_t *pend = h + hlen; | |||
692 | int i; | |||
693 | pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo); | |||
694 | ||||
695 | for (i = 0; i < keyalg->mpis && p + 2 <= pend; i++) { | |||
696 | int mpil = pgpMpiLen(p); | |||
697 | if (p + mpil > pend) | |||
698 | break; | |||
699 | if (keyalg->setmpi(keyalg, i, p)) | |||
700 | break; | |||
701 | p += mpil; | |||
702 | } | |||
703 | ||||
704 | /* Does the size and number of MPI's match our expectations? */ | |||
705 | if (p == pend && i == keyalg->mpis) | |||
706 | rc = 0; | |||
707 | ||||
708 | /* We can't handle more than one key at a time */ | |||
709 | if (rc == 0 && keyp->alg == NULL((void*)0) && (keyp->tag == PGPTAG_PUBLIC_KEY || | |||
710 | keyp->tag == PGPTAG_PUBLIC_SUBKEY)) | |||
711 | ||||
712 | keyp->alg = keyalg; | |||
713 | else | |||
714 | pgpDigAlgFree(keyalg); | |||
715 | ||||
716 | return rc; | |||
717 | } | |||
718 | ||||
719 | static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, | |||
720 | pgpDigParams _digp) | |||
721 | { | |||
722 | uint8_t version = 0; | |||
723 | const uint8_t * p = NULL((void*)0); | |||
724 | int rc = 1; | |||
725 | ||||
726 | if (pgpVersion(h, hlen, &version)) | |||
727 | return rc; | |||
728 | ||||
729 | /* We only permit V4 keys, V3 keys are long long since deprecated */ | |||
730 | switch (version) { | |||
731 | case 4: | |||
732 | { pgpPktKeyV4 v = (pgpPktKeyV4)h; | |||
733 | ||||
734 | if (hlen > sizeof(*v)) { | |||
735 | pgpPrtVal("V4 ", pgpTagTbl, tag); | |||
736 | pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo); | |||
737 | pgpPrtTime(" ", v->time, sizeof(v->time)); | |||
738 | pgpPrtNL(); | |||
739 | ||||
740 | /* If _digp->hash is not NULL then signature is already loaded */ | |||
741 | if (_digp->hash == NULL((void*)0)) { | |||
742 | _digp->version = v->version; | |||
743 | _digp->time = pgpGrab(v->time, sizeof(v->time)); | |||
744 | _digp->pubkey_algo = v->pubkey_algo; | |||
745 | } | |||
746 | ||||
747 | p = ((uint8_t *)v) + sizeof(*v); | |||
748 | rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp); | |||
749 | } | |||
750 | } break; | |||
751 | default: | |||
752 | rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n")dcgettext ("rpm", "Unsupported version of key: V%d\n", 5), h[0]); | |||
753 | } | |||
754 | return rc; | |||
755 | } | |||
756 | ||||
757 | static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen, | |||
758 | pgpDigParams _digp) | |||
759 | { | |||
760 | pgpPrtVal("", pgpTagTbl, tag); | |||
761 | if (_print) | |||
762 | fprintf(stderrstderr, " \"%.*s\"", (int)hlen, (const char *)h); | |||
763 | pgpPrtNL(); | |||
764 | free(_digp->userid); | |||
765 | _digp->userid = memcpy(xmalloc(hlen+1)rmalloc((hlen+1)), h, hlen); | |||
766 | _digp->userid[hlen] = '\0'; | |||
767 | return 0; | |||
768 | } | |||
769 | ||||
770 | int pgpPubkeyFingerprint(const uint8_t *h, size_t hlen, | |||
771 | uint8_t **fp, size_t *fplen) | |||
772 | { | |||
773 | int rc = -1; /* assume failure */ | |||
774 | const uint8_t *se; | |||
775 | const uint8_t *pend = h + hlen; | |||
776 | uint8_t version = 0; | |||
777 | ||||
778 | if (pgpVersion(h, hlen, &version)) | |||
779 | return rc; | |||
780 | ||||
781 | /* We only permit V4 keys, V3 keys are long long since deprecated */ | |||
782 | switch (version) { | |||
783 | case 4: | |||
784 | { pgpPktKeyV4 v = (pgpPktKeyV4) (h); | |||
785 | int mpis = -1; | |||
786 | ||||
787 | /* Packet must be larger than v to have room for the required MPIs */ | |||
788 | if (hlen > sizeof(*v)) { | |||
789 | switch (v->pubkey_algo) { | |||
790 | case PGPPUBKEYALGO_RSA: | |||
791 | mpis = 2; | |||
792 | break; | |||
793 | case PGPPUBKEYALGO_DSA: | |||
794 | mpis = 4; | |||
795 | break; | |||
796 | } | |||
797 | } | |||
798 | ||||
799 | se = (uint8_t *)(v + 1); | |||
800 | while (se < pend && mpis-- > 0) | |||
801 | se += pgpMpiLen(se); | |||
802 | ||||
803 | /* Does the size and number of MPI's match our expectations? */ | |||
804 | if (se == pend && mpis == 0) { | |||
805 | DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); | |||
806 | uint8_t *d = NULL((void*)0); | |||
807 | size_t dlen = 0; | |||
808 | int i = se - h; | |||
809 | uint8_t in[3] = { 0x99, (i >> 8), i }; | |||
810 | ||||
811 | (void) rpmDigestUpdate(ctx, in, 3); | |||
812 | (void) rpmDigestUpdate(ctx, h, i); | |||
813 | (void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0); | |||
814 | ||||
815 | if (dlen == 20) { | |||
816 | rc = 0; | |||
817 | *fp = d; | |||
818 | *fplen = dlen; | |||
819 | } else { | |||
820 | free(d); | |||
821 | } | |||
822 | } | |||
823 | ||||
824 | } break; | |||
825 | default: | |||
826 | rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n")dcgettext ("rpm", "Unsupported version of key: V%d\n", 5), version); | |||
827 | } | |||
828 | return rc; | |||
829 | } | |||
830 | ||||
831 | static int getKeyID(const uint8_t *h, size_t hlen, pgpKeyID_t keyid) | |||
832 | { | |||
833 | uint8_t *fp = NULL((void*)0); | |||
834 | size_t fplen = 0; | |||
835 | int rc = pgpPubkeyFingerprint(h, hlen, &fp, &fplen); | |||
836 | if (fp && fplen > 8) { | |||
837 | memcpy(keyid, (fp + (fplen-8)), 8); | |||
838 | free(fp); | |||
839 | } | |||
840 | return rc; | |||
841 | } | |||
842 | ||||
843 | int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid) | |||
844 | { | |||
845 | struct pgpPkt p; | |||
846 | ||||
847 | if (decodePkt(pkt, pktlen, &p)) | |||
848 | return -1; | |||
849 | ||||
850 | return getKeyID(p.body, p.blen, keyid); | |||
851 | } | |||
852 | ||||
853 | static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp) | |||
854 | { | |||
855 | int rc = 0; | |||
856 | ||||
857 | switch (p->tag) { | |||
858 | case PGPTAG_SIGNATURE: | |||
859 | rc = pgpPrtSig(p->tag, p->body, p->blen, _digp); | |||
860 | break; | |||
861 | case PGPTAG_PUBLIC_KEY: | |||
862 | /* Get the public key Key ID. */ | |||
863 | if (!getKeyID(p->body, p->blen, _digp->signid)) | |||
864 | _digp->saved |= PGPDIG_SAVED_ID(1 << 1); | |||
865 | else | |||
866 | memset(_digp->signid, 0, sizeof(_digp->signid)); | |||
867 | rc = pgpPrtKey(p->tag, p->body, p->blen, _digp); | |||
868 | break; | |||
869 | case PGPTAG_USER_ID: | |||
870 | rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp); | |||
871 | break; | |||
872 | case PGPTAG_RESERVED: | |||
873 | rc = -1; | |||
874 | break; | |||
875 | case PGPTAG_COMMENT: | |||
876 | case PGPTAG_COMMENT_OLD: | |||
877 | case PGPTAG_PUBLIC_SUBKEY: | |||
878 | case PGPTAG_SECRET_KEY: | |||
879 | case PGPTAG_SECRET_SUBKEY: | |||
880 | case PGPTAG_PUBLIC_SESSION_KEY: | |||
881 | case PGPTAG_SYMMETRIC_SESSION_KEY: | |||
882 | case PGPTAG_COMPRESSED_DATA: | |||
883 | case PGPTAG_SYMMETRIC_DATA: | |||
884 | case PGPTAG_MARKER: | |||
885 | case PGPTAG_LITERAL_DATA: | |||
886 | case PGPTAG_TRUST: | |||
887 | case PGPTAG_PHOTOID: | |||
888 | case PGPTAG_ENCRYPTED_MDC: | |||
889 | case PGPTAG_MDC: | |||
890 | case PGPTAG_PRIVATE_60: | |||
891 | case PGPTAG_PRIVATE_62: | |||
892 | case PGPTAG_CONTROL: | |||
893 | default: | |||
894 | pgpPrtVal("", pgpTagTbl, p->tag); | |||
895 | pgpPrtHex("", p->body, p->blen); | |||
896 | pgpPrtNL(); | |||
897 | break; | |||
898 | } | |||
899 | ||||
900 | return rc; | |||
901 | } | |||
902 | ||||
903 | pgpDig pgpNewDig(void) | |||
904 | { | |||
905 | pgpDig dig = xcalloc(1, sizeof(*dig))rcalloc((1), (sizeof(*dig))); | |||
906 | ||||
907 | return dig; | |||
908 | } | |||
909 | ||||
910 | pgpDigParams pgpDigParamsFree(pgpDigParams digp) | |||
911 | { | |||
912 | if (digp) { | |||
913 | pgpDigAlgFree(digp->alg); | |||
914 | free(digp->userid); | |||
915 | free(digp->hash); | |||
916 | memset(digp, 0, sizeof(*digp)); | |||
917 | free(digp); | |||
918 | } | |||
919 | return NULL((void*)0); | |||
920 | } | |||
921 | ||||
922 | void pgpCleanDig(pgpDig dig) | |||
923 | { | |||
924 | if (dig != NULL((void*)0)) { | |||
925 | pgpDigParamsFree(dig->signature); | |||
926 | pgpDigParamsFree(dig->pubkey); | |||
927 | memset(dig, 0, sizeof(*dig)); | |||
928 | } | |||
929 | return; | |||
930 | } | |||
931 | ||||
932 | pgpDig pgpFreeDig(pgpDig dig) | |||
933 | { | |||
934 | if (dig != NULL((void*)0)) { | |||
935 | ||||
936 | /* DUmp the signature/pubkey data. */ | |||
937 | pgpCleanDig(dig); | |||
938 | dig = _free(dig)rfree((dig)); | |||
939 | } | |||
940 | return dig; | |||
941 | } | |||
942 | ||||
943 | pgpDigParams pgpDigGetParams(pgpDig dig, unsigned int pkttype) | |||
944 | { | |||
945 | pgpDigParams params = NULL((void*)0); | |||
946 | if (dig) { | |||
947 | switch (pkttype) { | |||
948 | case PGPTAG_SIGNATURE: | |||
949 | params = dig->signature; | |||
950 | break; | |||
951 | case PGPTAG_PUBLIC_KEY: | |||
952 | params = dig->pubkey; | |||
953 | break; | |||
954 | } | |||
955 | } | |||
956 | return params; | |||
957 | } | |||
958 | ||||
959 | int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2) | |||
960 | { | |||
961 | int rc = 1; /* assume different, eg if either is NULL */ | |||
962 | if (p1 && p2) { | |||
963 | /* XXX Should we compare something else too? */ | |||
964 | if (p1->tag != p2->tag) | |||
965 | goto exit; | |||
966 | if (p1->hash_algo != p2->hash_algo) | |||
967 | goto exit; | |||
968 | if (p1->pubkey_algo != p2->pubkey_algo) | |||
969 | goto exit; | |||
970 | if (p1->version != p2->version) | |||
971 | goto exit; | |||
972 | if (p1->sigtype != p2->sigtype) | |||
973 | goto exit; | |||
974 | if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0) | |||
975 | goto exit; | |||
976 | if (p1->userid && p2->userid && strcmp(p1->userid, p2->userid) != 0) | |||
977 | goto exit; | |||
978 | ||||
979 | /* Parameters match ... at least for our purposes */ | |||
980 | rc = 0; | |||
981 | } | |||
982 | exit: | |||
983 | return rc; | |||
984 | } | |||
985 | ||||
986 | unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype) | |||
987 | { | |||
988 | unsigned int algo = 0; /* assume failure */ | |||
989 | if (digp) { | |||
990 | switch (algotype) { | |||
991 | case PGPVAL_PUBKEYALGO: | |||
992 | algo = digp->pubkey_algo; | |||
993 | break; | |||
994 | case PGPVAL_HASHALGO: | |||
995 | algo = digp->hash_algo; | |||
996 | break; | |||
997 | } | |||
998 | } | |||
999 | return algo; | |||
1000 | } | |||
1001 | ||||
1002 | int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, | |||
1003 | pgpDigParams * ret) | |||
1004 | { | |||
1005 | const uint8_t *p = pkts; | |||
1006 | const uint8_t *pend = pkts + pktlen; | |||
1007 | pgpDigParams digp = NULL((void*)0); | |||
1008 | struct pgpPkt pkt; | |||
1009 | int rc = -1; /* assume failure */ | |||
1010 | ||||
1011 | while (p < pend) { | |||
1012 | if (decodePkt(p, (pend - p), &pkt)) | |||
1013 | break; | |||
1014 | ||||
1015 | if (digp == NULL((void*)0)) { | |||
1016 | if (pkttype && pkt.tag != pkttype) { | |||
1017 | break; | |||
1018 | } else { | |||
1019 | digp = xcalloc(1, sizeof(*digp))rcalloc((1), (sizeof(*digp))); | |||
1020 | digp->tag = pkt.tag; | |||
1021 | } | |||
1022 | } | |||
1023 | ||||
1024 | if (pgpPrtPkt(&pkt, digp)) | |||
1025 | break; | |||
1026 | ||||
1027 | p += (pkt.body - pkt.head) + pkt.blen; | |||
1028 | } | |||
1029 | ||||
1030 | rc = (digp && (p == pend)) ? 0 : -1; | |||
1031 | ||||
1032 | if (ret && rc == 0) { | |||
1033 | *ret = digp; | |||
1034 | } else { | |||
1035 | pgpDigParamsFree(digp); | |||
1036 | } | |||
1037 | return rc; | |||
1038 | } | |||
1039 | ||||
1040 | int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen, | |||
1041 | pgpDigParams mainkey, pgpDigParams **subkeys, | |||
1042 | int *subkeysCount) | |||
1043 | { | |||
1044 | const uint8_t *p = pkts; | |||
1045 | const uint8_t *pend = pkts + pktlen; | |||
1046 | pgpDigParams *digps = NULL((void*)0); | |||
1047 | int count = 0; | |||
1048 | int alloced = 10; | |||
1049 | struct pgpPkt pkt; | |||
1050 | int rc, i; | |||
1051 | ||||
1052 | digps = xmalloc(alloced * sizeof(*digps))rmalloc((alloced * sizeof(*digps))); | |||
1053 | ||||
1054 | while (p < pend) { | |||
1055 | if (decodePkt(p, (pend - p), &pkt)) | |||
1056 | break; | |||
1057 | ||||
1058 | p += (pkt.body - pkt.head) + pkt.blen; | |||
1059 | ||||
1060 | if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) { | |||
1061 | if (count == alloced) { | |||
1062 | alloced <<= 1; | |||
1063 | digps = xrealloc(digps, alloced * sizeof(*digps))rrealloc((digps), (alloced * sizeof(*digps))); | |||
1064 | } | |||
1065 | ||||
1066 | digps[count] = xcalloc(1, sizeof(**digps))rcalloc((1), (sizeof(**digps))); | |||
1067 | digps[count]->tag = PGPTAG_PUBLIC_SUBKEY; | |||
1068 | /* Copy UID from main key to subkey */ | |||
1069 | digps[count]->userid = xstrdup(mainkey->userid)rstrdup((mainkey->userid)); | |||
1070 | ||||
1071 | if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) { | |||
1072 | pgpDigParamsFree(digps[count]); | |||
1073 | continue; | |||
1074 | } | |||
1075 | ||||
1076 | if (pgpPrtKey(pkt.tag, pkt.body, pkt.blen, digps[count])) { | |||
1077 | pgpDigParamsFree(digps[count]); | |||
1078 | continue; | |||
1079 | } | |||
1080 | count++; | |||
1081 | } | |||
1082 | } | |||
1083 | rc = (p == pend) ? 0 : -1; | |||
1084 | ||||
1085 | if (rc == 0) { | |||
1086 | *subkeys = xrealloc(digps, count * sizeof(*digps))rrealloc((digps), (count * sizeof(*digps))); | |||
1087 | *subkeysCount = count; | |||
1088 | } else { | |||
1089 | for (i = 0; i < count; i++) | |||
1090 | pgpDigParamsFree(digps[i]); | |||
1091 | free(digps); | |||
1092 | } | |||
1093 | ||||
1094 | return rc; | |||
1095 | } | |||
1096 | ||||
1097 | int pgpPrtPkts(const uint8_t * pkts, size_t pktlen, pgpDig dig, int printing) | |||
1098 | { | |||
1099 | int rc; | |||
1100 | pgpDigParams digp = NULL((void*)0); | |||
1101 | ||||
1102 | _print = printing; | |||
1103 | ||||
1104 | rc = pgpPrtParams(pkts, pktlen, 0, &digp); | |||
1105 | ||||
1106 | if (dig && rc == 0) { | |||
1107 | if (digp->tag == PGPTAG_SIGNATURE) { | |||
1108 | pgpDigParamsFree(dig->signature); | |||
1109 | dig->signature = digp; | |||
1110 | } else { | |||
1111 | pgpDigParamsFree(dig->pubkey); | |||
1112 | dig->pubkey = digp; | |||
1113 | } | |||
1114 | } else { | |||
1115 | pgpDigParamsFree(digp); | |||
1116 | } | |||
1117 | ||||
1118 | return rc; | |||
1119 | } | |||
1120 | ||||
1121 | char *pgpIdentItem(pgpDigParams digp) | |||
1122 | { | |||
1123 | char *id = NULL((void*)0); | |||
1124 | if (digp) { | |||
1125 | ||||
1126 | char *signid = pgpHexStr(digp->signid+4, sizeof(digp->signid)-4); | |||
1127 | rasprintf(&id, _("V%d %s/%s %s, key ID %s")dcgettext ("rpm", "V%d %s/%s %s, key ID %s", 5), | |||
1128 | digp->version, | |||
1129 | pgpValStr(pgpPubkeyTbl, digp->pubkey_algo), | |||
1130 | pgpValStr(pgpHashTbl, digp->hash_algo), | |||
1131 | pgpValStr(pgpTagTbl, digp->tag), | |||
1132 | signid); | |||
1133 | free(signid); | |||
1134 | } else { | |||
1135 | id = xstrdup(_("(none)"))rstrdup((dcgettext ("rpm", "(none)", 5))); | |||
1136 | } | |||
1137 | return id; | |||
1138 | } | |||
1139 | ||||
1140 | rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx) | |||
1141 | { | |||
1142 | DIGEST_CTX ctx = rpmDigestDup(hashctx); | |||
1143 | uint8_t *hash = NULL((void*)0); | |||
1144 | size_t hashlen = 0; | |||
1145 | rpmRC res = RPMRC_FAIL; /* assume failure */ | |||
1146 | ||||
1147 | if (sig == NULL((void*)0) || ctx == NULL((void*)0)) | |||
1148 | goto exit; | |||
1149 | ||||
1150 | if (sig->hash != NULL((void*)0)) | |||
1151 | rpmDigestUpdate(ctx, sig->hash, sig->hashlen); | |||
1152 | ||||
1153 | if (sig->version == 4) { | |||
1154 | /* V4 trailer is six octets long (rfc4880) */ | |||
1155 | uint8_t trailer[6]; | |||
1156 | uint32_t nb = sig->hashlen; | |||
1157 | nb = htonl(nb)(__extension__ ({ unsigned int __v, __x = (nb); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x ) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ( "bswap %0" : "=r" (__v) : "0" (__x)); __v; })); | |||
1158 | trailer[0] = sig->version; | |||
1159 | trailer[1] = 0xff; | |||
1160 | memcpy(trailer+2, &nb, 4); | |||
1161 | rpmDigestUpdate(ctx, trailer, sizeof(trailer)); | |||
1162 | } | |||
1163 | ||||
1164 | rpmDigestFinal(ctx, (void **)&hash, &hashlen, 0); | |||
1165 | ||||
1166 | /* Compare leading 16 bits of digest for quick check. */ | |||
1167 | if (hash == NULL((void*)0) || memcmp(hash, sig->signhash16, 2) != 0) | |||
1168 | goto exit; | |||
1169 | ||||
1170 | /* | |||
1171 | * If we have a key, verify the signature for real. Otherwise we've | |||
1172 | * done all we can, return NOKEY to indicate "looks okay but dunno." | |||
1173 | */ | |||
1174 | if (key && key->alg) { | |||
1175 | pgpDigAlg sa = sig->alg; | |||
1176 | pgpDigAlg ka = key->alg; | |||
1177 | if (sa && sa->verify) { | |||
1178 | if (sa->verify(ka, sa, hash, hashlen, sig->hash_algo) == 0) { | |||
1179 | res = RPMRC_OK; | |||
1180 | } | |||
1181 | } | |||
1182 | } else { | |||
1183 | res = RPMRC_NOKEY; | |||
1184 | } | |||
1185 | ||||
1186 | exit: | |||
1187 | free(hash); | |||
1188 | return res; | |||
1189 | ||||
1190 | } | |||
1191 | ||||
1192 | rpmRC pgpVerifySig(pgpDig dig, DIGEST_CTX hashctx) | |||
1193 | { | |||
1194 | if (dig == NULL((void*)0) || hashctx == NULL((void*)0)) | |||
1195 | return RPMRC_FAIL; | |||
1196 | ||||
1197 | return pgpVerifySignature(pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY), | |||
1198 | pgpDigGetParams(dig, PGPTAG_SIGNATURE), hashctx); | |||
1199 | } | |||
1200 | ||||
1201 | static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen) | |||
1202 | { | |||
1203 | const char * enc = NULL((void*)0); | |||
1204 | const char * crcenc = NULL((void*)0); | |||
1205 | uint8_t * dec; | |||
1206 | uint8_t * crcdec; | |||
1207 | size_t declen; | |||
1208 | size_t crclen; | |||
1209 | uint32_t crcpkt, crc; | |||
1210 | const char * armortype = NULL((void*)0); | |||
1211 | char * t, * te; | |||
1212 | int pstate = 0; | |||
1213 | pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */ | |||
1214 | ||||
1215 | #define TOKEQ(_s, _tok)(rstreqn((_s), (_tok), sizeof(_tok)-1)) (rstreqn((_s), (_tok), sizeof(_tok)-1)) | |||
1216 | ||||
1217 | for (t = (char *)b; t && *t; t = te) { | |||
1218 | int rc; | |||
1219 | if ((te = strchr(t, '\n')) == NULL((void*)0)) | |||
1220 | te = t + strlen(t); | |||
1221 | else | |||
1222 | te++; | |||
1223 | ||||
1224 | switch (pstate) { | |||
1225 | case 0: | |||
1226 | armortype = NULL((void*)0); | |||
1227 | if (!TOKEQ(t, "-----BEGIN PGP ")(rstreqn((t), ("-----BEGIN PGP "), sizeof("-----BEGIN PGP ")- 1))) | |||
1228 | continue; | |||
1229 | t += sizeof("-----BEGIN PGP ")-1; | |||
1230 | ||||
1231 | rc = pgpValTok(pgpArmorTbl, t, te); | |||
1232 | if (rc < 0) { | |||
1233 | ec = PGPARMOR_ERR_UNKNOWN_ARMOR_TYPE; | |||
1234 | goto exit; | |||
1235 | } | |||
1236 | if (rc != PGPARMOR_PUBKEY) /* XXX ASCII Pubkeys only, please. */ | |||
1237 | continue; | |||
1238 | ||||
1239 | armortype = pgpValStr(pgpArmorTbl, rc); | |||
1240 | t += strlen(armortype); | |||
1241 | if (!TOKEQ(t, "-----")(rstreqn((t), ("-----"), sizeof("-----")-1))) | |||
1242 | continue; | |||
1243 | t += sizeof("-----")-1; | |||
1244 | if (*t != '\n' && *t != '\r') | |||
1245 | continue; | |||
1246 | *t = '\0'; | |||
1247 | pstate++; | |||
1248 | break; | |||
1249 | case 1: | |||
1250 | enc = NULL((void*)0); | |||
1251 | rc = pgpValTok(pgpArmorKeyTbl, t, te); | |||
1252 | if (rc >= 0) | |||
1253 | continue; | |||
1254 | if (*t != '\n' && *t != '\r') { | |||
1255 | pstate = 0; | |||
1256 | continue; | |||
1257 | } | |||
1258 | enc = te; /* Start of encoded packets */ | |||
1259 | pstate++; | |||
1260 | break; | |||
1261 | case 2: | |||
1262 | crcenc = NULL((void*)0); | |||
1263 | if (*t != '=') | |||
1264 | continue; | |||
1265 | *t++ = '\0'; /* Terminate encoded packets */ | |||
1266 | crcenc = t; /* Start of encoded crc */ | |||
1267 | pstate++; | |||
1268 | break; | |||
1269 | case 3: | |||
1270 | pstate = 0; | |||
1271 | if (!TOKEQ(t, "-----END PGP ")(rstreqn((t), ("-----END PGP "), sizeof("-----END PGP ")-1))) { | |||
1272 | ec = PGPARMOR_ERR_NO_END_PGP; | |||
1273 | goto exit; | |||
1274 | } | |||
1275 | *t = '\0'; /* Terminate encoded crc */ | |||
1276 | t += sizeof("-----END PGP ")-1; | |||
1277 | if (t >= te) continue; | |||
1278 | ||||
1279 | if (armortype == NULL((void*)0)) /* XXX can't happen */ | |||
1280 | continue; | |||
1281 | if (!rstreqn(t, armortype, strlen(armortype))) | |||
1282 | continue; | |||
1283 | ||||
1284 | t += strlen(armortype); | |||
1285 | if (t >= te) continue; | |||
1286 | ||||
1287 | if (!TOKEQ(t, "-----")(rstreqn((t), ("-----"), sizeof("-----")-1))) { | |||
1288 | ec = PGPARMOR_ERR_NO_END_PGP; | |||
1289 | goto exit; | |||
1290 | } | |||
1291 | t += (sizeof("-----")-1); | |||
1292 | if (t >= te) continue; | |||
1293 | /* XXX permitting \r here is not RFC-2440 compliant <shrug> */ | |||
1294 | if (!(*t == '\n' || *t == '\r')) continue; | |||
1295 | ||||
1296 | crcdec = NULL((void*)0); | |||
1297 | crclen = 0; | |||
1298 | if (rpmBase64Decode(crcenc, (void **)&crcdec, &crclen) != 0) { | |||
1299 | ec = PGPARMOR_ERR_CRC_DECODE; | |||
1300 | goto exit; | |||
1301 | } | |||
1302 | crcpkt = pgpGrab(crcdec, crclen); | |||
1303 | crcdec = _free(crcdec)rfree((crcdec)); | |||
1304 | dec = NULL((void*)0); | |||
1305 | declen = 0; | |||
1306 | if (rpmBase64Decode(enc, (void **)&dec, &declen) != 0) { | |||
1307 | ec = PGPARMOR_ERR_BODY_DECODE; | |||
1308 | goto exit; | |||
1309 | } | |||
1310 | crc = pgpCRC(dec, declen); | |||
1311 | if (crcpkt != crc) { | |||
1312 | ec = PGPARMOR_ERR_CRC_CHECK; | |||
1313 | goto exit; | |||
1314 | } | |||
1315 | if (pkt) *pkt = dec; | |||
1316 | if (pktlen) *pktlen = declen; | |||
1317 | ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */ | |||
1318 | goto exit; | |||
1319 | break; | |||
1320 | } | |||
1321 | } | |||
1322 | ec = PGPARMOR_NONE; | |||
1323 | ||||
1324 | exit: | |||
1325 | return ec; | |||
1326 | } | |||
1327 | ||||
1328 | pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen) | |||
1329 | { | |||
1330 | uint8_t * b = NULL((void*)0); | |||
1331 | ssize_t blen; | |||
1332 | pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */ | |||
1333 | int rc = rpmioSlurp(fn, &b, &blen); | |||
1334 | if (rc == 0 && b != NULL((void*)0) && blen > 0) { | |||
1335 | ec = decodePkts(b, pkt, pktlen); | |||
1336 | } | |||
1337 | free(b); | |||
1338 | return ec; | |||
1339 | } | |||
1340 | ||||
1341 | pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen) | |||
1342 | { | |||
1343 | pgpArmor ec = PGPARMOR_ERR_NO_BEGIN_PGP; /* XXX assume failure */ | |||
1344 | if (armor && strlen(armor) > 0) { | |||
1345 | uint8_t *b = (uint8_t*) xstrdup(armor)rstrdup((armor)); | |||
1346 | ec = decodePkts(b, pkt, pktlen); | |||
1347 | free(b); | |||
1348 | } | |||
1349 | return ec; | |||
1350 | } | |||
1351 | ||||
1352 | int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen) | |||
1353 | { | |||
1354 | const uint8_t *p = pkts; | |||
1355 | const uint8_t *pend = pkts + pktslen; | |||
1356 | struct pgpPkt pkt; | |||
1357 | ||||
1358 | while (p < pend) { | |||
| ||||
1359 | if (decodePkt(p, (pend - p), &pkt)) | |||
1360 | return -1; | |||
1361 | ||||
1362 | if (pkt.tag == PGPTAG_PUBLIC_KEY && pkts != p) { | |||
1363 | *certlen = p - pkts; | |||
1364 | return 0; | |||
1365 | } | |||
1366 | ||||
1367 | p += (pkt.body - pkt.head) + pkt.blen; | |||
1368 | } | |||
1369 | ||||
1370 | *certlen = pktslen; | |||
1371 | ||||
1372 | return 0; | |||
1373 | } | |||
1374 | ||||
1375 | char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns) | |||
1376 | { | |||
1377 | char *buf = NULL((void*)0), *val = NULL((void*)0); | |||
1378 | char *enc = rpmBase64Encode(s, ns, -1); | |||
1379 | char *crc = rpmBase64CRC(s, ns); | |||
1380 | const char *valstr = pgpValStr(pgpArmorTbl, atype); | |||
1381 | ||||
1382 | if (crc != NULL((void*)0) && enc != NULL((void*)0)) { | |||
1383 | rasprintf(&buf, "%s=%s", enc, crc); | |||
1384 | } | |||
1385 | free(crc); | |||
1386 | free(enc); | |||
1387 | ||||
1388 | rasprintf(&val, "-----BEGIN PGP %s-----\nVersion: rpm-" VERSION"4.13.90" " (NSS-3)\n\n" | |||
1389 | "%s\n-----END PGP %s-----\n", | |||
1390 | valstr, buf != NULL((void*)0) ? buf : "", valstr); | |||
1391 | ||||
1392 | free(buf); | |||
1393 | return val; | |||
1394 | } | |||
1395 |