At update of non-LP_NORMAL TID, fail instead of corrupting page header.
[pgsql.git] / contrib / pgcrypto / pgcrypto.c
blobb7e5383b9a6a6b1282a0e412b500084eddb8eac9
1 /*
2 * pgcrypto.c
3 * Various cryptographic stuff for PostgreSQL.
5 * Copyright (c) 2001 Marko Kreen
6 * All rights reserved.
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.
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.
29 * contrib/pgcrypto/pgcrypto.c
32 #include "postgres.h"
34 #include <ctype.h>
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"
44 PG_MODULE_MAGIC;
46 /* private stuff */
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}
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);
59 int builtin_crypto_enabled = BC_ON;
62 * Entrypoint of this module.
64 void
65 _PG_init(void)
67 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,
76 NULL,
77 NULL,
78 NULL);
79 MarkGUCPrefixReserved("pgcrypto");
82 /* SQL function: hash(bytea, text) returns bytea */
83 PG_FUNCTION_INFO_V1(pg_digest);
85 Datum
86 pg_digest(PG_FUNCTION_ARGS)
88 bytea *arg;
89 text *name;
90 unsigned len,
91 hlen;
92 PX_MD *md;
93 bytea *res;
95 name = PG_GETARG_TEXT_PP(1);
97 /* will give error if fails */
98 md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
100 hlen = px_md_result_size(md);
102 res = (text *) palloc(hlen + VARHDRSZ);
103 SET_VARSIZE(res, hlen + VARHDRSZ);
105 arg = PG_GETARG_BYTEA_PP(0);
106 len = VARSIZE_ANY_EXHDR(arg);
108 px_md_update(md, (uint8 *) VARDATA_ANY(arg), len);
109 px_md_finish(md, (uint8 *) VARDATA(res));
110 px_md_free(md);
112 PG_FREE_IF_COPY(arg, 0);
113 PG_FREE_IF_COPY(name, 1);
115 PG_RETURN_BYTEA_P(res);
118 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
119 PG_FUNCTION_INFO_V1(pg_hmac);
121 Datum
122 pg_hmac(PG_FUNCTION_ARGS)
124 bytea *arg;
125 bytea *key;
126 text *name;
127 unsigned len,
128 hlen,
129 klen;
130 PX_HMAC *h;
131 bytea *res;
133 name = PG_GETARG_TEXT_PP(2);
135 /* will give error if fails */
136 h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
138 hlen = px_hmac_result_size(h);
140 res = (text *) palloc(hlen + VARHDRSZ);
141 SET_VARSIZE(res, hlen + VARHDRSZ);
143 arg = PG_GETARG_BYTEA_PP(0);
144 key = PG_GETARG_BYTEA_PP(1);
145 len = VARSIZE_ANY_EXHDR(arg);
146 klen = VARSIZE_ANY_EXHDR(key);
148 px_hmac_init(h, (uint8 *) VARDATA_ANY(key), klen);
149 px_hmac_update(h, (uint8 *) VARDATA_ANY(arg), len);
150 px_hmac_finish(h, (uint8 *) VARDATA(res));
151 px_hmac_free(h);
153 PG_FREE_IF_COPY(arg, 0);
154 PG_FREE_IF_COPY(key, 1);
155 PG_FREE_IF_COPY(name, 2);
157 PG_RETURN_BYTEA_P(res);
161 /* SQL function: pg_gen_salt(text) returns text */
162 PG_FUNCTION_INFO_V1(pg_gen_salt);
164 Datum
165 pg_gen_salt(PG_FUNCTION_ARGS)
167 text *arg0 = PG_GETARG_TEXT_PP(0);
168 int len;
169 char buf[PX_MAX_SALT_LEN + 1];
171 text_to_cstring_buffer(arg0, buf, sizeof(buf));
172 len = px_gen_salt(buf, buf, 0);
173 if (len < 0)
174 ereport(ERROR,
175 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
176 errmsg("gen_salt: %s", px_strerror(len))));
178 PG_FREE_IF_COPY(arg0, 0);
180 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
183 /* SQL function: pg_gen_salt(text, int4) returns text */
184 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
186 Datum
187 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
189 text *arg0 = PG_GETARG_TEXT_PP(0);
190 int rounds = PG_GETARG_INT32(1);
191 int len;
192 char buf[PX_MAX_SALT_LEN + 1];
194 text_to_cstring_buffer(arg0, buf, sizeof(buf));
195 len = px_gen_salt(buf, buf, rounds);
196 if (len < 0)
197 ereport(ERROR,
198 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
199 errmsg("gen_salt: %s", px_strerror(len))));
201 PG_FREE_IF_COPY(arg0, 0);
203 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
206 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
207 PG_FUNCTION_INFO_V1(pg_crypt);
209 Datum
210 pg_crypt(PG_FUNCTION_ARGS)
212 text *arg0 = PG_GETARG_TEXT_PP(0);
213 text *arg1 = PG_GETARG_TEXT_PP(1);
214 char *buf0,
215 *buf1,
216 *cres,
217 *resbuf;
218 text *res;
220 buf0 = text_to_cstring(arg0);
221 buf1 = text_to_cstring(arg1);
223 resbuf = palloc0(PX_MAX_CRYPT);
225 cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
227 pfree(buf0);
228 pfree(buf1);
230 if (cres == NULL)
231 ereport(ERROR,
232 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
233 errmsg("crypt(3) returned NULL")));
235 res = cstring_to_text(cres);
237 pfree(resbuf);
239 PG_FREE_IF_COPY(arg0, 0);
240 PG_FREE_IF_COPY(arg1, 1);
242 PG_RETURN_TEXT_P(res);
245 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
246 PG_FUNCTION_INFO_V1(pg_encrypt);
248 Datum
249 pg_encrypt(PG_FUNCTION_ARGS)
251 int err;
252 bytea *data,
253 *key,
254 *res;
255 text *type;
256 PX_Combo *c;
257 unsigned dlen,
258 klen,
259 rlen;
261 type = PG_GETARG_TEXT_PP(2);
262 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
264 data = PG_GETARG_BYTEA_PP(0);
265 key = PG_GETARG_BYTEA_PP(1);
266 dlen = VARSIZE_ANY_EXHDR(data);
267 klen = VARSIZE_ANY_EXHDR(key);
269 rlen = px_combo_encrypt_len(c, dlen);
270 res = palloc(VARHDRSZ + rlen);
272 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
273 if (!err)
274 err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
275 (uint8 *) VARDATA(res), &rlen);
276 px_combo_free(c);
278 PG_FREE_IF_COPY(data, 0);
279 PG_FREE_IF_COPY(key, 1);
280 PG_FREE_IF_COPY(type, 2);
282 if (err)
284 pfree(res);
285 ereport(ERROR,
286 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
287 errmsg("encrypt error: %s", px_strerror(err))));
290 SET_VARSIZE(res, VARHDRSZ + rlen);
291 PG_RETURN_BYTEA_P(res);
294 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
295 PG_FUNCTION_INFO_V1(pg_decrypt);
297 Datum
298 pg_decrypt(PG_FUNCTION_ARGS)
300 int err;
301 bytea *data,
302 *key,
303 *res;
304 text *type;
305 PX_Combo *c;
306 unsigned dlen,
307 klen,
308 rlen;
310 type = PG_GETARG_TEXT_PP(2);
311 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
313 data = PG_GETARG_BYTEA_PP(0);
314 key = PG_GETARG_BYTEA_PP(1);
315 dlen = VARSIZE_ANY_EXHDR(data);
316 klen = VARSIZE_ANY_EXHDR(key);
318 rlen = px_combo_decrypt_len(c, dlen);
319 res = palloc(VARHDRSZ + rlen);
321 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
322 if (!err)
323 err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
324 (uint8 *) VARDATA(res), &rlen);
326 px_combo_free(c);
328 if (err)
329 ereport(ERROR,
330 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
331 errmsg("decrypt error: %s", px_strerror(err))));
333 SET_VARSIZE(res, VARHDRSZ + rlen);
335 PG_FREE_IF_COPY(data, 0);
336 PG_FREE_IF_COPY(key, 1);
337 PG_FREE_IF_COPY(type, 2);
339 PG_RETURN_BYTEA_P(res);
342 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
343 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
345 Datum
346 pg_encrypt_iv(PG_FUNCTION_ARGS)
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;
360 type = PG_GETARG_TEXT_PP(3);
361 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
363 data = PG_GETARG_BYTEA_PP(0);
364 key = PG_GETARG_BYTEA_PP(1);
365 iv = PG_GETARG_BYTEA_PP(2);
366 dlen = VARSIZE_ANY_EXHDR(data);
367 klen = VARSIZE_ANY_EXHDR(key);
368 ivlen = VARSIZE_ANY_EXHDR(iv);
370 rlen = px_combo_encrypt_len(c, dlen);
371 res = palloc(VARHDRSZ + rlen);
373 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
374 (uint8 *) VARDATA_ANY(iv), ivlen);
375 if (!err)
376 err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
377 (uint8 *) VARDATA(res), &rlen);
379 px_combo_free(c);
381 if (err)
382 ereport(ERROR,
383 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
384 errmsg("encrypt_iv error: %s", px_strerror(err))));
386 SET_VARSIZE(res, VARHDRSZ + rlen);
388 PG_FREE_IF_COPY(data, 0);
389 PG_FREE_IF_COPY(key, 1);
390 PG_FREE_IF_COPY(iv, 2);
391 PG_FREE_IF_COPY(type, 3);
393 PG_RETURN_BYTEA_P(res);
396 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
397 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
399 Datum
400 pg_decrypt_iv(PG_FUNCTION_ARGS)
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;
414 type = PG_GETARG_TEXT_PP(3);
415 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
417 data = PG_GETARG_BYTEA_PP(0);
418 key = PG_GETARG_BYTEA_PP(1);
419 iv = PG_GETARG_BYTEA_PP(2);
420 dlen = VARSIZE_ANY_EXHDR(data);
421 klen = VARSIZE_ANY_EXHDR(key);
422 ivlen = VARSIZE_ANY_EXHDR(iv);
424 rlen = px_combo_decrypt_len(c, dlen);
425 res = palloc(VARHDRSZ + rlen);
427 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
428 (uint8 *) VARDATA_ANY(iv), ivlen);
429 if (!err)
430 err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
431 (uint8 *) VARDATA(res), &rlen);
433 px_combo_free(c);
435 if (err)
436 ereport(ERROR,
437 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
438 errmsg("decrypt_iv error: %s", px_strerror(err))));
440 SET_VARSIZE(res, VARHDRSZ + rlen);
442 PG_FREE_IF_COPY(data, 0);
443 PG_FREE_IF_COPY(key, 1);
444 PG_FREE_IF_COPY(iv, 2);
445 PG_FREE_IF_COPY(type, 3);
447 PG_RETURN_BYTEA_P(res);
450 /* SQL function: pg_random_bytes(int4) returns bytea */
451 PG_FUNCTION_INFO_V1(pg_random_bytes);
453 Datum
454 pg_random_bytes(PG_FUNCTION_ARGS)
456 int len = PG_GETARG_INT32(0);
457 bytea *res;
459 if (len < 1 || len > 1024)
460 ereport(ERROR,
461 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
462 errmsg("Length not in range")));
464 res = palloc(VARHDRSZ + len);
465 SET_VARSIZE(res, VARHDRSZ + len);
467 /* generate result */
468 if (!pg_strong_random(VARDATA(res), len))
469 px_THROW_ERROR(PXE_NO_RANDOM);
471 PG_RETURN_BYTEA_P(res);
474 /* SQL function: gen_random_uuid() returns uuid */
475 PG_FUNCTION_INFO_V1(pg_random_uuid);
477 Datum
478 pg_random_uuid(PG_FUNCTION_ARGS)
480 /* redirect to built-in function */
481 return gen_random_uuid(fcinfo);
484 PG_FUNCTION_INFO_V1(pg_check_fipsmode);
486 Datum
487 pg_check_fipsmode(PG_FUNCTION_ARGS)
489 PG_RETURN_BOOL(CheckFIPSMode());
492 static void *
493 find_provider(text *name,
494 PFN provider_lookup,
495 const char *desc, int silent)
497 void *res;
498 char *buf;
499 int err;
501 buf = downcase_truncate_identifier(VARDATA_ANY(name),
502 VARSIZE_ANY_EXHDR(name),
503 false);
505 err = provider_lookup(buf, &res);
507 if (err && !silent)
508 ereport(ERROR,
509 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
510 errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
512 pfree(buf);
514 return err ? NULL : res;