Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9bbbf02

Browse files
committed
Fix pgcrypto compilation with OpenSSL 1.1.0.
Was broken by the switch to using OpenSSL's EVP interface for ciphers, in commit 5ff4a67. Reported by Andres Freund. Fix by Michael Paquier with some kibitzing by me. Discussion: https://www.postgresql.org/message-id/20161201014826.ic72tfkahmevpwz7@alap3.anarazel.de
1 parent 41493ba commit 9bbbf02

File tree

2 files changed

+141
-49
lines changed

2 files changed

+141
-49
lines changed

contrib/pgcrypto/openssl.c

Lines changed: 139 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ typedef struct OSSLDigest
6666
} OSSLDigest;
6767

6868
static OSSLDigest *open_digests = NULL;
69-
static bool resowner_callback_registered = false;
69+
static bool digest_resowner_callback_registered = false;
7070

7171
static void
72-
free_openssldigest(OSSLDigest *digest)
72+
free_openssl_digest(OSSLDigest *digest)
7373
{
7474
EVP_MD_CTX_destroy(digest->ctx);
7575
if (digest->prev)
@@ -106,7 +106,7 @@ digest_free_callback(ResourceReleasePhase phase,
106106
{
107107
if (isCommit)
108108
elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr);
109-
free_openssldigest(curr);
109+
free_openssl_digest(curr);
110110
}
111111
}
112112
}
@@ -156,7 +156,7 @@ digest_free(PX_MD *h)
156156
{
157157
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
158158

159-
free_openssldigest(digest);
159+
free_openssl_digest(digest);
160160
px_free(h);
161161
}
162162

@@ -178,10 +178,10 @@ px_find_digest(const char *name, PX_MD **res)
178178
OpenSSL_add_all_algorithms();
179179
}
180180

181-
if (!resowner_callback_registered)
181+
if (!digest_resowner_callback_registered)
182182
{
183183
RegisterResourceReleaseCallback(digest_free_callback, NULL);
184-
resowner_callback_registered = true;
184+
digest_resowner_callback_registered = true;
185185
}
186186

187187
md = EVP_get_digestbyname(name);
@@ -240,6 +240,9 @@ px_find_digest(const char *name, PX_MD **res)
240240
*/
241241
typedef const EVP_CIPHER *(*ossl_EVP_cipher_func)(void);
242242

243+
/*
244+
* ossl_cipher contains the static information about each cipher.
245+
*/
243246
struct ossl_cipher
244247
{
245248
int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv);
@@ -248,31 +251,89 @@ struct ossl_cipher
248251
int max_key_size;
249252
};
250253

251-
typedef struct
254+
/*
255+
* OSSLCipher contains the state for using a cipher. A separate OSSLCipher
256+
* object is allocated in each px_find_cipher() call.
257+
*
258+
* To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher
259+
* objects in a linked list, allocated in TopMemoryContext. We use the
260+
* ResourceOwner mechanism to free them on abort.
261+
*/
262+
typedef struct OSSLCipher
252263
{
253-
EVP_CIPHER_CTX evp_ctx;
264+
EVP_CIPHER_CTX *evp_ctx;
254265
const EVP_CIPHER *evp_ciph;
255266
uint8 key[MAX_KEY];
256267
uint8 iv[MAX_IV];
257268
unsigned klen;
258269
unsigned init;
259270
const struct ossl_cipher *ciph;
260-
} ossldata;
271+
272+
ResourceOwner owner;
273+
struct OSSLCipher *next;
274+
struct OSSLCipher *prev;
275+
} OSSLCipher;
276+
277+
static OSSLCipher *open_ciphers = NULL;
278+
static bool cipher_resowner_callback_registered = false;
279+
280+
static void
281+
free_openssl_cipher(OSSLCipher *od)
282+
{
283+
EVP_CIPHER_CTX_free(od->evp_ctx);
284+
if (od->prev)
285+
od->prev->next = od->next;
286+
else
287+
open_ciphers = od->next;
288+
if (od->next)
289+
od->next->prev = od->prev;
290+
pfree(od);
291+
}
292+
293+
/*
294+
* Close any open OpenSSL cipher handles on abort.
295+
*/
296+
static void
297+
cipher_free_callback(ResourceReleasePhase phase,
298+
bool isCommit,
299+
bool isTopLevel,
300+
void *arg)
301+
{
302+
OSSLCipher *curr;
303+
OSSLCipher *next;
304+
305+
if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
306+
return;
307+
308+
next = open_ciphers;
309+
while (next)
310+
{
311+
curr = next;
312+
next = curr->next;
313+
314+
if (curr->owner == CurrentResourceOwner)
315+
{
316+
if (isCommit)
317+
elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr);
318+
free_openssl_cipher(curr);
319+
}
320+
}
321+
}
261322

262323
/* Common routines for all algorithms */
263324

