@@ -66,10 +66,10 @@ typedef struct OSSLDigest
6666} OSSLDigest ;
6767
6868static OSSLDigest * open_digests = NULL ;
69- static bool resowner_callback_registered = false;
69+ static bool digest_resowner_callback_registered = false;
7070
7171static 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 */
241241typedef const EVP_CIPHER * (* ossl_EVP_cipher_func )(void );
242242
243+ /*
244+ * ossl_cipher contains the static information about each cipher.
245+ */
243246struct 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
264325static unsigned
265326gen_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
272333static unsigned
273334gen_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
281342gen_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)
290351static void
291352gen_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
301360static int
302361gen_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
327385gen_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
394458static int
395459bf_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)
426490static int
427491ossl_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)
445509static int
446510ossl_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)
464528static int
465529ossl_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)
482546static int
483547ossl_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)
507571static int
508572ossl_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
537601static int
538602ossl_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 ;
0 commit comments