1 /*
2  * pgp-info.c
3  *	  Provide info about PGP data.
4  *
5  * Copyright (c) 2005 Marko Kreen
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *	  notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *	  notice, this list of conditions and the following disclaimer in the
15  *	  documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * contrib/pgcrypto/pgp-info.c
30  */
31 #include "postgres.h"
32 
33 #include "px.h"
34 #include "mbuf.h"
35 #include "pgp.h"
36 
37 static int
read_pubkey_keyid(PullFilter * pkt,uint8 * keyid_buf)38 read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
39 {
40 	int			res;
41 	PGP_PubKey *pk = NULL;
42 
43 	res = _pgp_read_public_key(pkt, &pk);
44 	if (res < 0)
45 		goto err;
46 
47 	/* skip secret key part, if it exists */
48 	res = pgp_skip_packet(pkt);
49 	if (res < 0)
50 		goto err;
51 
52 	/* is it encryption key */
53 	switch (pk->algo)
54 	{
55 		case PGP_PUB_ELG_ENCRYPT:
56 		case PGP_PUB_RSA_ENCRYPT:
57 		case PGP_PUB_RSA_ENCRYPT_SIGN:
58 			memcpy(keyid_buf, pk->key_id, 8);
59 			res = 1;
60 			break;
61 		default:
62 			res = 0;
63 	}
64 
65 err:
66 	pgp_key_free(pk);
67 	return res;
68 }
69 
70 static int
read_pubenc_keyid(PullFilter * pkt,uint8 * keyid_buf)71 read_pubenc_keyid(PullFilter *pkt, uint8 *keyid_buf)
72 {
73 	uint8		ver;
74 	int			res;
75 
76 	GETBYTE(pkt, ver);
77 	if (ver != 3)
78 		return -1;
79 
80 	res = pullf_read_fixed(pkt, 8, keyid_buf);
81 	if (res < 0)
82 		return res;
83 
84 	return pgp_skip_packet(pkt);
85 }
86 
87 static const char hextbl[] = "0123456789ABCDEF";
88 
89 static int
print_key(uint8 * keyid,char * dst)90 print_key(uint8 *keyid, char *dst)
91 {
92 	int			i;
93 	unsigned	c;
94 
95 	for (i = 0; i < 8; i++)
96 	{
97 		c = keyid[i];
98 		*dst++ = hextbl[(c >> 4) & 0x0F];
99 		*dst++ = hextbl[c & 0x0F];
100 	}
101 	*dst = 0;
102 	return 8 * 2;
103 }
104 
105 static const uint8 any_key[] =
106 {0, 0, 0, 0, 0, 0, 0, 0};
107 
108 /*
109  * dst should have room for 17 bytes
110  */
111 int
pgp_get_keyid(MBuf * pgp_data,char * dst)112 pgp_get_keyid(MBuf *pgp_data, char *dst)
113 {
114 	int			res;
115 	PullFilter *src;
116 	PullFilter *pkt = NULL;
117 	int			len;
118 	uint8		tag;
119 	int			got_pub_key = 0,
120 				got_symenc_key = 0,
121 				got_pubenc_key = 0;
122 	int			got_data = 0;
123 	uint8		keyid_buf[8];
124 	int			got_main_key = 0;
125 
126 
127 	res = pullf_create_mbuf_reader(&src, pgp_data);
128 	if (res < 0)
129 		return res;
130 
131 	while (1)
132 	{
133 		res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
134 		if (res <= 0)
135 			break;
136 		res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
137 		if (res < 0)
138 			break;
139 
140 		switch (tag)
141 		{
142 			case PGP_PKT_SECRET_KEY:
143 			case PGP_PKT_PUBLIC_KEY:
144 				/* main key is for signing, so ignore it */
145 				if (!got_main_key)
146 				{
147 					got_main_key = 1;
148 					res = pgp_skip_packet(pkt);
149 				}
150 				else
151 					res = PXE_PGP_MULTIPLE_KEYS;
152 				break;
153 			case PGP_PKT_SECRET_SUBKEY:
154 			case PGP_PKT_PUBLIC_SUBKEY:
155 				res = read_pubkey_keyid(pkt, keyid_buf);
156 				if (res < 0)
157 					break;
158 				if (res > 0)
159 					got_pub_key++;
160 				break;
161 			case PGP_PKT_PUBENCRYPTED_SESSKEY:
162 				got_pubenc_key++;
163 				res = read_pubenc_keyid(pkt, keyid_buf);
164 				break;
165 			case PGP_PKT_SYMENCRYPTED_DATA:
166 			case PGP_PKT_SYMENCRYPTED_DATA_MDC:
167 				/* don't skip it, just stop */
168 				got_data = 1;
169 				break;
170 			case PGP_PKT_SYMENCRYPTED_SESSKEY:
171 				got_symenc_key++;
172 				/* fallthru */
173 			case PGP_PKT_SIGNATURE:
174 			case PGP_PKT_MARKER:
175 			case PGP_PKT_TRUST:
176 			case PGP_PKT_USER_ID:
177 			case PGP_PKT_USER_ATTR:
178 			case PGP_PKT_PRIV_61:
179 				res = pgp_skip_packet(pkt);
180 				break;
181 			default:
182 				res = PXE_PGP_CORRUPT_DATA;
183 		}
184 
185 		if (pkt)
186 			pullf_free(pkt);
187 		pkt = NULL;
188 
189 		if (res < 0 || got_data)
190 			break;
191 	}
192 
193 	pullf_free(src);
194 	if (pkt)
195 		pullf_free(pkt);
196 
197 	if (res < 0)
198 		return res;
199 
200 	/* now check sanity */
201 	if (got_pub_key && got_pubenc_key)
202 		res = PXE_PGP_CORRUPT_DATA;
203 
204 	if (got_pub_key > 1)
205 		res = PXE_PGP_MULTIPLE_KEYS;
206 
207 	if (got_pubenc_key > 1)
208 		res = PXE_PGP_MULTIPLE_KEYS;
209 
210 	/*
211 	 * if still ok, look what we got
212 	 */
213 	if (res >= 0)
214 	{
215 		if (got_pubenc_key || got_pub_key)
216 		{
217 			if (memcmp(keyid_buf, any_key, 8) == 0)
218 			{
219 				memcpy(dst, "ANYKEY", 7);
220 				res = 6;
221 			}
222 			else
223 				res = print_key(keyid_buf, dst);
224 		}
225 		else if (got_symenc_key)
226 		{
227 			memcpy(dst, "SYMKEY", 7);
228 			res = 6;
229 		}
230 		else
231 			res = PXE_PGP_NO_USABLE_KEY;
232 	}
233 
234 	return res;
235 }
236