]> git.tuebingen.mpg.de Git - paraslash.git/blob - openssl.c
openssl: Use the EVP library for RSA public encryption.
[paraslash.git] / openssl.c
1 /* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file openssl.c Openssl-based encryption/decryption routines. */
4
5 #include <regex.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <openssl/rand.h>
9 #include <openssl/err.h>
10 #include <openssl/pem.h>
11 #include <openssl/sha.h>
12 #include <openssl/bn.h>
13 #include <openssl/aes.h>
14 #include <openssl/evp.h>
15
16 #include "para.h"
17 #include "error.h"
18 #include "string.h"
19 #include "crypt.h"
20 #include "crypt_backend.h"
21 #include "portable_io.h"
22
23 struct asymmetric_key {
24         RSA *rsa;
25         EVP_PKEY *pkey;
26         EVP_PKEY_CTX *ctx;
27 };
28
29 static int openssl_perror(const char *pfx)
30 {
31         unsigned long err = ERR_get_error();
32         PARA_ERROR_LOG("%s: \"%s\"\n", pfx, ERR_reason_error_string(err));
33         return -E_OPENSSL;
34 }
35
36 void get_random_bytes_or_die(unsigned char *buf, int num)
37 {
38         int ret;
39
40         if (RAND_bytes(buf, num) == 1) /* success */
41                 return;
42         ret = openssl_perror("RAND_bytes");
43         PARA_EMERG_LOG("%s\n", strerror(-ret));
44         exit(EXIT_FAILURE);
45 }
46
47 /*
48  * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Then seed the
49  * PRNG used by random(3) with a random seed obtained from SSL.
50  */
51 void crypt_init(void)
52 {
53         int seed, ret = RAND_load_file("/dev/urandom", 64);
54
55         if (ret != 64) {
56                 PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret);
57                 exit(EXIT_FAILURE);
58         }
59         get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed));
60         srandom(seed);
61 }
62
63 void crypt_shutdown(void)
64 {
65 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
66         CRYPTO_cleanup_all_ex_data();
67 #endif
68 #ifdef HAVE_OPENSSL_THREAD_STOP /* openssl-1.1 or later */
69         OPENSSL_thread_stop();
70 #else /* openssl-1.0 */
71         ERR_remove_thread_state(NULL);
72 #endif
73         EVP_cleanup();
74 }
75
76 /*
77  * The public key loading functions below were inspired by corresponding code
78  * of openssh-5.2p1, Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo,
79  * Finland. However, not much of the original code remains.
80  */
81
82 static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result)
83 {
84         const unsigned char *p = buf, *end = buf + len;
85         uint32_t bnsize;
86         BIGNUM *bn;
87
88         if (p + 4 < p)
89                 return -E_BIGNUM;
90         if (p + 4 > end)
91                 return -E_BIGNUM;
92         bnsize = read_u32_be(p);
93         PARA_DEBUG_LOG("bnsize: %u\n", bnsize);
94         p += 4;
95         if (p + bnsize < p)
96                 return -E_BIGNUM;
97         if (p + bnsize > end)
98                 return -E_BIGNUM;
99         if (bnsize > 8192)
100                 return -E_BIGNUM;
101         bn = BN_bin2bn(p, bnsize, NULL);
102         if (!bn)
103                 return -E_BIGNUM;
104         *result = bn;
105         return bnsize + 4;
106 }
107
108 #ifdef HAVE_OSSL_PARAM /* openssl-3 */
109 /*
110  * Convert bignumns e and n to a pkey and context.
111  */
112 static int generate_public_pkey(struct asymmetric_key *pub,
113                 const BIGNUM *e, const BIGNUM *n)
114 {
115         unsigned char *ebuf, *nbuf;
116         int ret, ebytes = BN_num_bytes(e), nbytes = BN_num_bytes(n);
117         OSSL_PARAM params[3];
118
119         /* Convert e and n to a buffer for OSSL_PARAM_construct_BN() */
120         ebuf = alloc(ebytes);
121         assert(BN_bn2nativepad(e, ebuf, ebytes) > 0);
122         nbuf = alloc(nbytes);
123         assert(BN_bn2nativepad(n, nbuf, nbytes) > 0);
124         /* Init params[] with {e,n}buf and create the pkey from it */
125         params[0] = OSSL_PARAM_construct_BN("e", ebuf, ebytes);
126         params[1] = OSSL_PARAM_construct_BN("n", nbuf, nbytes);
127         params[2] = OSSL_PARAM_construct_end();
128         pub->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
129         assert(pub->ctx);
130         assert(EVP_PKEY_fromdata_init(pub->ctx) > 0);
131         ret = EVP_PKEY_fromdata(pub->ctx, &pub->pkey, EVP_PKEY_PUBLIC_KEY,
132                 params);
133         free(nbuf);
134         free(ebuf);
135         if (ret <= 0) {
136                 EVP_PKEY_CTX_free(pub->ctx);
137                 return openssl_perror("EVP_PKEY_fromdata()");
138         }
139         assert(pub->pkey);
140         return nbytes * 8;
141 }
142 #endif /* HAVE_OSSL_PARAM */
143
144 static int read_public_key(const unsigned char *blob, size_t blen,
145                 struct asymmetric_key *pub)
146 {
147         int ret, bits;
148         const unsigned char *p = blob, *end = blob + blen;
149         BIGNUM *e, *n;
150
151         ret = read_bignum(p, end - p, &e);
152         if (ret < 0)
153                 return ret;
154         p += ret;
155         ret = read_bignum(p, end - p, &n);
156         if (ret < 0) {
157                 BN_free(e);
158                 return ret;
159         }
160         bits = BN_num_bytes(n) * 8;
161         PARA_DEBUG_LOG("modulus: %d bits\n", bits);
162 #ifdef HAVE_OSSL_PARAM /* openssl-3 */
163         ret = generate_public_pkey(pub, e, n);
164         BN_free(e);
165         BN_free(n);
166         if (ret < 0)
167                 return ret;
168 #else /* openssl < 3.0 */
169         pub->rsa = RSA_new();
170         assert(pub->rsa);
171         #if HAVE_RSA_SET0_KEY /* openssl-1.1 */
172                 RSA_set0_key(pub->rsa, n, e, NULL);
173         #else /* openssl-1.0 */
174                 pub->rsa->n = n;
175                 pub->rsa->e = e;
176         #endif
177         /* e and n are now owned by openssl */
178 #endif /* HAVE_OSSL_PARAM */
179         return bits;
180 }
181
182 static int read_pem_private_key(const char *path, struct asymmetric_key *priv)
183 {
184         EVP_PKEY *pkey;
185         BIO *bio;
186
187         assert((bio = BIO_new(BIO_s_file())));
188         priv->rsa = NULL;
189         if (BIO_read_filename(bio, path) <= 0)
190                 goto bio_free;
191         pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
192         if (!pkey)
193                 goto bio_free;
194         priv->rsa = EVP_PKEY_get1_RSA(pkey);
195         EVP_PKEY_free(pkey);
196 bio_free:
197         BIO_free(bio);
198         return priv->rsa? RSA_size(priv->rsa) : -E_PRIVATE_KEY;
199 }
200
201 static int read_openssh_private_key(const unsigned char *blob,
202                 const unsigned char *end, struct asymmetric_key *priv)
203 {
204         int ret;
205         RSA *rsa;
206         BIGNUM *n, *e, *d, *iqmp, *p, *q; /* stored in the key file */
207         const unsigned char *cp = blob;
208
209         assert((rsa = RSA_new()));
210         ret = read_bignum(cp, end - cp, &n);
211         if (ret < 0)
212                 goto free_rsa;
213         cp += ret;
214         ret = read_bignum(cp, end - cp, &e);
215         if (ret < 0)
216                 goto free_n;
217         cp += ret;
218         ret = read_bignum(cp, end - cp, &d);
219         if (ret < 0)
220                 goto free_e;
221         cp += ret;
222         ret = read_bignum(cp, end - cp, &iqmp);
223         if (ret < 0)
224                 goto free_d;
225         cp += ret;
226         ret = read_bignum(cp, end - cp, &p);
227         if (ret < 0)
228                 goto free_iqmp;
229         cp += ret;
230         ret = read_bignum(cp, end - cp, &q);
231         if (ret < 0)
232                 goto free_p;
233 #ifdef HAVE_RSA_SET0_KEY
234         RSA_set0_key(rsa, n, e, d);
235         RSA_set0_factors(rsa, p, q);
236         RSA_set0_crt_params(rsa, NULL, NULL, iqmp);
237
238 #else
239         rsa->n = n;
240         rsa->e = e;
241         rsa->d = d;
242         rsa->iqmp = iqmp;
243         rsa->p = p;
244         rsa->q = q;
245 #endif
246         priv->rsa = rsa;
247         return 1;
248 free_p:
249         BN_clear_free(p);
250 free_iqmp:
251         BN_clear_free(iqmp);
252 free_d:
253         BN_clear_free(d);
254 free_e:
255         BN_free(e);
256 free_n:
257         BN_free(n);
258 free_rsa:
259         RSA_free(rsa);
260         return ret;
261 }
262
263 static int get_private_key(const char *path, struct asymmetric_key *priv)
264 {
265         int ret;
266         unsigned char *blob, *end;
267         size_t blob_size;
268
269         priv->rsa = NULL;
270         ret = decode_private_key(path, &blob, &blob_size);
271         if (ret < 0)
272                 return ret;
273         end = blob + blob_size;
274         if (ret == PKT_OPENSSH) {
275                 ret = find_openssh_bignum_offset(blob, blob_size);
276                 if (ret < 0)
277                         goto free_blob;
278                 PARA_INFO_LOG("reading RSA params at offset %d\n", ret);
279                 ret = read_openssh_private_key(blob + ret, end, priv);
280         } else
281                 ret = read_pem_private_key(path, priv);
282 free_blob:
283         free(blob);
284         return ret;
285 }
286
287 int apc_get_pubkey(const char *key_file, struct asymmetric_key **result)
288 {
289         unsigned char *blob;
290         size_t decoded_size;
291         int ret;
292         struct asymmetric_key *pub;
293
294         ret = decode_public_key(key_file, &blob, &decoded_size);
295         if (ret < 0)
296                 return ret;
297         pub = zalloc(sizeof(*pub)); /* ->pkey needs to start out zeroed */
298         ret = read_public_key(blob + ret, decoded_size - ret, pub);
299         free(blob);
300         if (ret < 0) {
301                 free(pub);
302                 *result = NULL;
303                 PARA_ERROR_LOG("can not load key %s\n", key_file);
304                 return ret;
305         }
306         PARA_NOTICE_LOG("loaded %d bit key from %s\n", ret, key_file);
307         *result = pub;
308         return ret / 8;
309 }
310
311 void apc_free_pubkey(struct asymmetric_key *pub)
312 {
313         if (!pub)
314                 return;
315 #ifdef HAVE_OSSL_PARAM /* openssl-3 */
316         EVP_PKEY_CTX_free(pub->ctx);
317         EVP_PKEY_free(pub->pkey);
318 #else
319         RSA_free(pub->rsa);
320 #endif
321         free(pub);
322 }
323
324 int apc_priv_decrypt(const char *key_file, unsigned char **outbuf,
325                 unsigned char *inbuf, int inlen)
326 {
327         struct asymmetric_key *priv;
328         int ret;
329
330         *outbuf = NULL;
331         ret = check_private_key_file(key_file);
332         if (ret < 0)
333                 return ret;
334         if (inlen < 0)
335                 return -E_RSA;
336         priv = alloc(sizeof(*priv));
337         ret = get_private_key(key_file, priv);
338         if (ret < 0) {
339                 free(priv);
340                 return ret;
341         }
342         /*
343          * RSA is vulnerable to timing attacks. Generate a random blinding
344          * factor to protect against this kind of attack.
345          */
346         ret = -E_BLINDING;
347         if (RSA_blinding_on(priv->rsa, NULL) == 0)
348                 goto out;
349         *outbuf = alloc(RSA_size(priv->rsa));
350         ret = RSA_private_decrypt(inlen, inbuf, *outbuf, priv->rsa,
351                 RSA_PKCS1_OAEP_PADDING);
352         RSA_blinding_off(priv->rsa);
353         if (ret <= 0) {
354                 free(*outbuf);
355                 *outbuf = NULL;
356                 ret = -E_DECRYPT;
357         }
358 out:
359         RSA_free(priv->rsa);
360         free(priv);
361         return ret;
362 }
363
364 int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
365                 unsigned len, unsigned char **outbuf)
366 {
367         int ret;
368 #ifdef HAVE_OSSL_PARAM /* openssl-3 */
369         EVP_PKEY_CTX *ctx;
370         size_t outlen;
371
372         *outbuf = NULL;
373         assert((ctx = EVP_PKEY_CTX_new(pub->pkey, NULL)));
374         assert((EVP_PKEY_encrypt_init(ctx) > 0));
375         assert((EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0));
376         if (EVP_PKEY_encrypt(ctx, NULL, &outlen, inbuf, len) <= 0) {
377                 ret = openssl_perror("EVP_PKEY_encrypt()");
378                 goto free_ctx;
379         }
380         *outbuf = alloc(outlen);
381         assert((EVP_PKEY_encrypt(ctx, *outbuf, &outlen, inbuf, len) > 0));
382         PARA_INFO_LOG("wrote %zu encrypted data bytes\n", outlen);
383         ret = outlen;
384 free_ctx:
385         EVP_PKEY_CTX_free(ctx);
386         return ret;
387 #else /* openssl < 3.0 */
388         *outbuf = alloc(RSA_size(pub->rsa));
389         ret = RSA_public_encrypt((int)len, inbuf, *outbuf, pub->rsa,
390                 RSA_PKCS1_OAEP_PADDING);
391         if (ret < 0) {
392                 free(*outbuf);
393                 *outbuf = NULL;
394                 return -E_ENCRYPT;
395         }
396         return ret;
397 #endif /* HAVE_OSSL_PARAM */
398 }
399
400 struct stream_cipher {
401         EVP_CIPHER_CTX *aes;
402 };
403
404 struct stream_cipher *sc_new(const unsigned char *data, int len)
405 {
406         struct stream_cipher *sc = alloc(sizeof(*sc));
407
408         assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
409         assert((sc->aes = EVP_CIPHER_CTX_new()));
410         EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data,
411                 data + AES_CRT128_BLOCK_SIZE);
412         return sc;
413 }
414
415 void sc_free(struct stream_cipher *sc)
416 {
417         if (!sc)
418                 return;
419         EVP_CIPHER_CTX_free(sc->aes);
420         free(sc);
421 }
422
423 static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src,
424                 struct iovec *dst)
425 {
426         int ret, inlen = src->iov_len, outlen, tmplen;
427
428         *dst = (typeof(*dst)) {
429                 /* Add one for the terminating zero byte. */
430                 .iov_base = alloc(inlen + 1),
431                 .iov_len = inlen
432         };
433         ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen);
434         assert(ret != 0);
435         ret = EVP_EncryptFinal_ex(ctx, dst->iov_base + outlen, &tmplen);
436         assert(ret != 0);
437         outlen += tmplen;
438         ((char *)dst->iov_base)[outlen] = '\0';
439         dst->iov_len = outlen;
440 }
441
442 void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
443 {
444         return aes_ctr128_crypt(sc->aes, src, dst);
445 }
446
447 void hash_function(const char *data, unsigned long len, unsigned char *hash)
448 {
449         int ret;
450         EVP_MD_CTX *c;
451
452         assert((c = EVP_MD_CTX_new()));
453         ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
454         assert(ret != 0);
455         ret = EVP_DigestUpdate(c, data, len);
456         assert(ret != 0);
457         ret = EVP_DigestFinal_ex(c, hash, NULL);
458         assert(ret != 0);
459         EVP_MD_CTX_free(c);
460 }
461
462 void hash2_function(const char *data, unsigned long len, unsigned char *hash)
463 {
464         int ret;
465         EVP_MD_CTX *c;
466
467         assert((c = EVP_MD_CTX_new()));
468         ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
469         assert(ret != 0);
470         ret = EVP_DigestUpdate(c, data, len);
471         assert(ret != 0);
472         ret = EVP_DigestFinal_ex(c, hash, NULL);
473         assert(ret != 0);
474         EVP_MD_CTX_free(c);
475 }