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-2021, 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 #include <openssl/hmac.h>
24 
25 #include "common/hmac.h"
26 #include "common/md5.h"
27 #include "common/sha1.h"
28 #include "common/sha2.h"
29 #ifndef FRONTEND
30 #include "utils/memutils.h"
31 #include "utils/resowner.h"
32 #include "utils/resowner_private.h"
33 #endif
34 
35 /*
36  * In backend, use an allocation in TopMemoryContext to count for resowner
37  * cleanup handling if necessary. For versions of OpenSSL where HMAC_CTX is
38  * known, just use palloc(). In frontend, use malloc to be able to return
39  * a failure status back to the caller.
40  */
41 #ifndef FRONTEND
42 #ifdef HAVE_HMAC_CTX_NEW
43 #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
44 #else
45 #define ALLOC(size) palloc(size)
46 #endif
47 #define FREE(ptr) pfree(ptr)
48 #else /* FRONTEND */
49 #define ALLOC(size) malloc(size)
50 #define FREE(ptr) free(ptr)
51 #endif /* FRONTEND */
52 
53 /*
54  * Internal structure for pg_hmac_ctx->data with this implementation.
55  */
56 struct pg_hmac_ctx
57 {
58  HMAC_CTX *hmacctx;
60 
61 #ifndef FRONTEND
63 #endif
64 };
65 
66 /*
67  * pg_hmac_create
68  *
69  * Allocate a hash context. Returns NULL on failure for an OOM. The
70  * backend issues an error, without returning.
71  */
74 {
75  pg_hmac_ctx *ctx;
76 
77  ctx = ALLOC(sizeof(pg_hmac_ctx));
78  if (ctx == NULL)
79  return NULL;
80  memset(ctx, 0, sizeof(pg_hmac_ctx));
81 
82  ctx->type = type;
83 
84  /*
85  * Initialization takes care of assigning the correct type for OpenSSL.
86  */
87 #ifdef HAVE_HMAC_CTX_NEW
88 #ifndef FRONTEND
90 #endif
91  ctx->hmacctx = HMAC_CTX_new();
92 #else
93  ctx->hmacctx = ALLOC(sizeof(HMAC_CTX));
94 #endif
95 
96  if (ctx->hmacctx == NULL)
97  {
98  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
99  FREE(ctx);
100 #ifndef FRONTEND
101  ereport(ERROR,
102  (errcode(ERRCODE_OUT_OF_MEMORY),
103  errmsg("out of memory")));
104 #endif
105  return NULL;
106  }
107 
108 #ifdef HAVE_HMAC_CTX_NEW
109 #ifndef FRONTEND
112 #endif
113 #else
114  memset(ctx->hmacctx, 0, sizeof(HMAC_CTX));
115 #endif /* HAVE_HMAC_CTX_NEW */
116 
117  return ctx;
118 }
119 
120 /*
121  * pg_hmac_init
122  *
123  * Initialize a HMAC context. Returns 0 on success, -1 on failure.
124  */
125 int
126 pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
127 {
128  int status = 0;
129 
130  if (ctx == NULL)
131  return -1;
132 
133  switch (ctx->type)
134  {
135  case PG_MD5:
136  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_md5(), NULL);
137  break;
138  case PG_SHA1:
139  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha1(), NULL);
140  break;
141  case PG_SHA224:
142  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha224(), NULL);
143  break;
144  case PG_SHA256:
145  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha256(), NULL);
146  break;
147  case PG_SHA384:
148  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha384(), NULL);
149  break;
150  case PG_SHA512:
151  status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha512(), NULL);
152  break;
153  }
154 
155  /* OpenSSL internals return 1 on success, 0 on failure */
156  if (status <= 0)
157  return -1;
158 
159  return 0;
160 }
161 
162 /*
163  * pg_hmac_update
164  *
165  * Update a HMAC context. Returns 0 on success, -1 on failure.
166  */
167 int
168 pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
169 {
170  int status = 0;
171 
172  if (ctx == NULL)
173  return -1;
174 
175  status = HMAC_Update(ctx->hmacctx, data, len);
176 
177  /* OpenSSL internals return 1 on success, 0 on failure */
178  if (status <= 0)
179  return -1;
180  return 0;
181 }
182 
183 /*
184  * pg_hmac_final
185  *
186  * Finalize a HMAC context. Returns 0 on success, -1 on failure.
187  */
188 int
189 pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
190 {
191  int status = 0;
192  uint32 outlen;
193 
194  if (ctx == NULL)
195  return -1;
196 
197  switch (ctx->type)
198  {
199  case PG_MD5:
200  if (len < MD5_DIGEST_LENGTH)
201  return -1;
202  break;
203  case PG_SHA1:
204  if (len < SHA1_DIGEST_LENGTH)
205  return -1;
206  break;
207  case PG_SHA224:
208  if (len < PG_SHA224_DIGEST_LENGTH)
209  return -1;
210  break;
211  case PG_SHA256:
212  if (len < PG_SHA256_DIGEST_LENGTH)
213  return -1;
214  break;
215  case PG_SHA384:
216  if (len < PG_SHA384_DIGEST_LENGTH)
217  return -1;
218  break;
219  case PG_SHA512:
220  if (len < PG_SHA512_DIGEST_LENGTH)
221  return -1;
222  break;
223  }
224 
225  status = HMAC_Final(ctx->hmacctx, dest, &outlen);
226 
227  /* OpenSSL internals return 1 on success, 0 on failure */
228  if (status <= 0)
229  return -1;
230  return 0;
231 }
232 
233 /*
234  * pg_hmac_free
235  *
236  * Free a HMAC context.
237  */
238 void
240 {
241  if (ctx == NULL)
242  return;
243 
244 #ifdef HAVE_HMAC_CTX_FREE
245  HMAC_CTX_free(ctx->hmacctx);
246 #ifndef FRONTEND
248 #endif
249 #else
250  explicit_bzero(ctx->hmacctx, sizeof(HMAC_CTX));
251  FREE(ctx->hmacctx);
252 #endif
253 
254  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
255  FREE(ctx);
256 }
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac_openssl.c:73
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac_openssl.c:189
#define PointerGetDatum(X)
Definition: postgres.h:600
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:17
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:22
unsigned char uint8
Definition: c.h:439
int errcode(int sqlerrcode)
Definition: elog.c:698
#define FREE(ptr)
Definition: hmac_openssl.c:47
#define PG_SHA512_DIGEST_LENGTH
Definition: sha2.h:26
void ResourceOwnerEnlargeHMAC(ResourceOwner owner)
Definition: resowner.c:1456
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac_openssl.c:126
#define ERROR
Definition: elog.h:46
#define MD5_DIGEST_LENGTH
Definition: md5.h:20
#define ALLOC(size)
Definition: hmac_openssl.c:45
unsigned int uint32
Definition: c.h:441
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac_openssl.c:168
HMAC_CTX * hmacctx
Definition: hmac_openssl.c:58
#define ereport(elevel,...)
Definition: elog.h:157
void ResourceOwnerRememberHMAC(ResourceOwner owner, Datum handle)
Definition: resowner.c:1467
pg_cryptohash_type type
Definition: hmac.c:47
int errmsg(const char *fmt,...)
Definition: elog.c:909
pg_cryptohash_type
Definition: cryptohash.h:19
void explicit_bzero(void *buf, size_t len)
void ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
Definition: resowner.c:1476
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac_openssl.c:239
#define PG_SHA224_DIGEST_LENGTH
Definition: sha2.h:20
#define PG_SHA384_DIGEST_LENGTH
Definition: sha2.h:24
ResourceOwner resowner
Definition: hmac_openssl.c:62