PostgreSQL Source Code  git master
cryptohash_openssl.c
Go to the documentation of this file.
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-2021, 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/evp.h>
25 
26 #include "common/cryptohash.h"
27 #include "common/md5.h"
28 #include "common/sha1.h"
29 #include "common/sha2.h"
30 #ifndef FRONTEND
31 #include "utils/memutils.h"
32 #include "utils/resowner.h"
33 #include "utils/resowner_private.h"
34 #endif
35 
36 /*
37  * In the backend, use an allocation in TopMemoryContext to count for
38  * resowner cleanup handling. In the frontend, use malloc to be able
39  * to return a failure status back to the caller.
40  */
41 #ifndef FRONTEND
42 #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
43 #define FREE(ptr) pfree(ptr)
44 #else
45 #define ALLOC(size) malloc(size)
46 #define FREE(ptr) free(ptr)
47 #endif
48 
49 /*
50  * Internal pg_cryptohash_ctx structure.
51  *
52  * This tracks the resource owner associated to each EVP context data
53  * for the backend.
54  */
55 struct pg_cryptohash_ctx
56 {
58 
59  EVP_MD_CTX *evpctx;
60 
61 #ifndef FRONTEND
63 #endif
64 };
65 
66 /*
67  * pg_cryptohash_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_cryptohash_ctx *ctx;
76 
77  /*
78  * Make sure that the resource owner has space to remember this reference.
79  * This can error out with "out of memory", so do this before any other
80  * allocation to avoid leaking.
81  */
82 #ifndef FRONTEND
84 #endif
85 
86  ctx = ALLOC(sizeof(pg_cryptohash_ctx));
87  if (ctx == NULL)
88  return NULL;
89  memset(ctx, 0, sizeof(pg_cryptohash_ctx));
90  ctx->type = type;
91 
92  /*
93  * Initialization takes care of assigning the correct type for OpenSSL.
94  */
95  ctx->evpctx = EVP_MD_CTX_create();
96 
97  if (ctx->evpctx == NULL)
98  {
99  explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
100  FREE(ctx);
101 #ifndef FRONTEND
102  ereport(ERROR,
103  (errcode(ERRCODE_OUT_OF_MEMORY),
104  errmsg("out of memory")));
105 #else
106  return NULL;
107 #endif
108  }
109 
110 #ifndef FRONTEND
113  PointerGetDatum(ctx));
114 #endif
115 
116  return ctx;
117 }
118 
119 /*
120  * pg_cryptohash_init
121  *
122  * Initialize a hash context. Returns 0 on success, and -1 on failure.
123  */
124 int
126 {
127  int status = 0;
128 
129  if (ctx == NULL)
130  return -1;
131 
132  switch (ctx->type)
133  {
134  case PG_MD5:
135  status = EVP_DigestInit_ex(ctx->evpctx, EVP_md5(), NULL);
136  break;
137  case PG_SHA1:
138  status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha1(), NULL);
139  break;
140  case PG_SHA224:
141  status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha224(), NULL);
142  break;
143  case PG_SHA256:
144  status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha256(), NULL);
145  break;
146  case PG_SHA384:
147  status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha384(), NULL);
148  break;
149  case PG_SHA512:
150  status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha512(), NULL);
151  break;
152  }
153 
154  /* OpenSSL internals return 1 on success, 0 on failure */
155  if (status <= 0)
156  return -1;
157  return 0;
158 }
159 
160 /*
161  * pg_cryptohash_update
162  *
163  * Update a hash context. Returns 0 on success, and -1 on failure.
164  */
165 int
167 {
168  int status = 0;
169 
170  if (ctx == NULL)
171  return -1;
172 
173  status = EVP_DigestUpdate(ctx->evpctx, data, len);
174 
175  /* OpenSSL internals return 1 on success, 0 on failure */
176  if (status <= 0)
177  return -1;
178  return 0;
179 }
180 
181 /*
182  * pg_cryptohash_final
183  *
184  * Finalize a hash context. Returns 0 on success, and -1 on failure.
185  */
186 int
188 {
189  int status = 0;
190 
191  if (ctx == NULL)
192  return -1;
193 
194  switch (ctx->type)
195  {
196  case PG_MD5:
197  if (len < MD5_DIGEST_LENGTH)
198  return -1;
199  break;
200  case PG_SHA1:
201  if (len < SHA1_DIGEST_LENGTH)
202  return -1;
203  break;
204  case PG_SHA224:
205  if (len < PG_SHA224_DIGEST_LENGTH)
206  return -1;
207  break;
208  case PG_SHA256:
209  if (len < PG_SHA256_DIGEST_LENGTH)
210  return -1;
211  break;
212  case PG_SHA384:
213  if (len < PG_SHA384_DIGEST_LENGTH)
214  return -1;
215  break;
216  case PG_SHA512:
217  if (len < PG_SHA512_DIGEST_LENGTH)
218  return -1;
219  break;
220  }
221 
222  status = EVP_DigestFinal_ex(ctx->evpctx, dest, 0);
223 
224  /* OpenSSL internals return 1 on success, 0 on failure */
225  if (status <= 0)
226  return -1;
227  return 0;
228 }
229 
230 /*
231  * pg_cryptohash_free
232  *
233  * Free a hash context.
234  */
235 void
237 {
238  if (ctx == NULL)
239  return;
240 
241  EVP_MD_CTX_destroy(ctx->evpctx);
242 
243 #ifndef FRONTEND
245  PointerGetDatum(ctx));
246 #endif
247 
248  explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
249  FREE(ctx);
250 }
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
#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 PG_SHA512_DIGEST_LENGTH
Definition: sha2.h:26
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
union pg_cryptohash_ctx::@35 data
pg_cryptohash_type type
Definition: cryptohash.c:46
#define ERROR
Definition: elog.h:46
#define MD5_DIGEST_LENGTH
Definition: md5.h:20
void ResourceOwnerRememberCryptoHash(ResourceOwner owner, Datum handle)
Definition: resowner.c:1422
void ResourceOwnerEnlargeCryptoHash(ResourceOwner owner)
Definition: resowner.c:1411
ResourceOwner resowner
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
#define ereport(elevel,...)
Definition: elog.h:157
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
void ResourceOwnerForgetCryptoHash(ResourceOwner owner, Datum handle)
Definition: resowner.c:1431
#define ALLOC(size)
int errmsg(const char *fmt,...)
Definition: elog.c:909
pg_cryptohash_type
Definition: cryptohash.h:19
void explicit_bzero(void *buf, size_t len)
#define FREE(ptr)
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define PG_SHA224_DIGEST_LENGTH
Definition: sha2.h:20
#define PG_SHA384_DIGEST_LENGTH
Definition: sha2.h:24