1 /*
2  * px.c
3  *		Various cryptographic stuff for PostgreSQL.
4  *
5  * Copyright (c) 2001 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/px.c
30  */
31 
32 #include "postgres.h"
33 
34 #include "px.h"
35 
36 struct error_desc
37 {
38 	int			err;
39 	const char *desc;
40 };
41 
42 static const struct error_desc px_err_list[] = {
43 	{PXE_OK, "Everything ok"},
44 	{PXE_ERR_GENERIC, "Some PX error (not specified)"},
45 	{PXE_NO_HASH, "No such hash algorithm"},
46 	{PXE_NO_CIPHER, "No such cipher algorithm"},
47 	{PXE_NOTBLOCKSIZE, "Data not a multiple of block size"},
48 	{PXE_BAD_OPTION, "Unknown option"},
49 	{PXE_BAD_FORMAT, "Badly formatted type"},
50 	{PXE_KEY_TOO_BIG, "Key was too big"},
51 	{PXE_CIPHER_INIT, "Cipher cannot be initialized ?"},
52 	{PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
53 	{PXE_DEV_READ_ERROR, "Error reading from random device"},
54 	{PXE_BUG, "pgcrypto bug"},
55 	{PXE_ARGUMENT_ERROR, "Illegal argument to function"},
56 	{PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
57 	{PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
58 	{PXE_MCRYPT_INTERNAL, "mcrypt internal error"},
59 	{PXE_NO_RANDOM, "No strong random source"},
60 	{PXE_DECRYPT_FAILED, "Decryption failed"},
61 	{PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"},
62 	{PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"},
63 	{PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"},
64 	{PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"},
65 	{PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"},
66 	{PXE_PGP_COMPRESSION_ERROR, "Compression error"},
67 	{PXE_PGP_NOT_TEXT, "Not text data"},
68 	{PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"},
69 	{PXE_PGP_MATH_FAILED, "Math operation failed"},
70 	{PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"},
71 	{PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"},
72 	{PXE_PGP_WRONG_KEY, "Wrong key"},
73 	{PXE_PGP_MULTIPLE_KEYS,
74 	"Several keys given - pgcrypto does not handle keyring"},
75 	{PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"},
76 	{PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"},
77 	{PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"},
78 	{PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"},
79 	{PXE_PGP_NO_USABLE_KEY, "No encryption key found"},
80 	{PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"},
81 	{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
82 	{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
83 	{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
84 
85 	{0, NULL},
86 };
87 
88 /*
89  * Call ereport(ERROR, ...), with an error code and message corresponding to
90  * the PXE_* error code given as argument.
91  *
92  * This is similar to px_strerror(err), but for some errors, we fill in the
93  * error code and detail fields more appropriately.
94  */
95 void
px_THROW_ERROR(int err)96 px_THROW_ERROR(int err)
97 {
98 	if (err == PXE_NO_RANDOM)
99 	{
100 #ifdef HAVE_STRONG_RANDOM
101 		ereport(ERROR,
102 				(errcode(ERRCODE_INTERNAL_ERROR),
103 				 errmsg("could not generate a random number")));
104 #else
105 		ereport(ERROR,
106 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
107 				 errmsg("generating random data is not supported by this build"),
108 				 errdetail("This functionality requires a source of strong random numbers"),
109 				 errhint("You need to rebuild PostgreSQL using --enable-strong-random")));
110 #endif
111 	}
112 	else
113 	{
114 		/* For other errors, use the message from the above list. */
115 		ereport(ERROR,
116 				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
117 				 errmsg("%s", px_strerror(err))));
118 	}
119 }
120 
121 const char *
px_strerror(int err)122 px_strerror(int err)
123 {
124 	const struct error_desc *e;
125 
126 	for (e = px_err_list; e->desc; e++)
127 		if (e->err == err)
128 			return e->desc;
129 	return "Bad error code";
130 }
131 
132 /* memset that must not be optimized away */
133 void
px_memset(void * ptr,int c,size_t len)134 px_memset(void *ptr, int c, size_t len)
135 {
136 	memset(ptr, c, len);
137 }
138 
139 const char *
px_resolve_alias(const PX_Alias * list,const char * name)140 px_resolve_alias(const PX_Alias *list, const char *name)
141 {
142 	while (list->name)
143 	{
144 		if (pg_strcasecmp(list->alias, name) == 0)
145 			return list->name;
146 		list++;
147 	}
148 	return name;
149 }
150 
151 static void (*debug_handler) (const char *) = NULL;
152 
153 void
px_set_debug_handler(void (* handler)(const char *))154 px_set_debug_handler(void (*handler) (const char *))
155 {
156 	debug_handler = handler;
157 }
158 
159 void
px_debug(const char * fmt,...)160 px_debug(const char *fmt,...)
161 {
162 	va_list		ap;
163 
164 	va_start(ap, fmt);
165 	if (debug_handler)
166 	{
167 		char		buf[512];
168 
169 		vsnprintf(buf, sizeof(buf), fmt, ap);
170 		debug_handler(buf);
171 	}
172 	va_end(ap);
173 }
174 
175 /*
176  * combo - cipher + padding (+ checksum)
177  */
178 
179 static unsigned
combo_encrypt_len(PX_Combo * cx,unsigned dlen)180 combo_encrypt_len(PX_Combo *cx, unsigned dlen)
181 {
182 	return dlen + 512;
183 }
184 
185 static unsigned
combo_decrypt_len(PX_Combo * cx,unsigned dlen)186 combo_decrypt_len(PX_Combo *cx, unsigned dlen)
187 {
188 	return dlen;
189 }
190 
191 static int
combo_init(PX_Combo * cx,const uint8 * key,unsigned klen,const uint8 * iv,unsigned ivlen)192 combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
193 		   const uint8 *iv, unsigned ivlen)
194 {
195 	int			err;
196 	unsigned	ks,
197 				ivs;
198 	PX_Cipher  *c = cx->cipher;
199 	uint8	   *ivbuf = NULL;
200 	uint8	   *keybuf;
201 
202 	ks = px_cipher_key_size(c);
203 
204 	ivs = px_cipher_iv_size(c);
205 	if (ivs > 0)
206 	{
207 		ivbuf = px_alloc(ivs);
208 		memset(ivbuf, 0, ivs);
209 		if (ivlen > ivs)
210 			memcpy(ivbuf, iv, ivs);
211 		else
212 			memcpy(ivbuf, iv, ivlen);
213 	}
214 
215 	if (klen > ks)
216 		klen = ks;
217 	keybuf = px_alloc(ks);
218 	memset(keybuf, 0, ks);
219 	memcpy(keybuf, key, klen);
220 
221 	err = px_cipher_init(c, keybuf, klen, ivbuf);
222 
223 	if (ivbuf)
224 		px_free(ivbuf);
225 	px_free(keybuf);
226 
227 	return err;
228 }
229 
230 static int
combo_encrypt(PX_Combo * cx,const uint8 * data,unsigned dlen,uint8 * res,unsigned * rlen)231 combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
232 			  uint8 *res, unsigned *rlen)
233 {
234 	int			err = 0;
235 	uint8	   *bbuf;
236 	unsigned	bs,
237 				bpos,
238 				i,
239 				pad;
240 
241 	PX_Cipher  *c = cx->cipher;
242 
243 	bbuf = NULL;
244 	bs = px_cipher_block_size(c);
245 
246 	/* encrypt */
247 	if (bs > 1)
248 	{
249 		bbuf = px_alloc(bs * 4);
250 		bpos = dlen % bs;
251 		*rlen = dlen - bpos;
252 		memcpy(bbuf, data + *rlen, bpos);
253 
254 		/* encrypt full-block data */
255 		if (*rlen)
256 		{
257 			err = px_cipher_encrypt(c, data, *rlen, res);
258 			if (err)
259 				goto out;
260 		}
261 
262 		/* bbuf has now bpos bytes of stuff */
263 		if (cx->padding)
264 		{
265 			pad = bs - (bpos % bs);
266 			for (i = 0; i < pad; i++)
267 				bbuf[bpos++] = pad;
268 		}
269 		else if (bpos % bs)
270 		{
271 			/* ERROR? */
272 			pad = bs - (bpos % bs);
273 			for (i = 0; i < pad; i++)
274 				bbuf[bpos++] = 0;
275 		}
276 
277 		/* encrypt the rest - pad */
278 		if (bpos)
279 		{
280 			err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen);
281 			*rlen += bpos;
282 		}
283 	}
284 	else
285 	{
286 		/* stream cipher/mode - no pad needed */
287 		err = px_cipher_encrypt(c, data, dlen, res);
288 		if (err)
289 			goto out;
290 		*rlen = dlen;
291 	}
292 out:
293 	if (bbuf)
294 		px_free(bbuf);
295 
296 	return err;
297 }
298 
299 static int
combo_decrypt(PX_Combo * cx,const uint8 * data,unsigned dlen,uint8 * res,unsigned * rlen)300 combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
301 			  uint8 *res, unsigned *rlen)
302 {
303 	int			err = 0;
304 	unsigned	bs,
305 				i,
306 				pad;
307 	unsigned	pad_ok;
308 
309 	PX_Cipher  *c = cx->cipher;
310 
311 	/* decide whether zero-length input is allowed */
312 	if (dlen == 0)
313 	{
314 		/* with padding, empty ciphertext is not allowed */
315 		if (cx->padding)
316 			return PXE_DECRYPT_FAILED;
317 
318 		/* without padding, report empty result */
319 		*rlen = 0;
320 		return 0;
321 	}
322 
323 	bs = px_cipher_block_size(c);
324 	if (bs > 1 && (dlen % bs) != 0)
325 		goto block_error;
326 
327 	/* decrypt */
328 	*rlen = dlen;
329 	err = px_cipher_decrypt(c, data, dlen, res);
330 	if (err)
331 		return err;
332 
333 	/* unpad */
334 	if (bs > 1 && cx->padding)
335 	{
336 		pad = res[*rlen - 1];
337 		pad_ok = 0;
338 		if (pad > 0 && pad <= bs && pad <= *rlen)
339 		{
340 			pad_ok = 1;
341 			for (i = *rlen - pad; i < *rlen; i++)
342 				if (res[i] != pad)
343 				{
344 					pad_ok = 0;
345 					break;
346 				}
347 		}
348 
349 		if (pad_ok)
350 			*rlen -= pad;
351 	}
352 
353 	return 0;
354 
355 block_error:
356 	return PXE_NOTBLOCKSIZE;
357 }
358 
359 static void
combo_free(PX_Combo * cx)360 combo_free(PX_Combo *cx)
361 {
362 	if (cx->cipher)
363 		px_cipher_free(cx->cipher);
364 	px_memset(cx, 0, sizeof(*cx));
365 	px_free(cx);
366 }
367 
368 /* PARSER */
369 
370 static int
parse_cipher_name(char * full,char ** cipher,char ** pad)371 parse_cipher_name(char *full, char **cipher, char **pad)
372 {
373 	char	   *p,
374 			   *p2,
375 			   *q;
376 
377 	*cipher = full;
378 	*pad = NULL;
379 
380 	p = strchr(full, '/');
381 	if (p != NULL)
382 		*p++ = 0;
383 	while (p != NULL)
384 	{
385 		if ((q = strchr(p, '/')) != NULL)
386 			*q++ = 0;
387 
388 		if (!*p)
389 		{
390 			p = q;
391 			continue;
392 		}
393 		p2 = strchr(p, ':');
394 		if (p2 != NULL)
395 		{
396 			*p2++ = 0;
397 			if (strcmp(p, "pad") == 0)
398 				*pad = p2;
399 			else
400 				return PXE_BAD_OPTION;
401 		}
402 		else
403 			return PXE_BAD_FORMAT;
404 
405 		p = q;
406 	}
407 	return 0;
408 }
409 
410 /* provider */
411 
412 int
px_find_combo(const char * name,PX_Combo ** res)413 px_find_combo(const char *name, PX_Combo **res)
414 {
415 	int			err;
416 	char	   *buf,
417 			   *s_cipher,
418 			   *s_pad;
419 
420 	PX_Combo   *cx;
421 
422 	cx = px_alloc(sizeof(*cx));
423 	memset(cx, 0, sizeof(*cx));
424 
425 	buf = px_alloc(strlen(name) + 1);
426 	strcpy(buf, name);
427 
428 	err = parse_cipher_name(buf, &s_cipher, &s_pad);
429 	if (err)
430 	{
431 		px_free(buf);
432 		px_free(cx);
433 		return err;
434 	}
435 
436 	err = px_find_cipher(s_cipher, &cx->cipher);
437 	if (err)
438 		goto err1;
439 
440 	if (s_pad != NULL)
441 	{
442 		if (strcmp(s_pad, "pkcs") == 0)
443 			cx->padding = 1;
444 		else if (strcmp(s_pad, "none") == 0)
445 			cx->padding = 0;
446 		else
447 			goto err1;
448 	}
449 	else
450 		cx->padding = 1;
451 
452 	cx->init = combo_init;
453 	cx->encrypt = combo_encrypt;
454 	cx->decrypt = combo_decrypt;
455 	cx->encrypt_len = combo_encrypt_len;
456 	cx->decrypt_len = combo_decrypt_len;
457 	cx->free = combo_free;
458 
459 	px_free(buf);
460 
461 	*res = cx;
462 
463 	return 0;
464 
465 err1:
466 	if (cx->cipher)
467 		px_cipher_free(cx->cipher);
468 	px_free(cx);
469 	px_free(buf);
470 	return PXE_NO_CIPHER;
471 }
472