Branch data Line data Source code
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_NO_HASH, "No such hash algorithm"},
45 : : {PXE_NO_CIPHER, "No such cipher algorithm"},
46 : : {PXE_BAD_OPTION, "Unknown option"},
47 : : {PXE_BAD_FORMAT, "Badly formatted type"},
48 : : {PXE_KEY_TOO_BIG, "Key was too big"},
49 : : {PXE_CIPHER_INIT, "Cipher cannot be initialized"},
50 : : {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
51 : : {PXE_BUG, "pgcrypto bug"},
52 : : {PXE_ARGUMENT_ERROR, "Illegal argument to function"},
53 : : {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
54 : : {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
55 : : {PXE_NO_RANDOM, "Failed to generate strong random bits"},
56 : : {PXE_DECRYPT_FAILED, "Decryption failed"},
57 : : {PXE_ENCRYPT_FAILED, "Encryption failed"},
58 : : {PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"},
59 : : {PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"},
60 : : {PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"},
61 : : {PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"},
62 : : {PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"},
63 : : {PXE_PGP_COMPRESSION_ERROR, "Compression error"},
64 : : {PXE_PGP_NOT_TEXT, "Not text data"},
65 : : {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"},
66 : : {PXE_PGP_MATH_FAILED, "Math operation failed"},
67 : : {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"},
68 : : {PXE_PGP_KEY_TOO_BIG, "Session key too big"},
69 : : {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"},
70 : : {PXE_PGP_WRONG_KEY, "Wrong key"},
71 : : {PXE_PGP_MULTIPLE_KEYS,
72 : : "Several keys given - pgcrypto does not handle keyring"},
73 : : {PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"},
74 : : {PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"},
75 : : {PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"},
76 : : {PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"},
77 : : {PXE_PGP_NO_USABLE_KEY, "No encryption key found"},
78 : : {PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"},
79 : : {PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
80 : : {PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
81 : : {PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
82 : :
83 : : {0, NULL},
84 : : };
85 : :
86 : : /*
87 : : * Call ereport(ERROR, ...), with an error code and message corresponding to
88 : : * the PXE_* error code given as argument.
89 : : *
90 : : * This is similar to px_strerror(err), but for some errors, we fill in the
91 : : * error code and detail fields more appropriately.
92 : : */
93 : : void
94 : 21 : px_THROW_ERROR(int err)
95 : : {
96 [ - + ]: 21 : if (err == PXE_NO_RANDOM)
97 : : {
98 [ # # ]: 0 : ereport(ERROR,
99 : : (errcode(ERRCODE_INTERNAL_ERROR),
100 : : errmsg("could not generate a random number")));
101 : : }
102 : : else
103 : : {
104 : : /* For other errors, use the message from the above list. */
105 [ + - ]: 21 : ereport(ERROR,
106 : : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
107 : : errmsg("%s", px_strerror(err))));
108 : : }
109 : : }
110 : :
111 : : const char *
112 : 76 : px_strerror(int err)
113 : : {
114 : : const struct error_desc *e;
115 : :
116 [ + - ]: 899 : for (e = px_err_list; e->desc; e++)
117 [ + + ]: 899 : if (e->err == err)
118 : 76 : return e->desc;
119 : 0 : return "Bad error code";
120 : : }
121 : :
122 : : const char *
123 : 211 : px_resolve_alias(const PX_Alias *list, const char *name)
124 : : {
125 [ + + ]: 2981 : while (list->name)
126 : : {
127 [ + + ]: 2816 : if (pg_strcasecmp(list->alias, name) == 0)
128 : 46 : return list->name;
129 : 2770 : list++;
130 : : }
131 : 165 : return name;
132 : : }
133 : :
134 : : static void (*debug_handler) (const char *) = NULL;
135 : :
136 : : void
137 : 117 : px_set_debug_handler(void (*handler) (const char *))
138 : : {
139 : 117 : debug_handler = handler;
140 : 117 : }
141 : :
142 : : void
143 : 17 : px_debug(const char *fmt, ...)
144 : : {
145 : : va_list ap;
146 : :
147 : 17 : va_start(ap, fmt);
148 [ + + ]: 17 : if (debug_handler)
149 : : {
150 : : char buf[512];
151 : :
152 : 8 : vsnprintf(buf, sizeof(buf), fmt, ap);
153 : 8 : debug_handler(buf);
154 : : }
155 : 17 : va_end(ap);
156 : 17 : }
157 : :
158 : : /*
159 : : * combo - cipher + padding (+ checksum)
160 : : */
161 : :
162 : : static unsigned
163 : 72 : combo_encrypt_len(PX_Combo *cx, unsigned dlen)
164 : : {
165 : 72 : return dlen + 512;
166 : : }
167 : :
168 : : static unsigned
169 : 16 : combo_decrypt_len(PX_Combo *cx, unsigned dlen)
170 : : {
171 : 16 : return dlen;
172 : : }
173 : :
174 : : static int
175 : 88 : combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
176 : : const uint8 *iv, unsigned ivlen)
177 : : {
178 : : int err;
179 : : unsigned ks,
180 : : ivs;
181 : 88 : PX_Cipher *c = cx->cipher;
182 : 88 : uint8 *ivbuf = NULL;
183 : : uint8 *keybuf;
184 : :
185 : 88 : ks = px_cipher_key_size(c);
186 : :
187 : 88 : ivs = px_cipher_iv_size(c);
188 [ + - ]: 88 : if (ivs > 0)
189 : : {
190 : 88 : ivbuf = palloc0(ivs);
191 [ - + ]: 88 : if (ivlen > ivs)
192 : 0 : memcpy(ivbuf, iv, ivs);
193 [ + + ]: 88 : else if (ivlen > 0)
194 : 14 : memcpy(ivbuf, iv, ivlen);
195 : : }
196 : :
197 [ - + ]: 88 : if (klen > ks)
198 : 0 : klen = ks;
199 : 88 : keybuf = palloc0(ks);
200 : 88 : memcpy(keybuf, key, klen);
201 : :
202 : 88 : err = px_cipher_init(c, keybuf, klen, ivbuf);
203 : :
204 [ + - ]: 88 : if (ivbuf)
205 : 88 : pfree(ivbuf);
206 : 88 : pfree(keybuf);
207 : :
208 : 88 : return err;
209 : : }
210 : :
211 : : static int
212 : 68 : combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
213 : : uint8 *res, unsigned *rlen)
214 : : {
215 : 68 : return px_cipher_encrypt(cx->cipher, cx->padding, data, dlen, res, rlen);
216 : : }
217 : :
218 : : static int
219 : 16 : combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
220 : : uint8 *res, unsigned *rlen)
221 : : {
222 : 16 : return px_cipher_decrypt(cx->cipher, cx->padding, data, dlen, res, rlen);
223 : : }
224 : :
225 : : static void
226 : 88 : combo_free(PX_Combo *cx)
227 : : {
228 [ + - ]: 88 : if (cx->cipher)
229 : 88 : px_cipher_free(cx->cipher);
230 : 88 : explicit_bzero(cx, sizeof(*cx));
231 : 88 : pfree(cx);
232 : 88 : }
233 : :
234 : : /* PARSER */
235 : :
236 : : static int
237 : 89 : parse_cipher_name(char *full, char **cipher, char **pad)
238 : : {
239 : : char *p,
240 : : *p2,
241 : : *q;
242 : :
243 : 89 : *cipher = full;
244 : 89 : *pad = NULL;
245 : :
246 : 89 : p = strchr(full, '/');
247 [ + + ]: 89 : if (p != NULL)
248 : 21 : *p++ = 0;
249 [ + + ]: 110 : while (p != NULL)
250 : : {
251 [ - + ]: 21 : if ((q = strchr(p, '/')) != NULL)
252 : 0 : *q++ = 0;
253 : :
254 [ - + ]: 21 : if (!*p)
255 : : {
256 : 0 : p = q;
257 : 0 : continue;
258 : : }
259 : 21 : p2 = strchr(p, ':');
260 [ + - ]: 21 : if (p2 != NULL)
261 : : {
262 : 21 : *p2++ = 0;
263 [ + - ]: 21 : if (strcmp(p, "pad") == 0)
264 : 21 : *pad = p2;
265 : : else
266 : 0 : return PXE_BAD_OPTION;
267 : : }
268 : : else
269 : 0 : return PXE_BAD_FORMAT;
270 : :
271 : 21 : p = q;
272 : : }
273 : 89 : return 0;
274 : : }
275 : :
276 : : /* provider */
277 : :
278 : : int
279 : 89 : px_find_combo(const char *name, PX_Combo **res)
280 : : {
281 : : int err;
282 : : char *buf,
283 : : *s_cipher,
284 : : *s_pad;
285 : :
286 : : PX_Combo *cx;
287 : :
288 : 89 : cx = palloc0_object(PX_Combo);
289 : 89 : buf = pstrdup(name);
290 : :
291 : 89 : err = parse_cipher_name(buf, &s_cipher, &s_pad);
292 [ - + ]: 89 : if (err)
293 : : {
294 : 0 : pfree(buf);
295 : 0 : pfree(cx);
296 : 0 : return err;
297 : : }
298 : :
299 : 89 : err = px_find_cipher(s_cipher, &cx->cipher);
300 [ + + ]: 89 : if (err)
301 : 1 : goto err1;
302 : :
303 [ + + ]: 88 : if (s_pad != NULL)
304 : : {
305 [ - + ]: 21 : if (strcmp(s_pad, "pkcs") == 0)
306 : 0 : cx->padding = 1;
307 [ + - ]: 21 : else if (strcmp(s_pad, "none") == 0)
308 : 21 : cx->padding = 0;
309 : : else
310 : 0 : goto err1;
311 : : }
312 : : else
313 : 67 : cx->padding = 1;
314 : :
315 : 88 : cx->init = combo_init;
316 : 88 : cx->encrypt = combo_encrypt;
317 : 88 : cx->decrypt = combo_decrypt;
318 : 88 : cx->encrypt_len = combo_encrypt_len;
319 : 88 : cx->decrypt_len = combo_decrypt_len;
320 : 88 : cx->free = combo_free;
321 : :
322 : 88 : pfree(buf);
323 : :
324 : 88 : *res = cx;
325 : :
326 : 88 : return 0;
327 : :
328 : 1 : err1:
329 [ - + ]: 1 : if (cx->cipher)
330 : 0 : px_cipher_free(cx->cipher);
331 : 1 : pfree(cx);
332 : 1 : pfree(buf);
333 : 1 : return PXE_NO_CIPHER;
334 : : }
|