PostgreSQL Source Code  git master
hmac_openssl.c
Go to the documentation of this file.
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-2024, 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 #endif
35 
36 /*
37  * In backend, use an allocation in TopMemoryContext to count for resowner
38  * cleanup handling if necessary. In frontend, use malloc to be able to return
39  * a failure status back to the caller.
40  */
41 #ifndef FRONTEND
42 #define USE_RESOWNER_FOR_HMAC
43 #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
44 #define FREE(ptr) pfree(ptr)
45 #else /* FRONTEND */
46 #define ALLOC(size) malloc(size)
47 #define FREE(ptr) free(ptr)
48 #endif /* FRONTEND */
49 
50 /* Set of error states */
51 typedef enum pg_hmac_errno
52 {
57 
58 /* Internal pg_hmac_ctx structure */
59 struct pg_hmac_ctx
60 {
61  HMAC_CTX *hmacctx;
64  const char *errreason;
65 
66 #ifdef USE_RESOWNER_FOR_HMAC
68 #endif
69 };
70 
71 /* ResourceOwner callbacks to hold HMAC contexts */
72 #ifdef USE_RESOWNER_FOR_HMAC
73 static void ResOwnerReleaseHMAC(Datum res);
74 
76 {
77  .name = "OpenSSL HMAC context",
78  .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
79  .release_priority = RELEASE_PRIO_HMAC_CONTEXTS,
80  .ReleaseResource = ResOwnerReleaseHMAC,
81  .DebugPrint = NULL /* the default message is fine */
82 };
83 
84 /* Convenience wrappers over ResourceOwnerRemember/Forget */
85 static inline void
87 {
89 }
90 static inline void
92 {
94 }
95 #endif
96 
97 static const char *
98 SSLerrmessage(unsigned long ecode)
99 {
100  if (ecode == 0)
101  return NULL;
102 
103  /*
104  * This may return NULL, but we would fall back to a default error path if
105  * that were the case.
106  */
107  return ERR_reason_error_string(ecode);
108 }
109 
110 /*
111  * pg_hmac_create
112  *
113  * Allocate a hash context. Returns NULL on failure for an OOM. The
114  * backend issues an error, without returning.
115  */
116 pg_hmac_ctx *
118 {
119  pg_hmac_ctx *ctx;
120 
121  ctx = ALLOC(sizeof(pg_hmac_ctx));
122  if (ctx == NULL)
123  return NULL;
124  memset(ctx, 0, sizeof(pg_hmac_ctx));
125 
126  ctx->type = type;
127  ctx->error = PG_HMAC_ERROR_NONE;
128  ctx->errreason = NULL;
129 
130 
131  /*
132  * Initialization takes care of assigning the correct type for OpenSSL.
133  * Also ensure that there aren't any unconsumed errors in the queue from
134  * previous runs.
135  */
136  ERR_clear_error();
137 
138 #ifdef USE_RESOWNER_FOR_HMAC
140 #endif
141 
142  ctx->hmacctx = HMAC_CTX_new();
143 
144  if (ctx->hmacctx == NULL)
145  {
146  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
147  FREE(ctx);
148 #ifndef FRONTEND
149  ereport(ERROR,
150  (errcode(ERRCODE_OUT_OF_MEMORY),
151  errmsg("out of memory")));
152 #endif
153  return NULL;
154  }
155 
156 
157 #ifdef USE_RESOWNER_FOR_HMAC
160 #endif
161 
162  return ctx;
163 }
164 
165 /*
166  * pg_hmac_init
167  *
168  * Initialize a HMAC context. Returns 0 on success, -1 on failure.
169  */
170 int
171 pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
172 {
173  int status = 0;
174 
175  if (ctx == NULL)
176  return -1;
177 
178  switch (ctx->type)
179  {
180  case PG_MD5:
181  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_md5(), NULL);
182  break;
183  case PG_SHA1:
184  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha1(), NULL);
185  break;
186  case PG_SHA224:
187  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha224(), NULL);
188  break;
189  case PG_SHA256:
190  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha256(), NULL);
191  break;
192  case PG_SHA384:
193  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha384(), NULL);
194  break;
195  case PG_SHA512:
196  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha512(), NULL);
197  break;
198  }
199 
200  /* OpenSSL internals return 1 on success, 0 on failure */
201  if (status <= 0)
202  {
203  ctx->errreason = SSLerrmessage(ERR_get_error());
205  return -1;
206  }
207 
208  return 0;
209 }
210 
211 /*
212  * pg_hmac_update
213  *
214  * Update a HMAC context. Returns 0 on success, -1 on failure.
215  */
216 int
217 pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
218 {
219  int status = 0;
220 
221  if (ctx == NULL)
222  return -1;
223 
224  status = HMAC_Update(ctx->hmacctx, data, len);
225 
226  /* OpenSSL internals return 1 on success, 0 on failure */
227  if (status <= 0)
228  {
229  ctx->errreason = SSLerrmessage(ERR_get_error());
231  return -1;
232  }
233  return 0;
234 }
235 
236 /*
237  * pg_hmac_final
238  *
239  * Finalize a HMAC context. Returns 0 on success, -1 on failure.
240  */
241 int
243 {
244  int status = 0;
245  uint32 outlen;
246 
247  if (ctx == NULL)
248  return -1;
249 
250  switch (ctx->type)
251  {
252  case PG_MD5:
253  if (len < MD5_DIGEST_LENGTH)
254  {
256  return -1;
257  }
258  break;
259  case PG_SHA1:
260  if (len < SHA1_DIGEST_LENGTH)
261  {
263  return -1;
264  }
265  break;
266  case PG_SHA224:
268  {
270  return -1;
271  }
272  break;
273  case PG_SHA256:
275  {
277  return -1;
278  }
279  break;
280  case PG_SHA384:
282  {
284  return -1;
285  }
286  break;
287  case PG_SHA512:
289  {
291  return -1;
292  }
293  break;
294  }
295 
296  status = HMAC_Final(ctx->hmacctx, dest, &outlen);
297 
298  /* OpenSSL internals return 1 on success, 0 on failure */
299  if (status <= 0)
300  {
301  ctx->errreason = SSLerrmessage(ERR_get_error());
303  return -1;
304  }
305  return 0;
306 }
307 
308 /*
309  * pg_hmac_free
310  *
311  * Free a HMAC context.
312  */
313 void
315 {
316  if (ctx == NULL)
317  return;
318 
319  HMAC_CTX_free(ctx->hmacctx);
320 #ifdef USE_RESOWNER_FOR_HMAC
321  if (ctx->resowner)
323 #endif
324 
325  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
326  FREE(ctx);
327 }
328 
329 /*
330  * pg_hmac_error
331  *
332  * Returns a static string providing details about an error that happened
333  * during a HMAC computation.
334  */
335 const char *
337 {
338  if (ctx == NULL)
339  return _("out of memory");
340 
341  /*
342  * If a reason is provided, rely on it, else fallback to any error code
343  * set.
344  */
345  if (ctx->errreason)
346  return ctx->errreason;
347 
348  switch (ctx->error)
349  {
350  case PG_HMAC_ERROR_NONE:
351  return _("success");
353  return _("destination buffer too small");
355  return _("OpenSSL failure");
356  }
357 
358  Assert(false); /* cannot be reached */
359  return _("success");
360 }
361 
362 /* ResourceOwner callbacks */
363 
364 #ifdef USE_RESOWNER_FOR_HMAC
365 static void
367 {
369 
370  ctx->resowner = NULL;
371  pg_hmac_free(ctx);
372 }
373 #endif
unsigned int uint32
Definition: c.h:509
#define Assert(condition)
Definition: c.h:861
unsigned char uint8
Definition: c.h:507
pg_cryptohash_type
Definition: cryptohash.h:20
@ PG_SHA512
Definition: cryptohash.h:26
@ PG_SHA224
Definition: cryptohash.h:23
@ PG_SHA384
Definition: cryptohash.h:25
@ PG_SHA1
Definition: cryptohash.h:22
@ PG_SHA256
Definition: cryptohash.h:24
@ PG_MD5
Definition: cryptohash.h:21
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
pg_hmac_errno
Definition: hmac.c:43
static void ResOwnerReleaseHMAC(Datum res)
Definition: hmac_openssl.c:366
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac_openssl.c:117
#define FREE(ptr)
Definition: hmac_openssl.c:44
const char * pg_hmac_error(pg_hmac_ctx *ctx)
Definition: hmac_openssl.c:336
static const ResourceOwnerDesc hmac_resowner_desc
Definition: hmac_openssl.c:75
static void ResourceOwnerForgetHMAC(ResourceOwner owner, pg_hmac_ctx *ctx)
Definition: hmac_openssl.c:91
static const char * SSLerrmessage(unsigned long ecode)
Definition: hmac_openssl.c:98
static void ResourceOwnerRememberHMAC(ResourceOwner owner, pg_hmac_ctx *ctx)
Definition: hmac_openssl.c:86
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac_openssl.c:314
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac_openssl.c:217
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac_openssl.c:171
#define ALLOC(size)
Definition: hmac_openssl.c:43
pg_hmac_errno
Definition: hmac_openssl.c:52
@ PG_HMAC_ERROR_OPENSSL
Definition: hmac_openssl.c:55
@ PG_HMAC_ERROR_DEST_LEN
Definition: hmac_openssl.c:54
@ PG_HMAC_ERROR_NONE
Definition: hmac_openssl.c:53
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac_openssl.c:242
#define MD5_DIGEST_LENGTH
Definition: md5.h:20
const void size_t len
const void * data
void explicit_bzero(void *buf, size_t len)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
#define RELEASE_PRIO_HMAC_CONTEXTS
Definition: resowner.h:68
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:17
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
#define PG_SHA384_DIGEST_LENGTH
Definition: sha2.h:26
#define PG_SHA512_DIGEST_LENGTH
Definition: sha2.h:29
#define PG_SHA224_DIGEST_LENGTH
Definition: sha2.h:20
const char * name
Definition: resowner.h:93
const char * errreason
Definition: hmac.c:55
ResourceOwner resowner
Definition: hmac_openssl.c:67
HMAC_CTX * hmacctx
Definition: hmac_openssl.c:61
pg_cryptohash_type type
Definition: hmac.c:53
pg_hmac_errno error
Definition: hmac.c:54
const char * type