LCOV - differential code coverage report
Current view: top level - src/common - cryptohash_openssl.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 61.8 % 123 76 47 76
Current Date: 2023-04-08 17:13:01 Functions: 71.4 % 7 5 2 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 61.8 % 123 76 47 76
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 71.4 % 7 5 2 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * cryptohash_openssl.c
                                  4                 :  *    Set of wrapper routines on top of OpenSSL to support cryptographic
                                  5                 :  *    hash functions.
                                  6                 :  *
                                  7                 :  * This should only be used if code is compiled with OpenSSL support.
                                  8                 :  *
                                  9                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 10                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 11                 :  *
                                 12                 :  * IDENTIFICATION
                                 13                 :  *        src/common/cryptohash_openssl.c
                                 14                 :  *
                                 15                 :  *-------------------------------------------------------------------------
                                 16                 :  */
                                 17                 : 
                                 18                 : #ifndef FRONTEND
                                 19                 : #include "postgres.h"
                                 20                 : #else
                                 21                 : #include "postgres_fe.h"
                                 22                 : #endif
                                 23                 : 
                                 24                 : #include <openssl/err.h>
                                 25                 : #include <openssl/evp.h>
                                 26                 : 
                                 27                 : #include "common/cryptohash.h"
                                 28                 : #include "common/md5.h"
                                 29                 : #include "common/sha1.h"
                                 30                 : #include "common/sha2.h"
                                 31                 : #ifndef FRONTEND
                                 32                 : #include "utils/memutils.h"
                                 33                 : #include "utils/resowner.h"
                                 34                 : #include "utils/resowner_private.h"
                                 35                 : #endif
                                 36                 : 
                                 37                 : /*
                                 38                 :  * In the backend, use an allocation in TopMemoryContext to count for
                                 39                 :  * resowner cleanup handling.  In the frontend, use malloc to be able
                                 40                 :  * to return a failure status back to the caller.
                                 41                 :  */
                                 42                 : #ifndef FRONTEND
                                 43                 : #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
                                 44                 : #define FREE(ptr) pfree(ptr)
                                 45                 : #else
                                 46                 : #define ALLOC(size) malloc(size)
                                 47                 : #define FREE(ptr) free(ptr)
                                 48                 : #endif
                                 49                 : 
                                 50                 : /* Set of error states */
                                 51                 : typedef enum pg_cryptohash_errno
                                 52                 : {
                                 53                 :     PG_CRYPTOHASH_ERROR_NONE = 0,
                                 54                 :     PG_CRYPTOHASH_ERROR_DEST_LEN,
                                 55                 :     PG_CRYPTOHASH_ERROR_OPENSSL
                                 56                 : } pg_cryptohash_errno;
                                 57                 : 
                                 58                 : /*
                                 59                 :  * Internal pg_cryptohash_ctx structure.
                                 60                 :  *
                                 61                 :  * This tracks the resource owner associated to each EVP context data
                                 62                 :  * for the backend.
                                 63                 :  */
                                 64                 : struct pg_cryptohash_ctx
                                 65                 : {
                                 66                 :     pg_cryptohash_type type;
                                 67                 :     pg_cryptohash_errno error;
                                 68                 :     const char *errreason;
                                 69                 : 
                                 70                 :     EVP_MD_CTX *evpctx;
                                 71                 : 
                                 72                 : #ifndef FRONTEND
                                 73                 :     ResourceOwner resowner;
                                 74                 : #endif
                                 75                 : };
                                 76                 : 
                                 77                 : static const char *
  453 michael                    78 UBC           0 : SSLerrmessage(unsigned long ecode)
                                 79                 : {
                                 80               0 :     if (ecode == 0)
                                 81               0 :         return NULL;
                                 82                 : 
                                 83                 :     /*
                                 84                 :      * This may return NULL, but we would fall back to a default error path if
                                 85                 :      * that were the case.
                                 86                 :      */
                                 87               0 :     return ERR_reason_error_string(ecode);
                                 88                 : }
                                 89                 : 
                                 90                 : /*
                                 91                 :  * pg_cryptohash_create
                                 92                 :  *
                                 93                 :  * Allocate a hash context.  Returns NULL on failure for an OOM.  The
                                 94                 :  * backend issues an error, without returning.
                                 95                 :  */
                                 96                 : pg_cryptohash_ctx *
  858 michael                    97 CBC      503216 : pg_cryptohash_create(pg_cryptohash_type type)
                                 98                 : {
                                 99                 :     pg_cryptohash_ctx *ctx;
                                100                 : 
                                101                 :     /*
                                102                 :      * Make sure that the resource owner has space to remember this reference.
                                103                 :      * This can error out with "out of memory", so do this before any other
                                104                 :      * allocation to avoid leaking.
                                105                 :      */
                                106                 : #ifndef FRONTEND
  822                           107          499247 :     ResourceOwnerEnlargeCryptoHash(CurrentResourceOwner);
                                108                 : #endif
                                109                 : 
  858                           110          503216 :     ctx = ALLOC(sizeof(pg_cryptohash_ctx));
                                111          503216 :     if (ctx == NULL)
  858 michael                   112 UBC           0 :         return NULL;
  822 michael                   113 CBC      503216 :     memset(ctx, 0, sizeof(pg_cryptohash_ctx));
  856                           114          503216 :     ctx->type = type;
  453                           115          503216 :     ctx->error = PG_CRYPTOHASH_ERROR_NONE;
                                116          503216 :     ctx->errreason = NULL;
                                117                 : 
                                118                 :     /*
                                119                 :      * Initialization takes care of assigning the correct type for OpenSSL.
                                120                 :      * Also ensure that there aren't any unconsumed errors in the queue from
                                121                 :      * previous runs.
                                122                 :      */
  338 dgustafsson               123          503216 :     ERR_clear_error();
  822 michael                   124          503216 :     ctx->evpctx = EVP_MD_CTX_create();
                                125                 : 
                                126          503216 :     if (ctx->evpctx == NULL)
                                127                 :     {
  858 michael                   128 UBC           0 :         explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
  822                           129               0 :         FREE(ctx);
                                130                 : #ifndef FRONTEND
  856                           131               0 :         ereport(ERROR,
                                132                 :                 (errcode(ERRCODE_OUT_OF_MEMORY),
                                133                 :                  errmsg("out of memory")));
                                134                 : #else
  858                           135               0 :         return NULL;
                                136                 : #endif
                                137                 :     }
                                138                 : 
                                139                 : #ifndef FRONTEND
  822 michael                   140 CBC      499247 :     ctx->resowner = CurrentResourceOwner;
  856                           141          499247 :     ResourceOwnerRememberCryptoHash(CurrentResourceOwner,
                                142                 :                                     PointerGetDatum(ctx));
                                143                 : #endif
                                144                 : 
  858                           145          503216 :     return ctx;
                                146                 : }
                                147                 : 
                                148                 : /*
                                149                 :  * pg_cryptohash_init
                                150                 :  *
                                151                 :  * Initialize a hash context.  Returns 0 on success, and -1 on failure.
                                152                 :  */
                                153                 : int
                                154          503216 : pg_cryptohash_init(pg_cryptohash_ctx *ctx)
                                155                 : {
                                156          503216 :     int         status = 0;
                                157                 : 
                                158          503216 :     if (ctx == NULL)
  822 michael                   159 UBC           0 :         return -1;
                                160                 : 
  858 michael                   161 CBC      503216 :     switch (ctx->type)
                                162                 :     {
  850                           163          395998 :         case PG_MD5:
  822                           164          395998 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_md5(), NULL);
  850                           165          395998 :             break;
  806                           166               1 :         case PG_SHA1:
                                167               1 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha1(), NULL);
                                168               1 :             break;
  858                           169            1937 :         case PG_SHA224:
  822                           170            1937 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha224(), NULL);
  858                           171            1937 :             break;
                                172          101406 :         case PG_SHA256:
  822                           173          101406 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha256(), NULL);
  858                           174          101406 :             break;
                                175            1937 :         case PG_SHA384:
  822                           176            1937 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha384(), NULL);
  858                           177            1937 :             break;
                                178            1937 :         case PG_SHA512:
  822                           179            1937 :             status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha512(), NULL);
  858                           180            1937 :             break;
                                181                 :     }
                                182                 : 
                                183                 :     /* OpenSSL internals return 1 on success, 0 on failure */
                                184          503216 :     if (status <= 0)
                                185                 :     {
  453 michael                   186 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
                                187               0 :         ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL;
                                188                 : 
                                189                 :         /*
                                190                 :          * The OpenSSL error queue should normally be empty since we've
                                191                 :          * consumed an error, but cipher initialization can in FIPS-enabled
                                192                 :          * OpenSSL builds generate two errors so clear the queue here as well.
                                193                 :          */
  338 dgustafsson               194               0 :         ERR_clear_error();
  858 michael                   195               0 :         return -1;
                                196                 :     }
  858 michael                   197 CBC      503216 :     return 0;
                                198                 : }
                                199                 : 
                                200                 : /*
                                201                 :  * pg_cryptohash_update
                                202                 :  *
                                203                 :  * Update a hash context.  Returns 0 on success, and -1 on failure.
                                204                 :  */
                                205                 : int
                                206          642374 : pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
                                207                 : {
                                208          642374 :     int         status = 0;
                                209                 : 
                                210          642374 :     if (ctx == NULL)
  822 michael                   211 UBC           0 :         return -1;
                                212                 : 
  822 michael                   213 CBC      642374 :     status = EVP_DigestUpdate(ctx->evpctx, data, len);
                                214                 : 
                                215                 :     /* OpenSSL internals return 1 on success, 0 on failure */
  858                           216          642374 :     if (status <= 0)
                                217                 :     {
  453 michael                   218 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
                                219               0 :         ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL;
  858                           220               0 :         return -1;
                                221                 :     }
  858 michael                   222 CBC      642374 :     return 0;
                                223                 : }
                                224                 : 
                                225                 : /*
                                226                 :  * pg_cryptohash_final
                                227                 :  *
                                228                 :  * Finalize a hash context.  Returns 0 on success, and -1 on failure.
                                229                 :  */
                                230                 : int
  783                           231          503210 : pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
                                232                 : {
  858                           233          503210 :     int         status = 0;
                                234                 : 
                                235          503210 :     if (ctx == NULL)
  822 michael                   236 UBC           0 :         return -1;
                                237                 : 
  783 michael                   238 CBC      503210 :     switch (ctx->type)
                                239                 :     {
                                240          395998 :         case PG_MD5:
                                241          395998 :             if (len < MD5_DIGEST_LENGTH)
                                242                 :             {
  453 michael                   243 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           244               0 :                 return -1;
                                245                 :             }
  783 michael                   246 CBC      395998 :             break;
                                247               1 :         case PG_SHA1:
                                248               1 :             if (len < SHA1_DIGEST_LENGTH)
                                249                 :             {
  453 michael                   250 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           251               0 :                 return -1;
                                252                 :             }
  783 michael                   253 CBC           1 :             break;
                                254            1937 :         case PG_SHA224:
                                255            1937 :             if (len < PG_SHA224_DIGEST_LENGTH)
                                256                 :             {
  453 michael                   257 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           258               0 :                 return -1;
                                259                 :             }
  783 michael                   260 CBC        1937 :             break;
                                261          101400 :         case PG_SHA256:
                                262          101400 :             if (len < PG_SHA256_DIGEST_LENGTH)
                                263                 :             {
  453 michael                   264 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           265               0 :                 return -1;
                                266                 :             }
  783 michael                   267 CBC      101400 :             break;
                                268            1937 :         case PG_SHA384:
                                269            1937 :             if (len < PG_SHA384_DIGEST_LENGTH)
                                270                 :             {
  453 michael                   271 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           272               0 :                 return -1;
                                273                 :             }
  783 michael                   274 CBC        1937 :             break;
                                275            1937 :         case PG_SHA512:
                                276            1937 :             if (len < PG_SHA512_DIGEST_LENGTH)
                                277                 :             {
  453 michael                   278 UBC           0 :                 ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN;
  783                           279               0 :                 return -1;
                                280                 :             }
  783 michael                   281 CBC        1937 :             break;
                                282                 :     }
                                283                 : 
  822                           284          503210 :     status = EVP_DigestFinal_ex(ctx->evpctx, dest, 0);
                                285                 : 
                                286                 :     /* OpenSSL internals return 1 on success, 0 on failure */
  858                           287          503210 :     if (status <= 0)
                                288                 :     {
  453 michael                   289 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
                                290               0 :         ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL;
  858                           291               0 :         return -1;
                                292                 :     }
  858 michael                   293 CBC      503210 :     return 0;
                                294                 : }
                                295                 : 
                                296                 : /*
                                297                 :  * pg_cryptohash_free
                                298                 :  *
                                299                 :  * Free a hash context.
                                300                 :  */
                                301                 : void
                                302          503210 : pg_cryptohash_free(pg_cryptohash_ctx *ctx)
                                303                 : {
                                304          503210 :     if (ctx == NULL)
                                305               1 :         return;
                                306                 : 
  822                           307          503209 :     EVP_MD_CTX_destroy(ctx->evpctx);
                                308                 : 
                                309                 : #ifndef FRONTEND
                                310          499242 :     ResourceOwnerForgetCryptoHash(ctx->resowner,
                                311                 :                                   PointerGetDatum(ctx));
                                312                 : #endif
                                313                 : 
  858                           314          503209 :     explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
                                315          503209 :     FREE(ctx);
                                316                 : }
                                317                 : 
                                318                 : /*
                                319                 :  * pg_cryptohash_error
                                320                 :  *
                                321                 :  * Returns a static string providing details about an error that
                                322                 :  * happened during a computation.
                                323                 :  */
                                324                 : const char *
  453 michael                   325 UBC           0 : pg_cryptohash_error(pg_cryptohash_ctx *ctx)
                                326                 : {
                                327                 :     /*
                                328                 :      * This implementation would never fail because of an out-of-memory error,
                                329                 :      * except when creating the context.
                                330                 :      */
                                331               0 :     if (ctx == NULL)
                                332               0 :         return _("out of memory");
                                333                 : 
                                334                 :     /*
                                335                 :      * If a reason is provided, rely on it, else fallback to any error code
                                336                 :      * set.
                                337                 :      */
                                338               0 :     if (ctx->errreason)
                                339               0 :         return ctx->errreason;
                                340                 : 
                                341               0 :     switch (ctx->error)
                                342                 :     {
                                343               0 :         case PG_CRYPTOHASH_ERROR_NONE:
                                344               0 :             return _("success");
                                345               0 :         case PG_CRYPTOHASH_ERROR_DEST_LEN:
                                346               0 :             return _("destination buffer too small");
                                347               0 :         case PG_CRYPTOHASH_ERROR_OPENSSL:
                                348               0 :             return _("OpenSSL failure");
                                349                 :     }
                                350                 : 
                                351               0 :     Assert(false);              /* cannot be reached */
                                352                 :     return _("success");
                                353                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a