1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <crypto.h>
26
27 #include <openssl/err.h> /* ERR_* */
28 #include <openssl/rand.h> /* RAND_* */
29 #include <openssl/bn.h> /* BN_* */
30 #include <libcrypto-compat.h>
31
32 #include <cf3.defs.h>
33 #include <lastseen.h>
34 #include <files_interfaces.h>
35 #include <hash.h>
36 #include <pipes.h>
37 #include <mutex.h>
38 #include <known_dirs.h>
39 #include <bootstrap.h>
40 #include <misc_lib.h> /* UnexpectedError,ProgrammingError */
41 #include <file_lib.h>
42
43 #ifdef DARWIN
44 // On Mac OSX 10.7 and later, majority of functions in /usr/include/openssl/crypto.h
45 // are deprecated. No known replacement, so shutting up compiler warnings
46 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
47 #endif
48
49 #if OPENSSL_VERSION_NUMBER < 0x10100000
50 /* The deprecated is the easy way to setup threads for OpenSSL. */
51 #ifdef OPENSSL_NO_DEPRECATED
52 void CRYPTO_set_id_callback(unsigned long (*func)(void));
53 #endif
54 #endif
55
56 static void RandomSeed(void);
57 static void SetupOpenSSLThreadLocks(void);
58 static void CleanupOpenSSLThreadLocks(void);
59
60 /* TODO move crypto.[ch] to libutils. Will need to remove all manipulation of
61 * lastseen db. */
62
63 static bool crypto_initialized = false; /* GLOBAL_X */
64
CryptoLastErrorString()65 const char *CryptoLastErrorString()
66 {
67 const char *errmsg = ERR_reason_error_string(ERR_get_error());
68 return (errmsg != NULL) ? errmsg : "no error message";
69 }
70
CryptoInitialize()71 void CryptoInitialize()
72 {
73 if (!crypto_initialized)
74 {
75 SetupOpenSSLThreadLocks();
76 OpenSSL_add_all_algorithms();
77 OpenSSL_add_all_digests();
78 ERR_load_crypto_strings();
79
80 RandomSeed();
81
82 crypto_initialized = true;
83 }
84 }
85
CryptoDeInitialize()86 void CryptoDeInitialize()
87 {
88 if (crypto_initialized)
89 {
90 char randfile[CF_BUFSIZE];
91 snprintf(randfile, CF_BUFSIZE, "%s%crandseed",
92 GetWorkDir(), FILE_SEPARATOR);
93
94 /* Only write out a seed if the file doesn't exist
95 * and we have enough entropy to do so. If RAND_write_File
96 * returns a bad value, delete the poor seed.
97 */
98 if (access(randfile, R_OK) && errno == ENOENT && RAND_write_file(randfile) != 1024)
99 {
100 Log(LOG_LEVEL_WARNING,
101 "Could not write randomness to '%s'", randfile);
102 unlink(randfile); /* do not reuse entropy */
103 }
104
105 chmod(randfile, 0600);
106 EVP_cleanup();
107 CleanupOpenSSLThreadLocks();
108 ERR_free_strings();
109 crypto_initialized = false;
110 }
111 }
112
RandomSeed(void)113 static void RandomSeed(void)
114 {
115 /* 1. Seed the weak C PRNGs. */
116
117 /* Mix various stuff. */
118 pid_t pid = getpid();
119 size_t fqdn_len = strlen(VFQNAME) > 0 ? strlen(VFQNAME) : 1;
120 time_t start_time = CFSTARTTIME;
121 time_t now = time(NULL);
122
123 srand((unsigned) pid * start_time ^
124 (unsigned) fqdn_len * now);
125 srand48((long) pid * start_time ^
126 (long) fqdn_len * now);
127
128 /* 2. Seed the strong OpenSSL PRNG. */
129
130 #ifndef __MINGW32__
131 RAND_poll(); /* windows may hang */
132 #else
133 RAND_screen(); /* noop unless openssl is very old */
134 #endif
135
136 if (RAND_status() != 1)
137 {
138 /* randseed file is written on deinitialization of crypto system */
139 char randfile[CF_BUFSIZE];
140 snprintf(randfile, CF_BUFSIZE, "%s%crandseed",
141 GetWorkDir(), FILE_SEPARATOR);
142 Log(LOG_LEVEL_VERBOSE, "Looking for a source of entropy in '%s'",
143 randfile);
144
145 if (RAND_load_file(randfile, -1) != 1024)
146 {
147 Log(LOG_LEVEL_CRIT,
148 "Could not read randomness from '%s'", randfile);
149 unlink(randfile); /* kill randseed if error reading it */
150 }
151
152 /* If we've used the random seed, then delete */
153 unlink(randfile);
154 }
155 }
156
157 /* PEM functions need the const cast away, but hopefully the default
158 * call-back doesn't actually modify its user-data. */
159 static const char priv_passphrase[] = PRIVKEY_PASSPHRASE;
160
161 /**
162 * @param[in] priv_key_path path to the private key to use (%NULL to use the default)
163 * @param[in] pub_key_path path to the private key to use (%NULL to use the default)
164 * @param[out] priv_key a place to store the loaded private key (or %NULL to
165 * use the global PRIVKEY variable)
166 * @param[out] pub_key a place to store the loaded public key (or %NULL to
167 * use the global PUBKEY variable)
168 * @return true the error is not so severe that we must stop
169 */
LoadSecretKeys(const char * const priv_key_path,const char * const pub_key_path,RSA ** priv_key,RSA ** pub_key)170 bool LoadSecretKeys(const char *const priv_key_path,
171 const char *const pub_key_path,
172 RSA **priv_key, RSA **pub_key)
173 {
174 {
175 char *privkeyfile = NULL;
176 if (priv_key_path == NULL)
177 {
178 privkeyfile = PrivateKeyFile(GetWorkDir());
179 }
180 FILE *fp = safe_fopen(privkeyfile != NULL ? privkeyfile : priv_key_path, "r");
181 if (!fp)
182 {
183 /* VERBOSE in case it's a custom, local-only installation. */
184 Log(LOG_LEVEL_VERBOSE,
185 "Couldn't find a private key at '%s', use cf-key to get one. (fopen: %s)",
186 privkeyfile != NULL ? privkeyfile : priv_key_path, GetErrorStr());
187 free(privkeyfile);
188 return false;
189 }
190
191 if (priv_key == NULL)
192 {
193 /* if no place to store the private key was specified, use the
194 * global variable PRIVKEY */
195 priv_key = &PRIVKEY;
196 }
197 if (*priv_key != NULL)
198 {
199 DESTROY_AND_NULL(RSA_free, *priv_key);
200 }
201
202 // Can read both encrypted (old) and unencrypted(new) key files:
203 *priv_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, (void*) priv_passphrase);
204 if (*priv_key == NULL)
205 {
206 Log(LOG_LEVEL_ERR,
207 "Error reading private key. (PEM_read_RSAPrivateKey: %s)",
208 CryptoLastErrorString());
209 *priv_key = NULL;
210 fclose(fp);
211 return false;
212 }
213
214 fclose(fp);
215 Log(LOG_LEVEL_VERBOSE, "Loaded private key at '%s'", privkeyfile);
216 free(privkeyfile);
217 }
218
219 {
220 char *pubkeyfile = NULL;
221 if (pub_key_path == NULL)
222 {
223 pubkeyfile = PublicKeyFile(GetWorkDir());
224 }
225 FILE *fp = safe_fopen(pubkeyfile != NULL ? pubkeyfile : pub_key_path, "r");
226 if (!fp)
227 {
228 /* VERBOSE in case it's a custom, local-only installation. */
229 Log(LOG_LEVEL_VERBOSE,
230 "Couldn't find a public key at '%s', use cf-key to get one (fopen: %s)",
231 pubkeyfile != NULL ? pubkeyfile : pub_key_path, GetErrorStr());
232 free(pubkeyfile);
233 return false;
234 }
235
236 if (pub_key == NULL)
237 {
238 /* if no place to store the public key was specified, use the
239 * global variable PUBKEY */
240 pub_key = &PUBKEY;
241 }
242 if (*pub_key != NULL)
243 {
244 DESTROY_AND_NULL(RSA_free, *pub_key);
245 }
246 *pub_key = PEM_read_RSAPublicKey(fp, NULL, NULL, (void*) priv_passphrase);
247 if (*pub_key == NULL)
248 {
249 Log(LOG_LEVEL_ERR,
250 "Error reading public key at '%s'. (PEM_read_RSAPublicKey: %s)",
251 pubkeyfile, CryptoLastErrorString());
252 fclose(fp);
253 free(pubkeyfile);
254 return false;
255 }
256
257 Log(LOG_LEVEL_VERBOSE, "Loaded public key '%s'", pubkeyfile);
258 free(pubkeyfile);
259 fclose(fp);
260 }
261
262 if (*pub_key != NULL)
263 {
264 const BIGNUM *n, *e;
265 RSA_get0_key(*pub_key, &n, &e, NULL);
266 if ((BN_num_bits(e) < 2) || (!BN_is_odd(e)))
267 {
268 Log(LOG_LEVEL_ERR, "The public key RSA exponent is too small or not odd");
269 return false;
270 }
271 }
272
273 return true;
274 }
275
PolicyHubUpdateKeys(const char * policy_server)276 void PolicyHubUpdateKeys(const char *policy_server)
277 {
278 if (GetAmPolicyHub() && PUBKEY != NULL)
279 {
280 unsigned char digest[EVP_MAX_MD_SIZE + 1];
281 const char* const workdir = GetWorkDir();
282
283 char dst_public_key_filename[CF_BUFSIZE] = "";
284 {
285 char buffer[CF_HOSTKEY_STRING_SIZE];
286 HashPubKey(PUBKEY, digest, CF_DEFAULT_DIGEST);
287 snprintf(dst_public_key_filename, sizeof(dst_public_key_filename),
288 "%s/ppkeys/%s-%s.pub",
289 workdir, "root",
290 HashPrintSafe(buffer, sizeof(buffer), digest,
291 CF_DEFAULT_DIGEST, true));
292 MapName(dst_public_key_filename);
293 }
294
295 struct stat sb;
296 if ((stat(dst_public_key_filename, &sb) == -1))
297 {
298 char src_public_key_filename[CF_BUFSIZE] = "";
299 snprintf(src_public_key_filename, CF_MAXVARSIZE, "%s/ppkeys/localhost.pub", workdir);
300 MapName(src_public_key_filename);
301
302 // copy localhost.pub to root-HASH.pub on policy server
303 if (!LinkOrCopy(src_public_key_filename, dst_public_key_filename, false))
304 {
305 Log(LOG_LEVEL_ERR, "Unable to copy policy server's own public key from '%s' to '%s'", src_public_key_filename, dst_public_key_filename);
306 }
307
308 if (policy_server)
309 {
310 LastSaw(policy_server, digest, LAST_SEEN_ROLE_CONNECT);
311 }
312 }
313 }
314 }
315
316 /*********************************************************************/
317
318 /**
319 * @brief Search for a key given an IP address, by getting the
320 * key hash value from lastseen db.
321 * @return NULL if the key was not found in any form.
322 */
HavePublicKeyByIP(const char * username,const char * ipaddress)323 RSA *HavePublicKeyByIP(const char *username, const char *ipaddress)
324 {
325 char hash[CF_HOSTKEY_STRING_SIZE];
326
327 /* Get the key hash for that address from lastseen db. */
328 bool found = Address2Hostkey(hash, sizeof(hash), ipaddress);
329
330 /* If not found, by passing "" as digest, we effectively look only for
331 * the old-style key file, e.g. root-1.2.3.4.pub. */
332 return HavePublicKey(username, ipaddress,
333 found ? hash : "");
334 }
335
336 static const char *const pub_passphrase = "public";
337
338 /**
339 * @brief Search for a key:
340 * 1. username-hash.pub
341 * 2. username-ip.pub
342 * @return NULL if key not found in any form
343 */
HavePublicKey(const char * username,const char * ipaddress,const char * digest)344 RSA *HavePublicKey(const char *username, const char *ipaddress, const char *digest)
345 {
346 char keyname[CF_MAXVARSIZE], newname[CF_BUFSIZE], oldname[CF_BUFSIZE];
347 struct stat statbuf;
348 RSA *newkey = NULL;
349 const char* const workdir = GetWorkDir();
350
351 snprintf(keyname, CF_MAXVARSIZE, "%s-%s", username, digest);
352
353 snprintf(newname, CF_BUFSIZE, "%s/ppkeys/%s.pub", workdir, keyname);
354 MapName(newname);
355
356 if (stat(newname, &statbuf) == -1)
357 {
358 Log(LOG_LEVEL_VERBOSE, "Did not find new key format '%s'", newname);
359
360 snprintf(oldname, CF_BUFSIZE, "%s/ppkeys/%s-%s.pub",
361 workdir, username, ipaddress);
362 MapName(oldname);
363 Log(LOG_LEVEL_VERBOSE, "Trying old style '%s'", oldname);
364
365 if (stat(oldname, &statbuf) == -1)
366 {
367 Log(LOG_LEVEL_DEBUG, "Did not have old-style key '%s'", oldname);
368 return NULL;
369 }
370
371 if (strlen(digest) > 0)
372 {
373 Log(LOG_LEVEL_INFO, "Renaming old key from '%s' to '%s'", oldname, newname);
374
375 if (rename(oldname, newname) != 0)
376 {
377 Log(LOG_LEVEL_ERR, "Could not rename from old key format '%s' to new '%s'. (rename: %s)", oldname, newname, GetErrorStr());
378 }
379 }
380 else
381 {
382 /* We don't know the digest (e.g. because we are a client and have
383 no lastseen-map yet), so we're using old file format
384 (root-IP.pub). */
385 Log(LOG_LEVEL_VERBOSE,
386 "We have no digest yet, using old keyfile name: %s",
387 oldname);
388 snprintf(newname, sizeof(newname), "%s", oldname);
389 }
390 }
391
392 FILE *fp = safe_fopen(newname, "r");
393 if (fp == NULL)
394 {
395 Log(LOG_LEVEL_ERR, "Couldn't open public key file '%s' (fopen: %s)",
396 newname, GetErrorStr());
397 return NULL;
398 }
399
400 if ((newkey = PEM_read_RSAPublicKey(fp, NULL, NULL,
401 (void *)pub_passphrase)) == NULL)
402 {
403 Log(LOG_LEVEL_ERR,
404 "Error reading public key from '%s' (PEM_read_RSAPublicKey: %s)",
405 newname, CryptoLastErrorString());
406 fclose(fp);
407 return NULL;
408 }
409
410 fclose(fp);
411
412 {
413 const BIGNUM *n, *e;
414 RSA_get0_key(newkey, &n, &e, NULL);
415 if ((BN_num_bits(e) < 2) || (!BN_is_odd(e)))
416 {
417 Log(LOG_LEVEL_ERR, "RSA Exponent too small or not odd for key: %s",
418 newname);
419 RSA_free(newkey);
420 return NULL;
421 }
422 }
423
424 return newkey;
425 }
426
427 /*********************************************************************/
428
SavePublicKey(const char * user,const char * digest,const RSA * key)429 bool SavePublicKey(const char *user, const char *digest, const RSA *key)
430 {
431 char keyname[CF_MAXVARSIZE], filename[CF_BUFSIZE];
432 struct stat statbuf;
433 int ret;
434
435 ret = snprintf(keyname, sizeof(keyname), "%s-%s", user, digest);
436 if (ret < 0)
437 {
438 Log(LOG_LEVEL_ERR, "snprintf failed: %s", GetErrorStr());
439 return false;
440 }
441 else if ((unsigned long) ret >= sizeof(keyname))
442 {
443 Log(LOG_LEVEL_ERR, "USERNAME-KEY (%s-%s) string too long!",
444 user, digest);
445 return false;
446 }
447
448 ret = snprintf(filename, sizeof(filename), "%s/ppkeys/%s.pub",
449 GetWorkDir(), keyname);
450 if (ret < 0)
451 {
452 Log(LOG_LEVEL_ERR, "snprintf failed: %s", GetErrorStr());
453 return false;
454 }
455 else if ((unsigned long) ret >= sizeof(filename))
456 {
457 Log(LOG_LEVEL_ERR, "Filename too long!");
458 return false;
459 }
460
461 MapName(filename);
462 if (stat(filename, &statbuf) != -1)
463 {
464 Log(LOG_LEVEL_VERBOSE,
465 "Public key file '%s' already exists, not rewriting",
466 filename);
467 return true;
468 }
469
470 Log(LOG_LEVEL_VERBOSE, "Saving public key to file '%s'", filename);
471
472 FILE *fp = safe_fopen_create_perms(filename, "w", CF_PERMS_DEFAULT);
473 if (fp == NULL)
474 {
475 Log(LOG_LEVEL_ERR, "Unable to write a public key '%s'. (fopen: %s)", filename, GetErrorStr());
476 return false;
477 }
478
479 if (!PEM_write_RSAPublicKey(fp, key))
480 {
481 Log(LOG_LEVEL_ERR,
482 "Error saving public key to '%s'. (PEM_write_RSAPublicKey: %s)",
483 filename, CryptoLastErrorString());
484 fclose(fp);
485 return false;
486 }
487
488 fclose(fp);
489 return true;
490 }
491
LoadPublicKey(const char * filename)492 RSA *LoadPublicKey(const char *filename)
493 {
494 FILE *fp;
495 RSA *key;
496 const BIGNUM *n, *e;
497
498 fp = safe_fopen(filename, "r");
499 if (fp == NULL)
500 {
501 Log(LOG_LEVEL_ERR, "Cannot open public key file '%s' (fopen: %s)", filename, GetErrorStr());
502 return NULL;
503 };
504
505 if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL,
506 (void *)priv_passphrase)) == NULL)
507 {
508 Log(LOG_LEVEL_ERR,
509 "Error while reading public key '%s' (PEM_read_RSAPublicKey: %s)",
510 filename,
511 CryptoLastErrorString());
512 fclose(fp);
513 return NULL;
514 };
515
516 fclose(fp);
517
518 RSA_get0_key(key, &n, &e, NULL);
519
520 if (BN_num_bits(e) < 2 || !BN_is_odd(e))
521 {
522 Log(LOG_LEVEL_ERR, "Error while reading public key '%s' - RSA Exponent is too small or not odd. (BN_num_bits: %s)",
523 filename, GetErrorStr());
524 return NULL;
525 };
526
527 return key;
528 }
529
530 /** Return a string with the printed digest of the given key file,
531 or NULL if an error occurred. */
LoadPubkeyDigest(const char * filename)532 char *LoadPubkeyDigest(const char *filename)
533 {
534 unsigned char digest[EVP_MAX_MD_SIZE + 1];
535 RSA *key = NULL;
536 char *buffer = xmalloc(CF_HOSTKEY_STRING_SIZE);
537
538 key = LoadPublicKey(filename);
539 if (key == NULL)
540 {
541 return NULL;
542 }
543
544 HashPubKey(key, digest, CF_DEFAULT_DIGEST);
545 HashPrintSafe(buffer, CF_HOSTKEY_STRING_SIZE,
546 digest, CF_DEFAULT_DIGEST, true);
547 RSA_free(key);
548 return buffer;
549 }
550
551 /** Return a string with the printed digest of the given key file. */
GetPubkeyDigest(RSA * pubkey)552 char *GetPubkeyDigest(RSA *pubkey)
553 {
554 unsigned char digest[EVP_MAX_MD_SIZE + 1];
555 char *buffer = xmalloc(CF_HOSTKEY_STRING_SIZE);
556
557 HashPubKey(pubkey, digest, CF_DEFAULT_DIGEST);
558 HashPrintSafe(buffer, CF_HOSTKEY_STRING_SIZE,
559 digest, CF_DEFAULT_DIGEST, true);
560 return buffer;
561 }
562
563
564 /**
565 * Trust the given key. If #ipaddress is not NULL, then also
566 * update the "last seen" database. The IP address is required for
567 * trusting a server key (on the client); it is -currently- optional
568 * for trusting a client key (on the server).
569 */
TrustKey(const char * filename,const char * ipaddress,const char * username)570 bool TrustKey(const char *filename, const char *ipaddress, const char *username)
571 {
572 RSA* key;
573 char *digest;
574
575 key = LoadPublicKey(filename);
576 if (key == NULL)
577 {
578 return false;
579 }
580
581 digest = GetPubkeyDigest(key);
582 if (digest == NULL)
583 {
584 RSA_free(key);
585 return false;
586 }
587
588 if (ipaddress != NULL)
589 {
590 Log(LOG_LEVEL_VERBOSE,
591 "Adding a CONNECT entry in lastseen db: IP '%s', key '%s'",
592 ipaddress, digest);
593 LastSaw1(ipaddress, digest, LAST_SEEN_ROLE_CONNECT);
594 }
595
596 bool ret = SavePublicKey(username, digest, key);
597 RSA_free(key);
598 free(digest);
599
600 return ret;
601 }
602
EncryptString(char * out,size_t out_size,const char * in,int plainlen,char type,unsigned char * key)603 int EncryptString(char *out, size_t out_size, const char *in, int plainlen,
604 char type, unsigned char *key)
605 {
606 int cipherlen = 0, tmplen;
607 unsigned char iv[32] =
608 { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
609
610 if (key == NULL)
611 ProgrammingError("EncryptString: session key == NULL");
612
613 size_t max_ciphertext_size = CipherTextSizeMax(CfengineCipher(type), plainlen);
614
615 if(max_ciphertext_size > out_size)
616 {
617 ProgrammingError("EncryptString: output buffer too small: max_ciphertext_size (%zd) > out_size (%zd)",
618 max_ciphertext_size, out_size);
619 }
620
621 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
622 EVP_EncryptInit_ex(ctx, CfengineCipher(type), NULL, key, iv);
623
624 if (!EVP_EncryptUpdate(ctx, out, &cipherlen, in, plainlen))
625 {
626 EVP_CIPHER_CTX_free(ctx);
627 return -1;
628 }
629
630 if (!EVP_EncryptFinal_ex(ctx, out + cipherlen, &tmplen))
631 {
632 EVP_CIPHER_CTX_free(ctx);
633 return -1;
634 }
635
636 cipherlen += tmplen;
637
638 if (cipherlen < 0)
639 {
640 ProgrammingError("EncryptString: chipherlen (%d) < 0", cipherlen);
641 }
642 else if ((size_t) cipherlen > max_ciphertext_size)
643 {
644 ProgrammingError("EncryptString: too large ciphertext written: cipherlen (%d) > max_ciphertext_size (%zd)",
645 cipherlen, max_ciphertext_size);
646 }
647
648 EVP_CIPHER_CTX_free(ctx);
649 return cipherlen;
650 }
651
CipherBlockSizeBytes(const EVP_CIPHER * cipher)652 size_t CipherBlockSizeBytes(const EVP_CIPHER *cipher)
653 {
654 return EVP_CIPHER_block_size(cipher);
655 }
656
CipherTextSizeMax(const EVP_CIPHER * cipher,size_t plaintext_size)657 size_t CipherTextSizeMax(const EVP_CIPHER* cipher, size_t plaintext_size)
658 {
659 // see man EVP_DecryptUpdate() and EVP_DecryptFinal_ex()
660 size_t padding_size = (CipherBlockSizeBytes(cipher) * 2) - 1;
661
662 // check for potential integer overflow, leave some buffer
663 if(plaintext_size > SIZE_MAX - padding_size)
664 {
665 ProgrammingError("CipherTextSizeMax: plaintext_size is too large (%zu)",
666 plaintext_size);
667 }
668
669 return plaintext_size + padding_size;
670 }
671
PlainTextSizeMax(const EVP_CIPHER * cipher,size_t ciphertext_size)672 size_t PlainTextSizeMax(const EVP_CIPHER* cipher, size_t ciphertext_size)
673 {
674 // see man EVP_DecryptUpdate() and EVP_DecryptFinal_ex()
675 size_t padding_size = (CipherBlockSizeBytes(cipher) * 2);
676
677 // check for potential integer overflow, leave some buffer
678 if(ciphertext_size > SIZE_MAX - padding_size)
679 {
680 ProgrammingError("PlainTextSizeMax: ciphertext_size is too large (%zu)",
681 ciphertext_size);
682 }
683
684 return ciphertext_size + padding_size;
685 }
686
687 /*********************************************************************/
688
DecryptString(char * out,size_t out_size,const char * in,int cipherlen,char type,unsigned char * key)689 int DecryptString(char *out, size_t out_size, const char *in, int cipherlen,
690 char type, unsigned char *key)
691 {
692 int plainlen = 0, tmplen;
693 unsigned char iv[32] =
694 { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
695
696 if (key == NULL)
697 ProgrammingError("DecryptString: session key == NULL");
698
699 size_t max_plaintext_size = PlainTextSizeMax(CfengineCipher(type), cipherlen);
700
701 if(max_plaintext_size > out_size)
702 {
703 ProgrammingError("DecryptString: output buffer too small: max_plaintext_size (%zd) > out_size (%zd)",
704 max_plaintext_size, out_size);
705 }
706
707 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
708 EVP_DecryptInit_ex(ctx, CfengineCipher(type), NULL, key, iv);
709
710 if (!EVP_DecryptUpdate(ctx, out, &plainlen, in, cipherlen))
711 {
712 Log(LOG_LEVEL_ERR, "Failed to decrypt string");
713 EVP_CIPHER_CTX_free(ctx);
714 return -1;
715 }
716
717 if (!EVP_DecryptFinal_ex(ctx, out + plainlen, &tmplen))
718 {
719 unsigned long err = ERR_get_error();
720
721 Log(LOG_LEVEL_ERR, "Failed to decrypt at final of cipher length %d. (EVP_DecryptFinal_ex: %s)", cipherlen, ERR_error_string(err, NULL));
722 EVP_CIPHER_CTX_free(ctx);
723 return -1;
724 }
725
726 plainlen += tmplen;
727
728 if (plainlen < 0)
729 {
730 ProgrammingError("DecryptString: plainlen (%d) < 0", plainlen);
731 }
732 if ((size_t) plainlen > max_plaintext_size)
733 {
734 ProgrammingError("DecryptString: too large plaintext written: plainlen (%d) > max_plaintext_size (%zd)",
735 plainlen, max_plaintext_size);
736 }
737
738 EVP_CIPHER_CTX_free(ctx);
739 return plainlen;
740 }
741
742 /*********************************************************************/
743
DebugBinOut(char * buffer,int len,char * comment)744 void DebugBinOut(char *buffer, int len, char *comment)
745 {
746 unsigned char *sp;
747 char buf[CF_BUFSIZE];
748 char hexStr[3]; // one byte as hex
749
750 if (len < 0)
751 {
752 Log(LOG_LEVEL_ERR, "Debug binary print negative len param (len = %d)", len);
753 }
754 else if ((unsigned long) len >= (sizeof(buf) / 2)) // hex uses two chars per byte
755 {
756 Log(LOG_LEVEL_DEBUG, "Debug binary print is too large (len = %d)", len);
757 return;
758 }
759
760 memset(buf, 0, sizeof(buf));
761
762 for (sp = buffer; sp < (unsigned char *) (buffer + len); sp++)
763 {
764 xsnprintf(hexStr, sizeof(hexStr), "%2.2x", (int) *sp);
765 strcat(buf, hexStr);
766 }
767
768 Log(LOG_LEVEL_VERBOSE, "BinaryBuffer, %d bytes, comment '%s', buffer '%s'", len, comment, buf);
769 }
770
PublicKeyFile(const char * workdir)771 char *PublicKeyFile(const char *workdir)
772 {
773 char *keyfile;
774 xasprintf(&keyfile,
775 "%s" FILE_SEPARATOR_STR "ppkeys" FILE_SEPARATOR_STR "localhost.pub", workdir);
776 return keyfile;
777 }
778
PrivateKeyFile(const char * workdir)779 char *PrivateKeyFile(const char *workdir)
780 {
781 char *keyfile;
782 xasprintf(&keyfile,
783 "%s" FILE_SEPARATOR_STR "ppkeys" FILE_SEPARATOR_STR "localhost.priv", workdir);
784 return keyfile;
785 }
786
787
788 /*********************************************************************
789 * Functions for threadsafe OpenSSL usage *
790 * Only pthread support - we don't create threads with any other API *
791 *********************************************************************/
792
793 static pthread_mutex_t *cf_openssl_locks = NULL;
794
795
796 #ifndef __MINGW32__
797 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER)
ThreadId_callback(void)798 unsigned long ThreadId_callback(void)
799 {
800 return (unsigned long) pthread_self();
801 }
802 #endif
803 #endif
804
805 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER)
806
OpenSSLLock_callback(int mode,int index,char * file,int line)807 static void OpenSSLLock_callback(int mode, int index, char *file, int line)
808 {
809 if (mode & CRYPTO_LOCK)
810 {
811 int ret = pthread_mutex_lock(&(cf_openssl_locks[index]));
812 if (ret != 0)
813 {
814 Log(LOG_LEVEL_ERR,
815 "OpenSSL locking failure at %s:%d! (pthread_mutex_lock: %s)",
816 file, line, GetErrorStrFromCode(ret));
817 }
818 }
819 else
820 {
821 int ret = pthread_mutex_unlock(&(cf_openssl_locks[index]));
822 if (ret != 0)
823 {
824 Log(LOG_LEVEL_ERR,
825 "OpenSSL locking failure at %s:%d! (pthread_mutex_unlock: %s)",
826 file, line, GetErrorStrFromCode(ret));
827 }
828 }
829 }
830
831 #endif // Callback only for openssl < 1.1.0
832
SetupOpenSSLThreadLocks(void)833 static void SetupOpenSSLThreadLocks(void)
834 {
835 const int num_locks = CRYPTO_num_locks();
836 assert(cf_openssl_locks == NULL);
837 cf_openssl_locks = xmalloc(num_locks * sizeof(*cf_openssl_locks));
838
839 for (int i = 0; i < num_locks; i++)
840 {
841 pthread_mutexattr_t attr;
842 pthread_mutexattr_init(&attr);
843 int ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
844 if (ret != 0)
845 {
846 Log(LOG_LEVEL_ERR,
847 "Failed to use error-checking mutexes for openssl,"
848 " falling back to normal ones (pthread_mutexattr_settype: %s)",
849 GetErrorStrFromCode(ret));
850 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
851 }
852 ret = pthread_mutex_init(&cf_openssl_locks[i], &attr);
853 if (ret != 0)
854 {
855 Log(LOG_LEVEL_CRIT,
856 "Failed to use initialise mutexes for openssl"
857 " (pthread_mutex_init: %s)!",
858 GetErrorStrFromCode(ret));
859 }
860 pthread_mutexattr_destroy(&attr);
861 }
862
863 #ifndef __MINGW32__
864 CRYPTO_set_id_callback((unsigned long (*)())ThreadId_callback);
865 #endif
866 // This is a no-op macro for OpenSSL >= 1.1.0
867 // The callback function is not used (or defined) then
868 CRYPTO_set_locking_callback((void (*)())OpenSSLLock_callback);
869 }
870
CleanupOpenSSLThreadLocks(void)871 static void CleanupOpenSSLThreadLocks(void)
872 {
873 const int numLocks = CRYPTO_num_locks();
874 CRYPTO_set_locking_callback(NULL);
875 #ifndef __MINGW32__
876 CRYPTO_set_id_callback(NULL);
877 #endif
878
879 for (int i = 0; i < numLocks; i++)
880 {
881 pthread_mutex_destroy(&(cf_openssl_locks[i]));
882 }
883
884 free(cf_openssl_locks);
885 cf_openssl_locks = NULL;
886 }
887