264325
static unsigned
265326
gen_ossl_block_size(PX_Cipher *c)
266327
{
267-
ossldata *od = (ossldata *) c->ptr;
328+
OSSLCipher *od = (OSSLCipher *) c->ptr;
268329

269330
return od->ciph->block_size;
270331
}
271332

272333
static unsigned
273334
gen_ossl_key_size(PX_Cipher *c)
274335
{
275-
ossldata *od = (ossldata *) c->ptr;
336+
OSSLCipher *od = (OSSLCipher *) c->ptr;
276337

277338
return od->ciph->max_key_size;
278339
}
@@ -281,7 +342,7 @@ static unsigned
281342
gen_ossl_iv_size(PX_Cipher *c)
282343
{
283344
unsigned ivlen;
284-
ossldata *od = (ossldata *) c->ptr;
345+
OSSLCipher *od = (OSSLCipher *) c->ptr;
285346

286347
ivlen = od->ciph->block_size;
287348
return ivlen;
@@ -290,34 +351,31 @@ gen_ossl_iv_size(PX_Cipher *c)
290351
static void
291352
gen_ossl_free(PX_Cipher *c)
292353
{
293-
ossldata *od = (ossldata *) c->ptr;
354+
OSSLCipher *od = (OSSLCipher *) c->ptr;
294355

295-
EVP_CIPHER_CTX_cleanup(&od->evp_ctx);
296-
px_memset(od, 0, sizeof(*od));
297-
px_free(od);
356+
free_openssl_cipher(od);
298357
px_free(c);
299358
}
300359

301360
static int
302361
gen_ossl_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen,
303362
uint8 *res)
304363
{
305-
ossldata *od = c->ptr;
364+
OSSLCipher *od = c->ptr;
306365
int outlen;
307366

308367
if (!od->init)
309368
{
310-
EVP_CIPHER_CTX_init(&od->evp_ctx);
311-
if (!EVP_DecryptInit_ex(&od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
369+
if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
312370
return PXE_CIPHER_INIT;
313-
if (!EVP_CIPHER_CTX_set_key_length(&od->evp_ctx, od->klen))
371+
if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
314372
return PXE_CIPHER_INIT;
315-
if (!EVP_DecryptInit_ex(&od->evp_ctx, NULL, NULL, od->key, od->iv))
373+
if (!EVP_DecryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv))
316374
return PXE_CIPHER_INIT;
317375
od->init = true;
318376
}
319377

320-
if (!EVP_DecryptUpdate(&od->evp_ctx, res, &outlen, data, dlen))
378+
if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
321379
return PXE_DECRYPT_FAILED;
322380

323381
return 0;
@@ -327,22 +385,21 @@ static int
327385
gen_ossl_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen,
328386
uint8 *res)
329387
{
330-
ossldata *od = c->ptr;
388+
OSSLCipher *od = c->ptr;
331389
int outlen;
332390

333391
if (!od->init)
334392
{
335-
EVP_CIPHER_CTX_init(&od->evp_ctx);
336-
if (!EVP_EncryptInit_ex(&od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
393+
if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
337394
return PXE_CIPHER_INIT;
338-
if (!EVP_CIPHER_CTX_set_key_length(&od->evp_ctx, od->klen))
395+
if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
339396
return PXE_CIPHER_INIT;
340-
if (!EVP_EncryptInit_ex(&od->evp_ctx, NULL, NULL, od->key, od->iv))
397+
if (!EVP_EncryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv))
341398
return PXE_CIPHER_INIT;
342399
od->init = true;
343400
}
344401

345-
if (!EVP_EncryptUpdate(&od->evp_ctx, res, &outlen, data, dlen))
402+
if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
346403
return PXE_ERR_GENERIC;
347404

348405
return 0;
@@ -370,31 +427,38 @@ bf_check_supported_key_len(void)
370427
static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
371428
static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53};
372429
uint8 out[8];
373-
EVP_CIPHER_CTX evp_ctx;
430+
EVP_CIPHER_CTX *evp_ctx;
374431
int outlen;
432+
int status = 0;
375433

376434
/* encrypt with 448bits key and verify output */
377-
EVP_CIPHER_CTX_init(&evp_ctx);
378-
if (!EVP_EncryptInit_ex(&evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL))
379-
return 0;
380-
if (!EVP_CIPHER_CTX_set_key_length(&evp_ctx, 56))
381-
return 0;
382-
if (!EVP_EncryptInit_ex(&evp_ctx, NULL, NULL, key, NULL))
435+
evp_ctx = EVP_CIPHER_CTX_new();
436+
if (!evp_ctx)
383437
return 0;
438+
if (!EVP_EncryptInit_ex(evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL))
439+
goto leave;
440+
if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, 56))
441+
goto leave;
442+
if (!EVP_EncryptInit_ex(evp_ctx, NULL, NULL, key, NULL))
443+
goto leave;
384444

