Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * openssl.c
3 : : * Wrapper for OpenSSL library.
4 : : *
5 : : * Copyright (c) 2001 Marko Kreen
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : : * SUCH DAMAGE.
28 : : *
29 : : * contrib/pgcrypto/openssl.c
30 : : */
31 : :
32 : : #include "postgres.h"
33 : :
34 : : #include <openssl/crypto.h>
35 : : #include <openssl/evp.h>
36 : : #include <openssl/err.h>
37 : : #include <openssl/rand.h>
38 : :
39 : : #include "px.h"
40 : : #include "utils/memutils.h"
41 : : #include "utils/resowner.h"
42 : :
43 : : /*
44 : : * Max lengths we might want to handle.
45 : : */
46 : : #define MAX_KEY (512/8)
47 : : #define MAX_IV (128/8)
48 : :
49 : : /*
50 : : * Hashes
51 : : */
52 : :
53 : : /*
54 : : * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
55 : : * mechanism to free them on abort.
56 : : */
57 : : typedef struct OSSLDigest
58 : : {
59 : : const EVP_MD *algo;
60 : : EVP_MD_CTX *ctx;
61 : :
62 : : ResourceOwner owner;
63 : : } OSSLDigest;
64 : :
65 : : /* ResourceOwner callbacks to hold OpenSSL digest handles */
66 : : static void ResOwnerReleaseOSSLDigest(Datum res);
67 : :
68 : : static const ResourceOwnerDesc ossldigest_resowner_desc =
69 : : {
70 : : .name = "pgcrypto OpenSSL digest handle",
71 : : .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
72 : : .release_priority = RELEASE_PRIO_FIRST,
73 : : .ReleaseResource = ResOwnerReleaseOSSLDigest,
74 : : .DebugPrint = NULL, /* default message is fine */
75 : : };
76 : :
77 : : /* Convenience wrappers over ResourceOwnerRemember/Forget */
78 : : static inline void
668 heikki.linnakangas@i 79 :CBC 350 : ResourceOwnerRememberOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
80 : : {
81 : 350 : ResourceOwnerRemember(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
82 : 350 : }
83 : : static inline void
84 : 350 : ResourceOwnerForgetOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
85 : : {
86 : 350 : ResourceOwnerForget(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
3278 87 : 350 : }
88 : :
89 : : static void
668 90 : 350 : free_openssl_digest(OSSLDigest *digest)
91 : : {
92 : 350 : EVP_MD_CTX_destroy(digest->ctx);
93 [ + - ]: 350 : if (digest->owner != NULL)
94 : 350 : ResourceOwnerForgetOSSLDigest(digest->owner, digest);
95 : 350 : pfree(digest);
3278 96 : 350 : }
97 : :
98 : : static unsigned
5931 bruce@momjian.us 99 : 164 : digest_result_size(PX_MD *h)
100 : : {
6912 101 : 164 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
1733 michael@paquier.xyz 102 : 164 : int result = EVP_MD_CTX_size(digest->ctx);
103 : :
104 [ - + ]: 164 : if (result < 0)
1733 michael@paquier.xyz 105 [ # # ]:UBC 0 : elog(ERROR, "EVP_MD_CTX_size() failed");
106 : :
1733 michael@paquier.xyz 107 :CBC 164 : return result;
108 : : }
109 : :
110 : : static unsigned
5931 bruce@momjian.us 111 : 56 : digest_block_size(PX_MD *h)
112 : : {
6912 113 : 56 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
1733 michael@paquier.xyz 114 : 56 : int result = EVP_MD_CTX_block_size(digest->ctx);
115 : :
116 [ - + ]: 56 : if (result < 0)
1733 michael@paquier.xyz 117 [ # # ]:UBC 0 : elog(ERROR, "EVP_MD_CTX_block_size() failed");
118 : :
1733 michael@paquier.xyz 119 :CBC 56 : return result;
120 : : }
121 : :
122 : : static void
5931 bruce@momjian.us 123 : 531442 : digest_reset(PX_MD *h)
124 : : {
6912 125 : 531442 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
126 : :
1733 michael@paquier.xyz 127 [ - + ]: 531442 : if (!EVP_DigestInit_ex(digest->ctx, digest->algo, NULL))
1733 michael@paquier.xyz 128 [ # # ]:UBC 0 : elog(ERROR, "EVP_DigestInit_ex() failed");
9076 peter_e@gmx.net 129 :CBC 531442 : }
130 : :
131 : : static void
5931 bruce@momjian.us 132 : 27469497 : digest_update(PX_MD *h, const uint8 *data, unsigned dlen)
133 : : {
6912 134 : 27469497 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
135 : :
1733 michael@paquier.xyz 136 [ - + ]: 27469497 : if (!EVP_DigestUpdate(digest->ctx, data, dlen))
1733 michael@paquier.xyz 137 [ # # ]:UBC 0 : elog(ERROR, "EVP_DigestUpdate() failed");
8782 bruce@momjian.us 138 :CBC 27469497 : }
139 : :
140 : : static void
5931 141 : 531694 : digest_finish(PX_MD *h, uint8 *dst)
142 : : {
6912 143 : 531694 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
144 : :
1733 michael@paquier.xyz 145 [ - + ]: 531694 : if (!EVP_DigestFinal_ex(digest->ctx, dst, NULL))
1733 michael@paquier.xyz 146 [ # # ]:UBC 0 : elog(ERROR, "EVP_DigestFinal_ex() failed");
9076 peter_e@gmx.net 147 :CBC 531694 : }
148 : :
149 : : static void
5931 bruce@momjian.us 150 : 350 : digest_free(PX_MD *h)
151 : : {
6912 152 : 350 : OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
153 : :
3190 heikki.linnakangas@i 154 : 350 : free_openssl_digest(digest);
1807 michael@paquier.xyz 155 : 350 : pfree(h);
8782 bruce@momjian.us 156 : 350 : }
157 : :
158 : : /* PUBLIC functions */
159 : :
160 : : int
5931 161 : 352 : px_find_digest(const char *name, PX_MD **res)
162 : : {
163 : : const EVP_MD *md;
164 : : EVP_MD_CTX *ctx;
165 : : PX_MD *h;
166 : : OSSLDigest *digest;
167 : :
8331 168 : 352 : md = EVP_get_digestbyname(name);
169 [ + + ]: 352 : if (md == NULL)
3295 heikki.linnakangas@i 170 : 2 : return PXE_NO_HASH;
171 : :
668 172 : 350 : ResourceOwnerEnlarge(CurrentResourceOwner);
173 : :
174 : : /*
175 : : * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
176 : : * The order is crucial, to make sure we don't leak anything on
177 : : * out-of-memory or other error.
178 : : */
3278 179 : 350 : digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest));
180 : :
181 : 350 : ctx = EVP_MD_CTX_create();
182 [ - + ]: 350 : if (!ctx)
183 : : {
3278 heikki.linnakangas@i 184 :UBC 0 : pfree(digest);
1219 dgustafsson@postgres 185 : 0 : return PXE_CIPHER_INIT;
186 : : }
3278 heikki.linnakangas@i 187 [ - + ]:CBC 350 : if (EVP_DigestInit_ex(ctx, md, NULL) == 0)
188 : : {
1783 michael@paquier.xyz 189 :UBC 0 : EVP_MD_CTX_destroy(ctx);
3278 heikki.linnakangas@i 190 : 0 : pfree(digest);
1219 dgustafsson@postgres 191 : 0 : return PXE_CIPHER_INIT;
192 : : }
193 : :
3278 heikki.linnakangas@i 194 :CBC 350 : digest->algo = md;
195 : 350 : digest->ctx = ctx;
196 : 350 : digest->owner = CurrentResourceOwner;
668 197 : 350 : ResourceOwnerRememberOSSLDigest(digest->owner, digest);
198 : :
199 : : /* The PX_MD object is allocated in the current memory context. */
1807 michael@paquier.xyz 200 : 350 : h = palloc(sizeof(*h));
8331 bruce@momjian.us 201 : 350 : h->result_size = digest_result_size;
202 : 350 : h->block_size = digest_block_size;
203 : 350 : h->reset = digest_reset;
204 : 350 : h->update = digest_update;
205 : 350 : h->finish = digest_finish;
206 : 350 : h->free = digest_free;
282 peter@eisentraut.org 207 : 350 : h->p.ptr = digest;
208 : :
8331 bruce@momjian.us 209 : 350 : *res = h;
210 : 350 : return 0;
211 : : }
212 : :
213 : : /* ResourceOwner callbacks for OSSLDigest */
214 : :
215 : : static void
668 heikki.linnakangas@i 216 :UBC 0 : ResOwnerReleaseOSSLDigest(Datum res)
217 : : {
218 : 0 : OSSLDigest *digest = (OSSLDigest *) DatumGetPointer(res);
219 : :
220 : 0 : digest->owner = NULL;
221 : 0 : free_openssl_digest(digest);
222 : 0 : }
223 : :
224 : : /*
225 : : * Ciphers
226 : : *
227 : : * We use OpenSSL's EVP* family of functions for these.
228 : : */
229 : :
230 : : /*
231 : : * prototype for the EVP functions that return an algorithm, e.g.
232 : : * EVP_aes_128_cbc().
233 : : */
234 : : typedef const EVP_CIPHER *(*ossl_EVP_cipher_func) (void);
235 : :
236 : : /*
237 : : * ossl_cipher contains the static information about each cipher.
238 : : */
239 : : struct ossl_cipher
240 : : {
241 : : int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv);
242 : : ossl_EVP_cipher_func cipher_func;
243 : : int block_size;
244 : : int max_key_size;
245 : : };
246 : :
247 : : /*
248 : : * OSSLCipher contains the state for using a cipher. A separate OSSLCipher
249 : : * object is allocated in each px_find_cipher() call.
250 : : *
251 : : * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
252 : : * mechanism to free them on abort.
253 : : */
254 : : typedef struct OSSLCipher
255 : : {
256 : : EVP_CIPHER_CTX *evp_ctx;
257 : : const EVP_CIPHER *evp_ciph;
258 : : uint8 key[MAX_KEY];
259 : : uint8 iv[MAX_IV];
260 : : unsigned klen;
261 : : unsigned init;
262 : : const struct ossl_cipher *ciph;
263 : :
264 : : ResourceOwner owner;
265 : : } OSSLCipher;
266 : :
267 : : /* ResourceOwner callbacks to hold OpenSSL cipher state */
268 : : static void ResOwnerReleaseOSSLCipher(Datum res);
269 : :
270 : : static const ResourceOwnerDesc osslcipher_resowner_desc =
271 : : {
272 : : .name = "pgcrypto OpenSSL cipher handle",
273 : : .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
274 : : .release_priority = RELEASE_PRIO_FIRST,
275 : : .ReleaseResource = ResOwnerReleaseOSSLCipher,
276 : : .DebugPrint = NULL, /* default message is fine */
277 : : };
278 : :
279 : : /* Convenience wrappers over ResourceOwnerRemember/Forget */
280 : : static inline void
668 heikki.linnakangas@i 281 :CBC 208 : ResourceOwnerRememberOSSLCipher(ResourceOwner owner, OSSLCipher *od)
282 : : {
283 : 208 : ResourceOwnerRemember(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
284 : 208 : }
285 : : static inline void
286 : 208 : ResourceOwnerForgetOSSLCipher(ResourceOwner owner, OSSLCipher *od)
287 : : {
288 : 208 : ResourceOwnerForget(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
3190 289 : 208 : }
290 : :
291 : : static void
668 292 : 208 : free_openssl_cipher(OSSLCipher *od)
293 : : {
294 : 208 : EVP_CIPHER_CTX_free(od->evp_ctx);
295 [ + - ]: 208 : if (od->owner != NULL)
296 : 208 : ResourceOwnerForgetOSSLCipher(od->owner, od);
297 : 208 : pfree(od);
3190 298 : 208 : }
299 : :
300 : : /* Common routines for all algorithms */
301 : :
302 : : static unsigned
5931 bruce@momjian.us 303 : 328 : gen_ossl_block_size(PX_Cipher *c)
304 : : {
3190 heikki.linnakangas@i 305 : 328 : OSSLCipher *od = (OSSLCipher *) c->ptr;
306 : :
8331 bruce@momjian.us 307 : 328 : return od->ciph->block_size;
308 : : }
309 : :
310 : : static unsigned
5931 311 : 88 : gen_ossl_key_size(PX_Cipher *c)
312 : : {
3190 heikki.linnakangas@i 313 : 88 : OSSLCipher *od = (OSSLCipher *) c->ptr;
314 : :
8331 bruce@momjian.us 315 : 88 : return od->ciph->max_key_size;
316 : : }
317 : :
318 : : static unsigned
5931 319 : 88 : gen_ossl_iv_size(PX_Cipher *c)
320 : : {
321 : : unsigned ivlen;
3190 heikki.linnakangas@i 322 : 88 : OSSLCipher *od = (OSSLCipher *) c->ptr;
323 : :
8331 bruce@momjian.us 324 : 88 : ivlen = od->ciph->block_size;
8782 325 : 88 : return ivlen;
326 : : }
327 : :
328 : : static void
5931 329 : 208 : gen_ossl_free(PX_Cipher *c)
330 : : {
3190 heikki.linnakangas@i 331 : 208 : OSSLCipher *od = (OSSLCipher *) c->ptr;
332 : :
333 : 208 : free_openssl_cipher(od);
1807 michael@paquier.xyz 334 : 208 : pfree(c);
8782 bruce@momjian.us 335 : 208 : }
336 : :
337 : : static int
1264 peter@eisentraut.org 338 : 16 : gen_ossl_decrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen,
339 : : uint8 *res, unsigned *rlen)
340 : : {
3190 heikki.linnakangas@i 341 : 16 : OSSLCipher *od = c->ptr;
342 : : int outlen,
343 : : outlen2;
344 : :
3246 345 [ + - ]: 16 : if (!od->init)
346 : : {
3190 347 [ + + ]: 16 : if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
3246 348 : 3 : return PXE_CIPHER_INIT;
1264 peter@eisentraut.org 349 [ - + ]: 13 : if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding))
1488 dgustafsson@postgres 350 :UBC 0 : return PXE_CIPHER_INIT;
3190 heikki.linnakangas@i 351 [ - + ]:CBC 13 : if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
3246 heikki.linnakangas@i 352 :UBC 0 : return PXE_CIPHER_INIT;
3190 heikki.linnakangas@i 353 [ - + ]:CBC 13 : if (!EVP_DecryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv))
3246 heikki.linnakangas@i 354 :UBC 0 : return PXE_CIPHER_INIT;
3246 heikki.linnakangas@i 355 :CBC 13 : od->init = true;
356 : : }
357 : :
3190 358 [ - + ]: 13 : if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
3246 heikki.linnakangas@i 359 :UBC 0 : return PXE_DECRYPT_FAILED;
1264 peter@eisentraut.org 360 [ + + ]:CBC 13 : if (!EVP_DecryptFinal_ex(od->evp_ctx, res + outlen, &outlen2))
361 : 2 : return PXE_DECRYPT_FAILED;
362 : 11 : *rlen = outlen + outlen2;
363 : :
3246 heikki.linnakangas@i 364 : 11 : return 0;
365 : : }
366 : :
367 : : static int
1264 peter@eisentraut.org 368 : 10881 : gen_ossl_encrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen,
369 : : uint8 *res, unsigned *rlen)
370 : : {
3190 heikki.linnakangas@i 371 : 10881 : OSSLCipher *od = c->ptr;
372 : : int outlen,
373 : : outlen2;
374 : :
3246 375 [ + + ]: 10881 : if (!od->init)
376 : : {
3190 377 [ + + ]: 214 : if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL))
3246 378 : 65 : return PXE_CIPHER_INIT;
1264 peter@eisentraut.org 379 [ - + ]: 149 : if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding))
1488 dgustafsson@postgres 380 :UBC 0 : return PXE_CIPHER_INIT;
3190 heikki.linnakangas@i 381 [ - + ]:CBC 149 : if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
3246 heikki.linnakangas@i 382 :UBC 0 : return PXE_CIPHER_INIT;
3190 heikki.linnakangas@i 383 [ - + ]:CBC 149 : if (!EVP_EncryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv))
3246 heikki.linnakangas@i 384 :UBC 0 : return PXE_CIPHER_INIT;
3246 heikki.linnakangas@i 385 :CBC 149 : od->init = true;
386 : : }
387 : :
3190 388 [ - + ]: 10816 : if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
1770 michael@paquier.xyz 389 :UBC 0 : return PXE_ENCRYPT_FAILED;
1264 peter@eisentraut.org 390 [ + + ]:CBC 10816 : if (!EVP_EncryptFinal_ex(od->evp_ctx, res + outlen, &outlen2))
391 : 1 : return PXE_ENCRYPT_FAILED;
392 : 10815 : *rlen = outlen + outlen2;
393 : :
3246 heikki.linnakangas@i 394 : 10815 : return 0;
395 : : }
396 : :
397 : : /* Blowfish */
398 : :
399 : : /*
400 : : * Check if strong crypto is supported. Some OpenSSL installations
401 : : * support only short keys and unfortunately BF_set_key does not return any
402 : : * error value. This function tests if is possible to use strong key.
403 : : */
404 : : static int
6552 tgl@sss.pgh.pa.us 405 : 4 : bf_check_supported_key_len(void)
406 : : {
407 : : static const uint8 key[56] = {
408 : : 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69,
409 : : 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f, 0x00, 0x11, 0x22, 0x33,
410 : : 0x44, 0x55, 0x66, 0x77, 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd,
411 : : 0x3b, 0x2f, 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
412 : : 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e, 0xff, 0xff,
413 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
414 : : };
415 : :
416 : : static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
417 : : static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53};
418 : : uint8 out[8];
419 : : EVP_CIPHER_CTX *evp_ctx;
420 : : int outlen;
3190 heikki.linnakangas@i 421 : 4 : int status = 0;
422 : :
423 : : /* encrypt with 448bits key and verify output */
424 : 4 : evp_ctx = EVP_CIPHER_CTX_new();
425 [ - + ]: 4 : if (!evp_ctx)
3246 heikki.linnakangas@i 426 :UBC 0 : return 0;
3190 heikki.linnakangas@i 427 [ + - ]:CBC 4 : if (!EVP_EncryptInit_ex(evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL))
428 : 4 : goto leave;
3190 heikki.linnakangas@i 429 [ # # ]:UBC 0 : if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, 56))
430 : 0 : goto leave;
431 [ # # ]: 0 : if (!EVP_EncryptInit_ex(evp_ctx, NULL, NULL, key, NULL))
432 : 0 : goto leave;
433 : :
434 [ # # ]: 0 : if (!EVP_EncryptUpdate(evp_ctx, out, &outlen, data, 8))
435 : 0 : goto leave;
436 : :
6505 bruce@momjian.us 437 [ # # ]: 0 : if (memcmp(out, res, 8) != 0)
3190 heikki.linnakangas@i 438 : 0 : goto leave; /* Output does not match -> strong cipher is
439 : : * not supported */
440 : 0 : status = 1;
441 : :
3190 heikki.linnakangas@i 442 :CBC 4 : leave:
443 : 4 : EVP_CIPHER_CTX_free(evp_ctx);
444 : 4 : return status;
445 : : }
446 : :
447 : : static int
5931 bruce@momjian.us 448 : 28 : bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
449 : : {
3190 heikki.linnakangas@i 450 : 28 : OSSLCipher *od = c->ptr;
3246 451 : 28 : unsigned bs = gen_ossl_block_size(c);
452 : : static int bf_is_strong = -1;
453 : :
454 : : /*
455 : : * Test if key len is supported. BF_set_key silently cut large keys and it
456 : : * could be a problem when user transfer encrypted data from one server to
457 : : * another.
458 : : */
459 : :
6505 bruce@momjian.us 460 [ + + ]: 28 : if (bf_is_strong == -1)
6552 tgl@sss.pgh.pa.us 461 : 4 : bf_is_strong = bf_check_supported_key_len();
462 : :
6505 bruce@momjian.us 463 [ + - + + ]: 28 : if (!bf_is_strong && klen > 16)
464 : 4 : return PXE_KEY_TOO_BIG;
465 : :
466 : : /* Key len is supported. We can use it. */
3246 heikki.linnakangas@i 467 : 24 : od->klen = klen;
468 : 24 : memcpy(od->key, key, klen);
469 : :
8717 bruce@momjian.us 470 [ + + ]: 24 : if (iv)
3246 heikki.linnakangas@i 471 : 16 : memcpy(od->iv, iv, bs);
472 : : else
473 : 8 : memset(od->iv, 0, bs);
8331 bruce@momjian.us 474 : 24 : return 0;
475 : : }
476 : :
477 : : /* DES */
478 : :
479 : : static int
5931 480 : 8 : ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
481 : : {
3190 heikki.linnakangas@i 482 : 8 : OSSLCipher *od = c->ptr;
3246 483 : 8 : unsigned bs = gen_ossl_block_size(c);
484 : :
485 : 8 : od->klen = 8;
486 : 8 : memset(od->key, 0, 8);
487 : 8 : memcpy(od->key, key, klen > 8 ? 8 : klen);
488 : :
8717 bruce@momjian.us 489 [ + - ]: 8 : if (iv)
3246 heikki.linnakangas@i 490 : 8 : memcpy(od->iv, iv, bs);
491 : : else
3246 heikki.linnakangas@i 492 :UBC 0 : memset(od->iv, 0, bs);
8782 bruce@momjian.us 493 :CBC 8 : return 0;
494 : : }
495 : :
496 : : /* DES3 */
497 : :
498 : : static int
5931 499 : 11 : ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
500 : : {
3190 heikki.linnakangas@i 501 : 11 : OSSLCipher *od = c->ptr;
7474 neilc@samurai.com 502 : 11 : unsigned bs = gen_ossl_block_size(c);
503 : :
3246 heikki.linnakangas@i 504 : 11 : od->klen = 24;
505 : 11 : memset(od->key, 0, 24);
506 : 11 : memcpy(od->key, key, klen > 24 ? 24 : klen);
507 : :
508 [ + - ]: 11 : if (iv)
509 : 11 : memcpy(od->iv, iv, bs);
510 : : else
3246 heikki.linnakangas@i 511 :UBC 0 : memset(od->iv, 0, bs);
7474 neilc@samurai.com 512 :CBC 11 : return 0;
513 : : }
514 : :
515 : : /* CAST5 */
516 : :
517 : : static int
5931 bruce@momjian.us 518 : 10 : ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
519 : : {
3190 heikki.linnakangas@i 520 : 10 : OSSLCipher *od = c->ptr;
8331 bruce@momjian.us 521 : 10 : unsigned bs = gen_ossl_block_size(c);
522 : :
3246 heikki.linnakangas@i 523 : 10 : od->klen = klen;
524 : 10 : memcpy(od->key, key, klen);
525 : :
8331 bruce@momjian.us 526 [ + - ]: 10 : if (iv)
527 : 10 : memcpy(od->iv, iv, bs);
528 : : else
8331 bruce@momjian.us 529 :UBC 0 : memset(od->iv, 0, bs);
8782 bruce@momjian.us 530 :CBC 10 : return 0;
531 : : }
532 : :
533 : : /* AES */
534 : :
535 : : static int
5931 536 : 151 : ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
537 : : {
3190 heikki.linnakangas@i 538 : 151 : OSSLCipher *od = c->ptr;
7474 neilc@samurai.com 539 : 151 : unsigned bs = gen_ossl_block_size(c);
540 : :
7266 bruce@momjian.us 541 [ + + ]: 151 : if (klen <= 128 / 8)
542 : 117 : od->klen = 128 / 8;
543 [ + + ]: 34 : else if (klen <= 192 / 8)
544 : 15 : od->klen = 192 / 8;
545 [ + - ]: 19 : else if (klen <= 256 / 8)
546 : 19 : od->klen = 256 / 8;
547 : : else
7474 neilc@samurai.com 548 :UBC 0 : return PXE_KEY_TOO_BIG;
549 : :
7474 neilc@samurai.com 550 :CBC 151 : memcpy(od->key, key, klen);
551 : :
552 [ + + ]: 151 : if (iv)
553 : 39 : memcpy(od->iv, iv, bs);
554 : : else
555 : 112 : memset(od->iv, 0, bs);
556 : :
557 : 151 : return 0;
558 : : }
559 : :
560 : : static int
3246 heikki.linnakangas@i 561 : 115 : ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
562 : : {
3190 563 : 115 : OSSLCipher *od = c->ptr;
564 : : int err;
565 : :
3246 566 : 115 : err = ossl_aes_init(c, key, klen, iv);
567 [ - + ]: 115 : if (err)
3246 heikki.linnakangas@i 568 :UBC 0 : return err;
569 : :
3246 heikki.linnakangas@i 570 [ + + + - ]:CBC 115 : switch (od->klen)
571 : : {
572 : 91 : case 128 / 8:
573 : 91 : od->evp_ciph = EVP_aes_128_ecb();
574 : 91 : break;
575 : 11 : case 192 / 8:
576 : 11 : od->evp_ciph = EVP_aes_192_ecb();
577 : 11 : break;
578 : 13 : case 256 / 8:
579 : 13 : od->evp_ciph = EVP_aes_256_ecb();
580 : 13 : break;
3246 heikki.linnakangas@i 581 :UBC 0 : default:
582 : : /* shouldn't happen */
583 : 0 : err = PXE_CIPHER_INIT;
584 : 0 : break;
585 : : }
586 : :
3246 heikki.linnakangas@i 587 :CBC 115 : return err;
588 : : }
589 : :
590 : : static int
591 : 18 : ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
592 : : {
3190 593 : 18 : OSSLCipher *od = c->ptr;
594 : : int err;
595 : :
3246 596 : 18 : err = ossl_aes_init(c, key, klen, iv);
597 [ - + ]: 18 : if (err)
3246 heikki.linnakangas@i 598 :UBC 0 : return err;
599 : :
3246 heikki.linnakangas@i 600 [ + + + - ]:CBC 18 : switch (od->klen)
601 : : {
602 : 13 : case 128 / 8:
603 : 13 : od->evp_ciph = EVP_aes_128_cbc();
604 : 13 : break;
605 : 2 : case 192 / 8:
606 : 2 : od->evp_ciph = EVP_aes_192_cbc();
607 : 2 : break;
608 : 3 : case 256 / 8:
609 : 3 : od->evp_ciph = EVP_aes_256_cbc();
610 : 3 : break;
3246 heikki.linnakangas@i 611 :UBC 0 : default:
612 : : /* shouldn't happen */
613 : 0 : err = PXE_CIPHER_INIT;
614 : 0 : break;
615 : : }
616 : :
3246 heikki.linnakangas@i 617 :CBC 18 : return err;
618 : : }
619 : :
620 : : static int
204 dgustafsson@postgres 621 : 18 : ossl_aes_cfb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
622 : : {
623 : 18 : OSSLCipher *od = c->ptr;
624 : : int err;
625 : :
626 : 18 : err = ossl_aes_init(c, key, klen, iv);
627 [ - + ]: 18 : if (err)
204 dgustafsson@postgres 628 :UBC 0 : return err;
629 : :
204 dgustafsson@postgres 630 [ + + + - ]:CBC 18 : switch (od->klen)
631 : : {
632 : 13 : case 128 / 8:
633 : 13 : od->evp_ciph = EVP_aes_128_cfb();
634 : 13 : break;
635 : 2 : case 192 / 8:
636 : 2 : od->evp_ciph = EVP_aes_192_cfb();
637 : 2 : break;
638 : 3 : case 256 / 8:
639 : 3 : od->evp_ciph = EVP_aes_256_cfb();
640 : 3 : break;
204 dgustafsson@postgres 641 :UBC 0 : default:
642 : : /* shouldn't happen */
643 : 0 : err = PXE_CIPHER_INIT;
644 : 0 : break;
645 : : }
646 : :
204 dgustafsson@postgres 647 :CBC 18 : return err;
648 : : }
649 : :
650 : : /*
651 : : * aliases
652 : : */
653 : :
654 : : static PX_Alias ossl_aliases[] = {
655 : : {"bf", "bf-cbc"},
656 : : {"blowfish", "bf-cbc"},
657 : : {"blowfish-cbc", "bf-cbc"},
658 : : {"blowfish-ecb", "bf-ecb"},
659 : : {"blowfish-cfb", "bf-cfb"},
660 : : {"des", "des-cbc"},
661 : : {"3des", "des3-cbc"},
662 : : {"3des-ecb", "des3-ecb"},
663 : : {"3des-cbc", "des3-cbc"},
664 : : {"cast5", "cast5-cbc"},
665 : : {"aes", "aes-cbc"},
666 : : {"rijndael", "aes-cbc"},
667 : : {"rijndael-cbc", "aes-cbc"},
668 : : {"rijndael-ecb", "aes-ecb"},
669 : : {"rijndael-cfb", "aes-cfb"},
670 : : {NULL}
671 : : };
672 : :
673 : : static const struct ossl_cipher ossl_bf_cbc = {
674 : : bf_init,
675 : : EVP_bf_cbc,
676 : : 64 / 8, 448 / 8
677 : : };
678 : :
679 : : static const struct ossl_cipher ossl_bf_ecb = {
680 : : bf_init,
681 : : EVP_bf_ecb,
682 : : 64 / 8, 448 / 8
683 : : };
684 : :
685 : : static const struct ossl_cipher ossl_bf_cfb = {
686 : : bf_init,
687 : : EVP_bf_cfb,
688 : : 64 / 8, 448 / 8
689 : : };
690 : :
691 : : static const struct ossl_cipher ossl_des_ecb = {
692 : : ossl_des_init,
693 : : EVP_des_ecb,
694 : : 64 / 8, 64 / 8
695 : : };
696 : :
697 : : static const struct ossl_cipher ossl_des_cbc = {
698 : : ossl_des_init,
699 : : EVP_des_cbc,
700 : : 64 / 8, 64 / 8
701 : : };
702 : :
703 : : static const struct ossl_cipher ossl_des3_ecb = {
704 : : ossl_des3_init,
705 : : EVP_des_ede3_ecb,
706 : : 64 / 8, 192 / 8
707 : : };
708 : :
709 : : static const struct ossl_cipher ossl_des3_cbc = {
710 : : ossl_des3_init,
711 : : EVP_des_ede3_cbc,
712 : : 64 / 8, 192 / 8
713 : : };
714 : :
715 : : static const struct ossl_cipher ossl_cast_ecb = {
716 : : ossl_cast_init,
717 : : EVP_cast5_ecb,
718 : : 64 / 8, 128 / 8
719 : : };
720 : :
721 : : static const struct ossl_cipher ossl_cast_cbc = {
722 : : ossl_cast_init,
723 : : EVP_cast5_cbc,
724 : : 64 / 8, 128 / 8
725 : : };
726 : :
727 : : static const struct ossl_cipher ossl_aes_ecb = {
728 : : ossl_aes_ecb_init,
729 : : NULL, /* EVP_aes_XXX_ecb(), determined in init
730 : : * function */
731 : : 128 / 8, 256 / 8
732 : : };
733 : :
734 : : static const struct ossl_cipher ossl_aes_cbc = {
735 : : ossl_aes_cbc_init,
736 : : NULL, /* EVP_aes_XXX_cbc(), determined in init
737 : : * function */
738 : : 128 / 8, 256 / 8
739 : : };
740 : :
741 : : static const struct ossl_cipher ossl_aes_cfb = {
742 : : ossl_aes_cfb_init,
743 : : NULL, /* EVP_aes_XXX_cfb(), determined in init
744 : : * function */
745 : : 128 / 8, 256 / 8
746 : : };
747 : :
748 : : /*
749 : : * Special handlers
750 : : */
751 : : struct ossl_cipher_lookup
752 : : {
753 : : const char *name;
754 : : const struct ossl_cipher *ciph;
755 : : };
756 : :
757 : : static const struct ossl_cipher_lookup ossl_cipher_types[] = {
758 : : {"bf-cbc", &ossl_bf_cbc},
759 : : {"bf-ecb", &ossl_bf_ecb},
760 : : {"bf-cfb", &ossl_bf_cfb},
761 : : {"des-ecb", &ossl_des_ecb},
762 : : {"des-cbc", &ossl_des_cbc},
763 : : {"des3-ecb", &ossl_des3_ecb},
764 : : {"des3-cbc", &ossl_des3_cbc},
765 : : {"cast5-ecb", &ossl_cast_ecb},
766 : : {"cast5-cbc", &ossl_cast_cbc},
767 : : {"aes-ecb", &ossl_aes_ecb},
768 : : {"aes-cbc", &ossl_aes_cbc},
769 : : {"aes-cfb", &ossl_aes_cfb},
770 : : {NULL}
771 : : };
772 : :
773 : : /* PUBLIC functions */
774 : :
775 : : int
5931 bruce@momjian.us 776 : 209 : px_find_cipher(const char *name, PX_Cipher **res)
777 : : {
778 : : const struct ossl_cipher_lookup *i;
7474 neilc@samurai.com 779 : 209 : PX_Cipher *c = NULL;
780 : : EVP_CIPHER_CTX *ctx;
781 : : OSSLCipher *od;
782 : :
8782 bruce@momjian.us 783 : 209 : name = px_resolve_alias(ossl_aliases, name);
7474 neilc@samurai.com 784 [ + + ]: 1825 : for (i = ossl_cipher_types; i->name; i++)
5002 peter_e@gmx.net 785 [ + + ]: 1824 : if (strcmp(i->name, name) == 0)
8331 bruce@momjian.us 786 : 208 : break;
7474 neilc@samurai.com 787 [ + + ]: 209 : if (i->name == NULL)
788 : 1 : return PXE_NO_CIPHER;
789 : :
668 heikki.linnakangas@i 790 : 208 : ResourceOwnerEnlarge(CurrentResourceOwner);
791 : :
792 : : /*
793 : : * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
794 : : * The order is crucial, to make sure we don't leak anything on
795 : : * out-of-memory or other error.
796 : : */
3190 797 : 208 : od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od));
7474 neilc@samurai.com 798 : 208 : od->ciph = i->ciph;
799 : :
800 : : /* Allocate an EVP_CIPHER_CTX object. */
3190 heikki.linnakangas@i 801 : 208 : ctx = EVP_CIPHER_CTX_new();
802 [ - + ]: 208 : if (!ctx)
803 : : {
3190 heikki.linnakangas@i 804 :UBC 0 : pfree(od);
805 : 0 : return PXE_CIPHER_INIT;
806 : : }
807 : :
3190 heikki.linnakangas@i 808 :CBC 208 : od->evp_ctx = ctx;
809 : 208 : od->owner = CurrentResourceOwner;
668 810 : 208 : ResourceOwnerRememberOSSLCipher(od->owner, od);
811 : :
3246 812 [ + + ]: 208 : if (i->ciph->cipher_func)
813 : 57 : od->evp_ciph = i->ciph->cipher_func();
814 : :
815 : : /* The PX_Cipher is allocated in current memory context */
1807 michael@paquier.xyz 816 : 208 : c = palloc(sizeof(*c));
8331 bruce@momjian.us 817 : 208 : c->block_size = gen_ossl_block_size;
818 : 208 : c->key_size = gen_ossl_key_size;
819 : 208 : c->iv_size = gen_ossl_iv_size;
820 : 208 : c->free = gen_ossl_free;
7474 neilc@samurai.com 821 : 208 : c->init = od->ciph->init;
3246 heikki.linnakangas@i 822 : 208 : c->encrypt = gen_ossl_encrypt;
823 : 208 : c->decrypt = gen_ossl_decrypt;
8782 bruce@momjian.us 824 : 208 : c->ptr = od;
825 : :
826 : 208 : *res = c;
827 : 208 : return 0;
828 : : }
829 : :
830 : : /* ResourceOwner callbacks for OSSLCipher */
831 : :
832 : : static void
668 heikki.linnakangas@i 833 :UBC 0 : ResOwnerReleaseOSSLCipher(Datum res)
834 : : {
835 : 0 : free_openssl_cipher((OSSLCipher *) DatumGetPointer(res));
836 : 0 : }
837 : :
838 : : /*
839 : : * CheckFIPSMode
840 : : *
841 : : * Returns the FIPS mode of the underlying OpenSSL installation.
842 : : */
843 : : bool
225 dgustafsson@postgres 844 : 0 : CheckFIPSMode(void)
845 : : {
846 : 0 : int fips_enabled = 0;
847 : :
848 : : /*
849 : : * EVP_default_properties_is_fips_enabled was added in OpenSSL 3.0, before
850 : : * that FIPS_mode() was used to test for FIPS being enabled. The last
851 : : * upstream OpenSSL version before 3.0 which supported FIPS was 1.0.2, but
852 : : * there are forks of 1.1.1 which are FIPS validated so we still need to
853 : : * test with FIPS_mode() even though we don't support 1.0.2.
854 : : */
855 : : fips_enabled =
856 : : #if OPENSSL_VERSION_NUMBER >= 0x30000000L
857 : 0 : EVP_default_properties_is_fips_enabled(NULL);
858 : : #else
859 : : FIPS_mode();
860 : : #endif
861 : :
862 : 0 : return (fips_enabled == 1);
863 : : }
864 : :
865 : : /*
866 : : * CheckBuiltinCryptoMode
867 : : *
868 : : * Function for erroring out in case built-in crypto is executed when the user
869 : : * has disabled it. If builtin_crypto_enabled is set to BC_OFF or BC_FIPS and
870 : : * OpenSSL is operating in FIPS mode the function will error out, else the
871 : : * query executing built-in crypto can proceed.
872 : : */
873 : : void
225 dgustafsson@postgres 874 :CBC 66 : CheckBuiltinCryptoMode(void)
875 : : {
876 [ + + ]: 66 : if (builtin_crypto_enabled == BC_ON)
877 : 64 : return;
878 : :
879 [ + - ]: 2 : if (builtin_crypto_enabled == BC_OFF)
880 [ + - ]: 2 : ereport(ERROR,
881 : : errmsg("use of built-in crypto functions is disabled"));
882 : :
225 dgustafsson@postgres 883 [ # # ]:UBC 0 : Assert(builtin_crypto_enabled == BC_FIPS);
884 : :
885 [ # # ]: 0 : if (CheckFIPSMode() == true)
886 [ # # ]: 0 : ereport(ERROR,
887 : : errmsg("use of non-FIPS validated crypto not allowed when OpenSSL is in FIPS mode"));
888 : : }
|