Line data Source code
1 : /*
2 : * pgcrypto.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/pgcrypto.c
30 : */
31 :
32 : #include "postgres.h"
33 :
34 : #include <ctype.h>
35 :
36 : #include "parser/scansup.h"
37 : #include "pgcrypto.h"
38 : #include "px-crypt.h"
39 : #include "px.h"
40 : #include "utils/builtins.h"
41 : #include "utils/guc.h"
42 : #include "varatt.h"
43 :
44 46 : PG_MODULE_MAGIC;
45 :
46 : /* private stuff */
47 :
48 : static const struct config_enum_entry builtin_crypto_options[] = {
49 : {"on", BC_ON, false},
50 : {"off", BC_OFF, false},
51 : {"fips", BC_FIPS, false},
52 : {NULL, 0, false}
53 : };
54 :
55 : typedef int (*PFN) (const char *name, void **res);
56 : static void *find_provider(text *name, PFN provider_lookup, const char *desc,
57 : int silent);
58 :
59 : int builtin_crypto_enabled = BC_ON;
60 :
61 : /*
62 : * Entrypoint of this module.
63 : */
64 : void
65 46 : _PG_init(void)
66 : {
67 46 : DefineCustomEnumVariable("pgcrypto.builtin_crypto_enabled",
68 : "Sets if builtin crypto functions are enabled.",
69 : "\"on\" enables builtin crypto, \"off\" unconditionally disables and \"fips\" "
70 : "will disable builtin crypto if OpenSSL is in FIPS mode",
71 : &builtin_crypto_enabled,
72 : BC_ON,
73 : builtin_crypto_options,
74 : PGC_SUSET,
75 : 0,
76 : NULL,
77 : NULL,
78 : NULL);
79 46 : MarkGUCPrefixReserved("pgcrypto");
80 46 : }
81 :
82 : /* SQL function: hash(bytea, text) returns bytea */
83 16 : PG_FUNCTION_INFO_V1(pg_digest);
84 :
85 : Datum
86 88 : pg_digest(PG_FUNCTION_ARGS)
87 : {
88 : bytea *arg;
89 : text *name;
90 : unsigned len,
91 : hlen;
92 : PX_MD *md;
93 : bytea *res;
94 :
95 88 : name = PG_GETARG_TEXT_PP(1);
96 :
97 : /* will give error if fails */
98 88 : md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
99 :
100 86 : hlen = px_md_result_size(md);
101 :
102 86 : res = (text *) palloc(hlen + VARHDRSZ);
103 86 : SET_VARSIZE(res, hlen + VARHDRSZ);
104 :
105 86 : arg = PG_GETARG_BYTEA_PP(0);
106 86 : len = VARSIZE_ANY_EXHDR(arg);
107 :
108 86 : px_md_update(md, (uint8 *) VARDATA_ANY(arg), len);
109 86 : px_md_finish(md, (uint8 *) VARDATA(res));
110 86 : px_md_free(md);
111 :
112 86 : PG_FREE_IF_COPY(arg, 0);
113 86 : PG_FREE_IF_COPY(name, 1);
114 :
115 86 : PG_RETURN_BYTEA_P(res);
116 : }
117 :
118 : /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
119 14 : PG_FUNCTION_INFO_V1(pg_hmac);
120 :
121 : Datum
122 30 : pg_hmac(PG_FUNCTION_ARGS)
123 : {
124 : bytea *arg;
125 : bytea *key;
126 : text *name;
127 : unsigned len,
128 : hlen,
129 : klen;
130 : PX_HMAC *h;
131 : bytea *res;
132 :
133 30 : name = PG_GETARG_TEXT_PP(2);
134 :
135 : /* will give error if fails */
136 30 : h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
137 :
138 28 : hlen = px_hmac_result_size(h);
139 :
140 28 : res = (text *) palloc(hlen + VARHDRSZ);
141 28 : SET_VARSIZE(res, hlen + VARHDRSZ);
142 :
143 28 : arg = PG_GETARG_BYTEA_PP(0);
144 28 : key = PG_GETARG_BYTEA_PP(1);
145 28 : len = VARSIZE_ANY_EXHDR(arg);
146 28 : klen = VARSIZE_ANY_EXHDR(key);
147 :
148 28 : px_hmac_init(h, (uint8 *) VARDATA_ANY(key), klen);
149 28 : px_hmac_update(h, (uint8 *) VARDATA_ANY(arg), len);
150 28 : px_hmac_finish(h, (uint8 *) VARDATA(res));
151 28 : px_hmac_free(h);
152 :
153 28 : PG_FREE_IF_COPY(arg, 0);
154 28 : PG_FREE_IF_COPY(key, 1);
155 28 : PG_FREE_IF_COPY(name, 2);
156 :
157 28 : PG_RETURN_BYTEA_P(res);
158 : }
159 :
160 :
161 : /* SQL function: pg_gen_salt(text) returns text */
162 8 : PG_FUNCTION_INFO_V1(pg_gen_salt);
163 :
164 : Datum
165 8 : pg_gen_salt(PG_FUNCTION_ARGS)
166 : {
167 8 : text *arg0 = PG_GETARG_TEXT_PP(0);
168 : int len;
169 : char buf[PX_MAX_SALT_LEN + 1];
170 :
171 8 : text_to_cstring_buffer(arg0, buf, sizeof(buf));
172 8 : len = px_gen_salt(buf, buf, 0);
173 6 : if (len < 0)
174 2 : ereport(ERROR,
175 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
176 : errmsg("gen_salt: %s", px_strerror(len))));
177 :
178 4 : PG_FREE_IF_COPY(arg0, 0);
179 :
180 4 : PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
181 : }
182 :
183 : /* SQL function: pg_gen_salt(text, int4) returns text */
184 6 : PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
185 :
186 : Datum
187 4 : pg_gen_salt_rounds(PG_FUNCTION_ARGS)
188 : {
189 4 : text *arg0 = PG_GETARG_TEXT_PP(0);
190 4 : int rounds = PG_GETARG_INT32(1);
191 : int len;
192 : char buf[PX_MAX_SALT_LEN + 1];
193 :
194 4 : text_to_cstring_buffer(arg0, buf, sizeof(buf));
195 4 : len = px_gen_salt(buf, buf, rounds);
196 4 : if (len < 0)
197 0 : ereport(ERROR,
198 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
199 : errmsg("gen_salt: %s", px_strerror(len))));
200 :
201 4 : PG_FREE_IF_COPY(arg0, 0);
202 :
203 4 : PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
204 : }
205 :
206 : /* SQL function: pg_crypt(psw:text, salt:text) returns text */
207 10 : PG_FUNCTION_INFO_V1(pg_crypt);
208 :
209 : Datum
210 52 : pg_crypt(PG_FUNCTION_ARGS)
211 : {
212 52 : text *arg0 = PG_GETARG_TEXT_PP(0);
213 52 : text *arg1 = PG_GETARG_TEXT_PP(1);
214 : char *buf0,
215 : *buf1,
216 : *cres,
217 : *resbuf;
218 : text *res;
219 :
220 52 : buf0 = text_to_cstring(arg0);
221 52 : buf1 = text_to_cstring(arg1);
222 :
223 52 : resbuf = palloc0(PX_MAX_CRYPT);
224 :
225 52 : cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
226 :
227 40 : pfree(buf0);
228 40 : pfree(buf1);
229 :
230 40 : if (cres == NULL)
231 4 : ereport(ERROR,
232 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
233 : errmsg("crypt(3) returned NULL")));
234 :
235 36 : res = cstring_to_text(cres);
236 :
237 36 : pfree(resbuf);
238 :
239 36 : PG_FREE_IF_COPY(arg0, 0);
240 36 : PG_FREE_IF_COPY(arg1, 1);
241 :
242 36 : PG_RETURN_TEXT_P(res);
243 : }
244 :
245 : /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
246 14 : PG_FUNCTION_INFO_V1(pg_encrypt);
247 :
248 : Datum
249 134 : pg_encrypt(PG_FUNCTION_ARGS)
250 : {
251 : int err;
252 : bytea *data,
253 : *key,
254 : *res;
255 : text *type;
256 : PX_Combo *c;
257 : unsigned dlen,
258 : klen,
259 : rlen;
260 :
261 134 : type = PG_GETARG_TEXT_PP(2);
262 134 : c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
263 :
264 132 : data = PG_GETARG_BYTEA_PP(0);
265 132 : key = PG_GETARG_BYTEA_PP(1);
266 132 : dlen = VARSIZE_ANY_EXHDR(data);
267 132 : klen = VARSIZE_ANY_EXHDR(key);
268 :
269 132 : rlen = px_combo_encrypt_len(c, dlen);
270 132 : res = palloc(VARHDRSZ + rlen);
271 :
272 132 : err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
273 132 : if (!err)
274 132 : err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
275 : (uint8 *) VARDATA(res), &rlen);
276 132 : px_combo_free(c);
277 :
278 132 : PG_FREE_IF_COPY(data, 0);
279 132 : PG_FREE_IF_COPY(key, 1);
280 132 : PG_FREE_IF_COPY(type, 2);
281 :
282 132 : if (err)
283 : {
284 2 : pfree(res);
285 2 : ereport(ERROR,
286 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
287 : errmsg("encrypt error: %s", px_strerror(err))));
288 : }
289 :
290 130 : SET_VARSIZE(res, VARHDRSZ + rlen);
291 130 : PG_RETURN_BYTEA_P(res);
292 : }
293 :
294 : /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
295 12 : PG_FUNCTION_INFO_V1(pg_decrypt);
296 :
297 : Datum
298 28 : pg_decrypt(PG_FUNCTION_ARGS)
299 : {
300 : int err;
301 : bytea *data,
302 : *key,
303 : *res;
304 : text *type;
305 : PX_Combo *c;
306 : unsigned dlen,
307 : klen,
308 : rlen;
309 :
310 28 : type = PG_GETARG_TEXT_PP(2);
311 28 : c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
312 :
313 28 : data = PG_GETARG_BYTEA_PP(0);
314 28 : key = PG_GETARG_BYTEA_PP(1);
315 28 : dlen = VARSIZE_ANY_EXHDR(data);
316 28 : klen = VARSIZE_ANY_EXHDR(key);
317 :
318 28 : rlen = px_combo_decrypt_len(c, dlen);
319 28 : res = palloc(VARHDRSZ + rlen);
320 :
321 28 : err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
322 28 : if (!err)
323 28 : err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
324 : (uint8 *) VARDATA(res), &rlen);
325 :
326 28 : px_combo_free(c);
327 :
328 28 : if (err)
329 2 : ereport(ERROR,
330 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
331 : errmsg("decrypt error: %s", px_strerror(err))));
332 :
333 26 : SET_VARSIZE(res, VARHDRSZ + rlen);
334 :
335 26 : PG_FREE_IF_COPY(data, 0);
336 26 : PG_FREE_IF_COPY(key, 1);
337 26 : PG_FREE_IF_COPY(type, 2);
338 :
339 26 : PG_RETURN_BYTEA_P(res);
340 : }
341 :
342 : /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
343 12 : PG_FUNCTION_INFO_V1(pg_encrypt_iv);
344 :
345 : Datum
346 12 : pg_encrypt_iv(PG_FUNCTION_ARGS)
347 : {
348 : int err;
349 : bytea *data,
350 : *key,
351 : *iv,
352 : *res;
353 : text *type;
354 : PX_Combo *c;
355 : unsigned dlen,
356 : klen,
357 : ivlen,
358 : rlen;
359 :
360 12 : type = PG_GETARG_TEXT_PP(3);
361 12 : c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
362 :
363 12 : data = PG_GETARG_BYTEA_PP(0);
364 12 : key = PG_GETARG_BYTEA_PP(1);
365 12 : iv = PG_GETARG_BYTEA_PP(2);
366 12 : dlen = VARSIZE_ANY_EXHDR(data);
367 12 : klen = VARSIZE_ANY_EXHDR(key);
368 12 : ivlen = VARSIZE_ANY_EXHDR(iv);
369 :
370 12 : rlen = px_combo_encrypt_len(c, dlen);
371 12 : res = palloc(VARHDRSZ + rlen);
372 :
373 12 : err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
374 : (uint8 *) VARDATA_ANY(iv), ivlen);
375 12 : if (!err)
376 12 : err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
377 : (uint8 *) VARDATA(res), &rlen);
378 :
379 12 : px_combo_free(c);
380 :
381 12 : if (err)
382 0 : ereport(ERROR,
383 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
384 : errmsg("encrypt_iv error: %s", px_strerror(err))));
385 :
386 12 : SET_VARSIZE(res, VARHDRSZ + rlen);
387 :
388 12 : PG_FREE_IF_COPY(data, 0);
389 12 : PG_FREE_IF_COPY(key, 1);
390 12 : PG_FREE_IF_COPY(iv, 2);
391 12 : PG_FREE_IF_COPY(type, 3);
392 :
393 12 : PG_RETURN_BYTEA_P(res);
394 : }
395 :
396 : /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
397 12 : PG_FUNCTION_INFO_V1(pg_decrypt_iv);
398 :
399 : Datum
400 16 : pg_decrypt_iv(PG_FUNCTION_ARGS)
401 : {
402 : int err;
403 : bytea *data,
404 : *key,
405 : *iv,
406 : *res;
407 : text *type;
408 : PX_Combo *c;
409 : unsigned dlen,
410 : klen,
411 : rlen,
412 : ivlen;
413 :
414 16 : type = PG_GETARG_TEXT_PP(3);
415 16 : c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
416 :
417 16 : data = PG_GETARG_BYTEA_PP(0);
418 16 : key = PG_GETARG_BYTEA_PP(1);
419 16 : iv = PG_GETARG_BYTEA_PP(2);
420 16 : dlen = VARSIZE_ANY_EXHDR(data);
421 16 : klen = VARSIZE_ANY_EXHDR(key);
422 16 : ivlen = VARSIZE_ANY_EXHDR(iv);
423 :
424 16 : rlen = px_combo_decrypt_len(c, dlen);
425 16 : res = palloc(VARHDRSZ + rlen);
426 :
427 16 : err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
428 : (uint8 *) VARDATA_ANY(iv), ivlen);
429 16 : if (!err)
430 16 : err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
431 : (uint8 *) VARDATA(res), &rlen);
432 :
433 16 : px_combo_free(c);
434 :
435 16 : if (err)
436 2 : ereport(ERROR,
437 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
438 : errmsg("decrypt_iv error: %s", px_strerror(err))));
439 :
440 14 : SET_VARSIZE(res, VARHDRSZ + rlen);
441 :
442 14 : PG_FREE_IF_COPY(data, 0);
443 14 : PG_FREE_IF_COPY(key, 1);
444 14 : PG_FREE_IF_COPY(iv, 2);
445 14 : PG_FREE_IF_COPY(type, 3);
446 :
447 14 : PG_RETURN_BYTEA_P(res);
448 : }
449 :
450 : /* SQL function: pg_random_bytes(int4) returns bytea */
451 2 : PG_FUNCTION_INFO_V1(pg_random_bytes);
452 :
453 : Datum
454 0 : pg_random_bytes(PG_FUNCTION_ARGS)
455 : {
456 0 : int len = PG_GETARG_INT32(0);
457 : bytea *res;
458 :
459 0 : if (len < 1 || len > 1024)
460 0 : ereport(ERROR,
461 : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
462 : errmsg("Length not in range")));
463 :
464 0 : res = palloc(VARHDRSZ + len);
465 0 : SET_VARSIZE(res, VARHDRSZ + len);
466 :
467 : /* generate result */
468 0 : if (!pg_strong_random(VARDATA(res), len))
469 0 : px_THROW_ERROR(PXE_NO_RANDOM);
470 :
471 0 : PG_RETURN_BYTEA_P(res);
472 : }
473 :
474 : /* SQL function: gen_random_uuid() returns uuid */
475 2 : PG_FUNCTION_INFO_V1(pg_random_uuid);
476 :
477 : Datum
478 0 : pg_random_uuid(PG_FUNCTION_ARGS)
479 : {
480 : /* redirect to built-in function */
481 0 : return gen_random_uuid(fcinfo);
482 : }
483 :
484 2 : PG_FUNCTION_INFO_V1(pg_check_fipsmode);
485 :
486 : Datum
487 0 : pg_check_fipsmode(PG_FUNCTION_ARGS)
488 : {
489 0 : PG_RETURN_BOOL(CheckFIPSMode());
490 : }
491 :
492 : static void *
493 308 : find_provider(text *name,
494 : PFN provider_lookup,
495 : const char *desc, int silent)
496 : {
497 : void *res;
498 : char *buf;
499 : int err;
500 :
501 308 : buf = downcase_truncate_identifier(VARDATA_ANY(name),
502 308 : VARSIZE_ANY_EXHDR(name),
503 : false);
504 :
505 308 : err = provider_lookup(buf, &res);
506 :
507 308 : if (err && !silent)
508 6 : ereport(ERROR,
509 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
510 : errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
511 :
512 302 : pfree(buf);
513 :
514 302 : return err ? NULL : res;
515 : }
|