385-
if (!EVP_EncryptUpdate(&evp_ctx, out, &outlen, data, 8))
386-
return 0;
445+
if (!EVP_EncryptUpdate(evp_ctx, out, &outlen, data, 8))
446+
goto leave;
387447

388448
if (memcmp(out, res, 8) != 0)
389-
return 0; /* Output does not match -> strong cipher is
449+
goto leave; /* Output does not match -> strong cipher is
390450
* not supported */
391-
return 1;
451+
status = 1;
452+
453+
leave:
454+
EVP_CIPHER_CTX_free(evp_ctx);
455+
return status;
392456
}
393457

394458
static int
395459
bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
396460
{
397-
ossldata *od = c->ptr;
461+
OSSLCipher *od = c->ptr;
398462
unsigned bs = gen_ossl_block_size(c);
399463
static int bf_is_strong = -1;
400464

@@ -426,7 +490,7 @@ bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
426490
static int
427491
ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
428492
{
429-
ossldata *od = c->ptr;
493+
OSSLCipher *od = c->ptr;
430494
unsigned bs = gen_ossl_block_size(c);
431495

432496
od->klen = 8;
@@ -445,7 +509,7 @@ ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
445509
static int
446510
ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
447511
{
448-
ossldata *od = c->ptr;
512+
OSSLCipher *od = c->ptr;
449513
unsigned bs = gen_ossl_block_size(c);
450514

451515
od->klen = 24;
@@ -464,7 +528,7 @@ ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
464528
static int
465529
ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
466530
{
467-
ossldata *od = c->ptr;
531+
OSSLCipher *od = c->ptr;
468532
unsigned bs = gen_ossl_block_size(c);
469533

470534
od->klen = klen;
@@ -482,7 +546,7 @@ ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
482546
static int
483547
ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
484548
{
485-
ossldata *od = c->ptr;
549+
OSSLCipher *od = c->ptr;
486550
unsigned bs = gen_ossl_block_size(c);
487551

488552
if (klen <= 128 / 8)
@@ -507,7 +571,7 @@ ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
507571
static int
508572
ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
509573
{
510-
ossldata *od = c->ptr;
574+
OSSLCipher *od = c->ptr;
511575
int err;
512576

513577
err = ossl_aes_init(c, key, klen, iv);
@@ -537,7 +601,7 @@ ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv
537601
static int
538602
ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
539603
{
540-
ossldata *od = c->ptr;
604+
OSSLCipher *od = c->ptr;
541605
int err;
542606

543607
err = ossl_aes_init(c, key, klen, iv);
@@ -683,7 +747,8 @@ px_find_cipher(const char *name, PX_Cipher **res)
683747
{
684748
const struct ossl_cipher_lookup *i;
685749
PX_Cipher *c = NULL;
686-
ossldata *od;
750+
EVP_CIPHER_CTX *ctx;
751+
OSSLCipher *od;
687752

688753
name = px_resolve_alias(ossl_aliases, name);
689754
for (i = ossl_cipher_types; i->name; i++)
@@ -692,13 +757,38 @@ px_find_cipher(const char *name, PX_Cipher **res)
692757
if (i->name == NULL)
693758
return PXE_NO_CIPHER;
694759

695-
od = px_alloc(sizeof(*od));
696-
memset(od, 0, sizeof(*od));
760+
if (!cipher_resowner_callback_registered)
761+
{
762+
RegisterResourceReleaseCallback(cipher_free_callback, NULL);
763+
cipher_resowner_callback_registered = true;
764+
}
765+
766+
/*
767+
* Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
768+
* The order is crucial, to make sure we don't leak anything on
769+
* out-of-memory or other error.
770+
*/
771+
od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od));
697772
od->ciph = i->ciph;
698773

774+
/* Allocate an EVP_CIPHER_CTX object. */
775+
ctx = EVP_CIPHER_CTX_new();
776+
if (!ctx)
777+
{
778+
pfree(od);
779+
return PXE_CIPHER_INIT;
780+
}
781+
782+
od->evp_ctx = ctx;
783+
od->owner = CurrentResourceOwner;
784+
od->next = open_ciphers;
785+
od->prev = NULL;
786+
open_ciphers = od;
787+
699788
if (i->ciph->cipher_func)
700789
od->evp_ciph = i->ciph->cipher_func();
701790

791+
/* The PX_Cipher is allocated in current memory context */
702792
c = px_alloc(sizeof(*c));
703793
c->block_size = gen_ossl_block_size;
704794
c->key_size = gen_ossl_key_size;

contrib/pgcrypto/pgp-encrypt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ encrypt_free(void *priv)
219219
{
220220
struct EncStat *st = priv;
221221

222+
if (st->ciph)
223+
pgp_cfb_free(st->ciph);
222224
px_memset(st, 0, sizeof(*st));
223225
px_free(st);
224226
}

0 commit comments

Comments
 (0)