| 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 |