LCOV - differential code coverage report
Current view: top level - src/common - hmac_openssl.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 36.9 % 122 45 77 45
Current Date: 2023-04-08 15:15:32 Functions: 71.4 % 7 5 2 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * hmac_openssl.c
       4                 :  *    Implementation of HMAC with OpenSSL.
       5                 :  *
       6                 :  * This should only be used if code is compiled with OpenSSL support.
       7                 :  *
       8                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       9                 :  * Portions Copyright (c) 1994, Regents of the University of California
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/common/hmac_openssl.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : 
      17                 : #ifndef FRONTEND
      18                 : #include "postgres.h"
      19                 : #else
      20                 : #include "postgres_fe.h"
      21                 : #endif
      22                 : 
      23                 : 
      24                 : #include <openssl/err.h>
      25                 : #include <openssl/hmac.h>
      26                 : 
      27                 : #include "common/hmac.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 backend, use an allocation in TopMemoryContext to count for resowner
      39                 :  * cleanup handling if necessary.  For versions of OpenSSL where HMAC_CTX is
      40                 :  * known, just use palloc().  In frontend, use malloc to be able to return
      41                 :  * a failure status back to the caller.
      42                 :  */
      43                 : #ifndef FRONTEND
      44                 : #ifdef HAVE_HMAC_CTX_NEW
      45                 : #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
      46                 : #else
      47                 : #define ALLOC(size) palloc(size)
      48                 : #endif
      49                 : #define FREE(ptr) pfree(ptr)
      50                 : #else                           /* FRONTEND */
      51                 : #define ALLOC(size) malloc(size)
      52                 : #define FREE(ptr) free(ptr)
      53                 : #endif                          /* FRONTEND */
      54                 : 
      55                 : /* Set of error states */
      56                 : typedef enum pg_hmac_errno
      57                 : {
      58                 :     PG_HMAC_ERROR_NONE = 0,
      59                 :     PG_HMAC_ERROR_DEST_LEN,
      60                 :     PG_HMAC_ERROR_OPENSSL
      61                 : } pg_hmac_errno;
      62                 : 
      63                 : /* Internal pg_hmac_ctx structure */
      64                 : struct pg_hmac_ctx
      65                 : {
      66                 :     HMAC_CTX   *hmacctx;
      67                 :     pg_cryptohash_type type;
      68                 :     pg_hmac_errno error;
      69                 :     const char *errreason;
      70                 : 
      71                 : #ifndef FRONTEND
      72                 :     ResourceOwner resowner;
      73                 : #endif
      74                 : };
      75                 : 
      76                 : static const char *
      77 UBC           0 : SSLerrmessage(unsigned long ecode)
      78                 : {
      79               0 :     if (ecode == 0)
      80               0 :         return NULL;
      81                 : 
      82                 :     /*
      83                 :      * This may return NULL, but we would fall back to a default error path if
      84                 :      * that were the case.
      85                 :      */
      86               0 :     return ERR_reason_error_string(ecode);
      87                 : }
      88                 : 
      89                 : /*
      90                 :  * pg_hmac_create
      91                 :  *
      92                 :  * Allocate a hash context.  Returns NULL on failure for an OOM.  The
      93                 :  * backend issues an error, without returning.
      94                 :  */
      95                 : pg_hmac_ctx *
      96 CBC         377 : pg_hmac_create(pg_cryptohash_type type)
      97                 : {
      98                 :     pg_hmac_ctx *ctx;
      99                 : 
     100             377 :     ctx = ALLOC(sizeof(pg_hmac_ctx));
     101             377 :     if (ctx == NULL)
     102 UBC           0 :         return NULL;
     103 CBC         377 :     memset(ctx, 0, sizeof(pg_hmac_ctx));
     104                 : 
     105             377 :     ctx->type = type;
     106             377 :     ctx->error = PG_HMAC_ERROR_NONE;
     107             377 :     ctx->errreason = NULL;
     108                 : 
     109                 : 
     110                 :     /*
     111                 :      * Initialization takes care of assigning the correct type for OpenSSL.
     112                 :      * Also ensure that there aren't any unconsumed errors in the queue from
     113                 :      * previous runs.
     114                 :      */
     115             377 :     ERR_clear_error();
     116                 : #ifdef HAVE_HMAC_CTX_NEW
     117                 : #ifndef FRONTEND
     118             216 :     ResourceOwnerEnlargeHMAC(CurrentResourceOwner);
     119                 : #endif
     120             377 :     ctx->hmacctx = HMAC_CTX_new();
     121                 : #else
     122                 :     ctx->hmacctx = ALLOC(sizeof(HMAC_CTX));
     123                 : #endif
     124                 : 
     125             377 :     if (ctx->hmacctx == NULL)
     126                 :     {
     127 UBC           0 :         explicit_bzero(ctx, sizeof(pg_hmac_ctx));
     128               0 :         FREE(ctx);
     129                 : #ifndef FRONTEND
     130               0 :         ereport(ERROR,
     131                 :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     132                 :                  errmsg("out of memory")));
     133                 : #endif
     134               0 :         return NULL;
     135                 :     }
     136                 : 
     137                 : #ifdef HAVE_HMAC_CTX_NEW
     138                 : #ifndef FRONTEND
     139 CBC         216 :     ctx->resowner = CurrentResourceOwner;
     140             216 :     ResourceOwnerRememberHMAC(CurrentResourceOwner, PointerGetDatum(ctx));
     141                 : #endif
     142                 : #else
     143                 :     memset(ctx->hmacctx, 0, sizeof(HMAC_CTX));
     144                 : #endif                          /* HAVE_HMAC_CTX_NEW */
     145                 : 
     146             377 :     return ctx;
     147                 : }
     148                 : 
     149                 : /*
     150                 :  * pg_hmac_init
     151                 :  *
     152                 :  * Initialize a HMAC context.  Returns 0 on success, -1 on failure.
     153                 :  */
     154                 : int
     155          334235 : pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
     156                 : {
     157          334235 :     int         status = 0;
     158                 : 
     159          334235 :     if (ctx == NULL)
     160 UBC           0 :         return -1;
     161                 : 
     162 CBC      334235 :     switch (ctx->type)
     163                 :     {
     164 UBC           0 :         case PG_MD5:
     165               0 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_md5(), NULL);
     166               0 :             break;
     167               0 :         case PG_SHA1:
     168               0 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha1(), NULL);
     169               0 :             break;
     170               0 :         case PG_SHA224:
     171               0 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha224(), NULL);
     172               0 :             break;
     173 CBC      334235 :         case PG_SHA256:
     174          334235 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha256(), NULL);
     175          334235 :             break;
     176 UBC           0 :         case PG_SHA384:
     177               0 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha384(), NULL);
     178               0 :             break;
     179               0 :         case PG_SHA512:
     180               0 :             status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha512(), NULL);
     181               0 :             break;
     182                 :     }
     183                 : 
     184                 :     /* OpenSSL internals return 1 on success, 0 on failure */
     185 CBC      334235 :     if (status <= 0)
     186                 :     {
     187 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
     188               0 :         ctx->error = PG_HMAC_ERROR_OPENSSL;
     189               0 :         return -1;
     190                 :     }
     191                 : 
     192 CBC      334235 :     return 0;
     193                 : }
     194                 : 
     195                 : /*
     196                 :  * pg_hmac_update
     197                 :  *
     198                 :  * Update a HMAC context.  Returns 0 on success, -1 on failure.
     199                 :  */
     200                 : int
     201          334815 : pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
     202                 : {
     203          334815 :     int         status = 0;
     204                 : 
     205          334815 :     if (ctx == NULL)
     206 UBC           0 :         return -1;
     207                 : 
     208 CBC      334815 :     status = HMAC_Update(ctx->hmacctx, data, len);
     209                 : 
     210                 :     /* OpenSSL internals return 1 on success, 0 on failure */
     211          334815 :     if (status <= 0)
     212                 :     {
     213 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
     214               0 :         ctx->error = PG_HMAC_ERROR_OPENSSL;
     215               0 :         return -1;
     216                 :     }
     217 CBC      334815 :     return 0;
     218                 : }
     219                 : 
     220                 : /*
     221                 :  * pg_hmac_final
     222                 :  *
     223                 :  * Finalize a HMAC context.  Returns 0 on success, -1 on failure.
     224                 :  */
     225                 : int
     226          334235 : pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
     227                 : {
     228          334235 :     int         status = 0;
     229                 :     uint32      outlen;
     230                 : 
     231          334235 :     if (ctx == NULL)
     232 UBC           0 :         return -1;
     233                 : 
     234 CBC      334235 :     switch (ctx->type)
     235                 :     {
     236 UBC           0 :         case PG_MD5:
     237               0 :             if (len < MD5_DIGEST_LENGTH)
     238                 :             {
     239               0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     240               0 :                 return -1;
     241                 :             }
     242               0 :             break;
     243               0 :         case PG_SHA1:
     244               0 :             if (len < SHA1_DIGEST_LENGTH)
     245                 :             {
     246               0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     247               0 :                 return -1;
     248                 :             }
     249               0 :             break;
     250               0 :         case PG_SHA224:
     251               0 :             if (len < PG_SHA224_DIGEST_LENGTH)
     252                 :             {
     253               0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     254               0 :                 return -1;
     255                 :             }
     256               0 :             break;
     257 CBC      334235 :         case PG_SHA256:
     258          334235 :             if (len < PG_SHA256_DIGEST_LENGTH)
     259                 :             {
     260 UBC           0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     261               0 :                 return -1;
     262                 :             }
     263 CBC      334235 :             break;
     264 UBC           0 :         case PG_SHA384:
     265               0 :             if (len < PG_SHA384_DIGEST_LENGTH)
     266                 :             {
     267               0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     268               0 :                 return -1;
     269                 :             }
     270               0 :             break;
     271               0 :         case PG_SHA512:
     272               0 :             if (len < PG_SHA512_DIGEST_LENGTH)
     273                 :             {
     274               0 :                 ctx->error = PG_HMAC_ERROR_DEST_LEN;
     275               0 :                 return -1;
     276                 :             }
     277               0 :             break;
     278                 :     }
     279                 : 
     280 CBC      334235 :     status = HMAC_Final(ctx->hmacctx, dest, &outlen);
     281                 : 
     282                 :     /* OpenSSL internals return 1 on success, 0 on failure */
     283          334235 :     if (status <= 0)
     284                 :     {
     285 UBC           0 :         ctx->errreason = SSLerrmessage(ERR_get_error());
     286               0 :         ctx->error = PG_HMAC_ERROR_OPENSSL;
     287               0 :         return -1;
     288                 :     }
     289 CBC      334235 :     return 0;
     290                 : }
     291                 : 
     292                 : /*
     293                 :  * pg_hmac_free
     294                 :  *
     295                 :  * Free a HMAC context.
     296                 :  */
     297                 : void
     298             377 : pg_hmac_free(pg_hmac_ctx *ctx)
     299                 : {
     300             377 :     if (ctx == NULL)
     301 UBC           0 :         return;
     302                 : 
     303                 : #ifdef HAVE_HMAC_CTX_FREE
     304 CBC         377 :     HMAC_CTX_free(ctx->hmacctx);
     305                 : #ifndef FRONTEND
     306             216 :     ResourceOwnerForgetHMAC(ctx->resowner, PointerGetDatum(ctx));
     307                 : #endif
     308                 : #else
     309                 :     explicit_bzero(ctx->hmacctx, sizeof(HMAC_CTX));
     310                 :     FREE(ctx->hmacctx);
     311                 : #endif
     312                 : 
     313             377 :     explicit_bzero(ctx, sizeof(pg_hmac_ctx));
     314             377 :     FREE(ctx);
     315                 : }
     316                 : 
     317                 : /*
     318                 :  * pg_hmac_error
     319                 :  *
     320                 :  * Returns a static string providing details about an error that happened
     321                 :  * during a HMAC computation.
     322                 :  */
     323                 : const char *
     324 UBC           0 : pg_hmac_error(pg_hmac_ctx *ctx)
     325                 : {
     326               0 :     if (ctx == NULL)
     327               0 :         return _("out of memory");
     328                 : 
     329                 :     /*
     330                 :      * If a reason is provided, rely on it, else fallback to any error code
     331                 :      * set.
     332                 :      */
     333               0 :     if (ctx->errreason)
     334               0 :         return ctx->errreason;
     335                 : 
     336               0 :     switch (ctx->error)
     337                 :     {
     338               0 :         case PG_HMAC_ERROR_NONE:
     339               0 :             return _("success");
     340               0 :         case PG_HMAC_ERROR_DEST_LEN:
     341               0 :             return _("destination buffer too small");
     342               0 :         case PG_HMAC_ERROR_OPENSSL:
     343               0 :             return _("OpenSSL failure");
     344                 :     }
     345                 : 
     346               0 :     Assert(false);              /* cannot be reached */
     347                 :     return _("success");
     348                 : }
        

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