LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgcrypto.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 175 190 92.1 %
Date: 2025-02-18 08:14:55 Functions: 24 27 88.9 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14