| /* |
| * pgp-info.c |
| * Provide info about PGP data. |
| * |
| * Copyright (c) 2005 Marko Kreen |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * |
| * contrib/pgcrypto/pgp-info.c |
| */ |
| #include "postgres.h" |
| |
| #include "px.h" |
| #include "mbuf.h" |
| #include "pgp.h" |
| |
| static int |
| read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf) |
| { |
| int res; |
| PGP_PubKey *pk = NULL; |
| |
| res = _pgp_read_public_key(pkt, &pk); |
| if (res < 0) |
| goto err; |
| |
| /* skip secret key part, if it exists */ |
| res = pgp_skip_packet(pkt); |
| if (res < 0) |
| goto err; |
| |
| /* is it encryption key */ |
| switch (pk->algo) |
| { |
| case PGP_PUB_ELG_ENCRYPT: |
| case PGP_PUB_RSA_ENCRYPT: |
| case PGP_PUB_RSA_ENCRYPT_SIGN: |
| memcpy(keyid_buf, pk->key_id, 8); |
| res = 1; |
| break; |
| default: |
| res = 0; |
| } |
| |
| err: |
| pgp_key_free(pk); |
| return res; |
| } |
| |
| static int |
| read_pubenc_keyid(PullFilter *pkt, uint8 *keyid_buf) |
| { |
| uint8 ver; |
| int res; |
| |
| GETBYTE(pkt, ver); |
| if (ver != 3) |
| return -1; |
| |
| res = pullf_read_fixed(pkt, 8, keyid_buf); |
| if (res < 0) |
| return res; |
| |
| return pgp_skip_packet(pkt); |
| } |
| |
| static const char hextbl[] = "0123456789ABCDEF"; |
| |
| static int |
| print_key(uint8 *keyid, char *dst) |
| { |
| int i; |
| unsigned c; |
| |
| for (i = 0; i < 8; i++) |
| { |
| c = keyid[i]; |
| *dst++ = hextbl[(c >> 4) & 0x0F]; |
| *dst++ = hextbl[c & 0x0F]; |
| } |
| *dst = 0; |
| return 8 * 2; |
| } |
| |
| static const uint8 any_key[] = |
| {0, 0, 0, 0, 0, 0, 0, 0}; |
| |
| /* |
| * dst should have room for 17 bytes |
| */ |
| int |
| pgp_get_keyid(MBuf *pgp_data, char *dst) |
| { |
| int res; |
| PullFilter *src; |
| PullFilter *pkt = NULL; |
| int len; |
| uint8 tag; |
| int got_pub_key = 0, |
| got_symenc_key = 0, |
| got_pubenc_key = 0; |
| int got_data = 0; |
| uint8 keyid_buf[8]; |
| int got_main_key = 0; |
| |
| |
| res = pullf_create_mbuf_reader(&src, pgp_data); |
| if (res < 0) |
| return res; |
| |
| while (1) |
| { |
| res = pgp_parse_pkt_hdr(src, &tag, &len, 0); |
| if (res <= 0) |
| break; |
| res = pgp_create_pkt_reader(&pkt, src, len, res, NULL); |
| if (res < 0) |
| break; |
| |
| switch (tag) |
| { |
| case PGP_PKT_SECRET_KEY: |
| case PGP_PKT_PUBLIC_KEY: |
| /* main key is for signing, so ignore it */ |
| if (!got_main_key) |
| { |
| got_main_key = 1; |
| res = pgp_skip_packet(pkt); |
| } |
| else |
| res = PXE_PGP_MULTIPLE_KEYS; |
| break; |
| case PGP_PKT_SECRET_SUBKEY: |
| case PGP_PKT_PUBLIC_SUBKEY: |
| res = read_pubkey_keyid(pkt, keyid_buf); |
| if (res < 0) |
| break; |
| if (res > 0) |
| got_pub_key++; |
| break; |
| case PGP_PKT_PUBENCRYPTED_SESSKEY: |
| got_pubenc_key++; |
| res = read_pubenc_keyid(pkt, keyid_buf); |
| break; |
| case PGP_PKT_SYMENCRYPTED_DATA: |
| case PGP_PKT_SYMENCRYPTED_DATA_MDC: |
| /* don't skip it, just stop */ |
| got_data = 1; |
| break; |
| case PGP_PKT_SYMENCRYPTED_SESSKEY: |
| got_symenc_key++; |
| /* fallthru */ |
| case PGP_PKT_SIGNATURE: |
| case PGP_PKT_MARKER: |
| case PGP_PKT_TRUST: |
| case PGP_PKT_USER_ID: |
| case PGP_PKT_USER_ATTR: |
| case PGP_PKT_PRIV_61: |
| res = pgp_skip_packet(pkt); |
| break; |
| default: |
| res = PXE_PGP_CORRUPT_DATA; |
| } |
| |
| if (pkt) |
| pullf_free(pkt); |
| pkt = NULL; |
| |
| if (res < 0 || got_data) |
| break; |
| } |
| |
| pullf_free(src); |
| if (pkt) |
| pullf_free(pkt); |
| |
| if (res < 0) |
| return res; |
| |
| /* now check sanity */ |
| if (got_pub_key && got_pubenc_key) |
| res = PXE_PGP_CORRUPT_DATA; |
| |
| if (got_pub_key > 1) |
| res = PXE_PGP_MULTIPLE_KEYS; |
| |
| if (got_pubenc_key > 1) |
| res = PXE_PGP_MULTIPLE_KEYS; |
| |
| /* |
| * if still ok, look what we got |
| */ |
| if (res >= 0) |
| { |
| if (got_pubenc_key || got_pub_key) |
| { |
| if (memcmp(keyid_buf, any_key, 8) == 0) |
| { |
| memcpy(dst, "ANYKEY", 7); |
| res = 6; |
| } |
| else |
| res = print_key(keyid_buf, dst); |
| } |
| else if (got_symenc_key) |
| { |
| memcpy(dst, "SYMKEY", 7); |
| res = 6; |
| } |
| else |
| res = PXE_PGP_NO_USABLE_KEY; |
| } |
| |
| return res; |
| } |