]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/creds-util.c
creds-util: refuse unexpected key types explicitly
[thirdparty/systemd.git] / src / shared / creds-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/file.h>
4
5 #if HAVE_OPENSSL
6 #include <openssl/err.h>
7 #endif
8
9 #include "sd-id128.h"
10
11 #include "blockdev-util.h"
12 #include "chattr-util.h"
13 #include "creds-util.h"
14 #include "env-util.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "fs-util.h"
18 #include "io-util.h"
19 #include "memory-util.h"
20 #include "mkdir.h"
21 #include "openssl-util.h"
22 #include "path-util.h"
23 #include "random-util.h"
24 #include "sparse-endian.h"
25 #include "stat-util.h"
26 #include "tpm2-util.h"
27 #include "virt.h"
28
29 bool credential_name_valid(const char *s) {
30 /* We want that credential names are both valid in filenames (since that's our primary way to pass
31 * them around) and as fdnames (which is how we might want to pass them around eventually) */
32 return filename_is_valid(s) && fdname_is_valid(s);
33 }
34
35 int get_credentials_dir(const char **ret) {
36 const char *e;
37
38 assert(ret);
39
40 e = secure_getenv("CREDENTIALS_DIRECTORY");
41 if (!e)
42 return -ENXIO;
43
44 if (!path_is_absolute(e) || !path_is_normalized(e))
45 return -EINVAL;
46
47 *ret = e;
48 return 0;
49 }
50
51 int read_credential(const char *name, void **ret, size_t *ret_size) {
52 _cleanup_free_ char *fn = NULL;
53 const char *d;
54 int r;
55
56 assert(ret);
57
58 if (!credential_name_valid(name))
59 return -EINVAL;
60
61 r = get_credentials_dir(&d);
62 if (r < 0)
63 return r;
64
65 fn = path_join(d, name);
66 if (!fn)
67 return -ENOMEM;
68
69 return read_full_file_full(
70 AT_FDCWD, fn,
71 UINT64_MAX, SIZE_MAX,
72 READ_FULL_FILE_SECURE,
73 NULL,
74 (char**) ret, ret_size);
75 }
76
77 #if HAVE_OPENSSL
78
79 #define CREDENTIAL_HOST_SECRET_SIZE 4096
80
81 static const sd_id128_t credential_app_id =
82 SD_ID128_MAKE(d3,ac,ec,ba,0d,ad,4c,df,b8,c9,38,15,28,93,6c,58);
83
84 struct credential_host_secret_format {
85 /* The hashed machine ID of the machine this belongs to. Why? We want to ensure that each machine
86 * gets its own secret, even if people forget to flush out this secret file. Hence we bind it to the
87 * machine ID, for which there's hopefully a better chance it will be flushed out. We use a hashed
88 * machine ID instead of the literal one, because it's trivial to, and it might be a good idea not
89 * being able to directly associate a secret key file with a host. */
90 sd_id128_t machine_id;
91
92 /* The actual secret key */
93 uint8_t data[CREDENTIAL_HOST_SECRET_SIZE];
94 } _packed_;
95
96 static int make_credential_host_secret(
97 int dfd,
98 const sd_id128_t machine_id,
99 const char *fn,
100 void **ret_data,
101 size_t *ret_size) {
102
103 struct credential_host_secret_format buf;
104 _cleanup_free_ char *t = NULL;
105 _cleanup_close_ int fd = -1;
106 int r;
107
108 assert(dfd >= 0);
109 assert(fn);
110
111 fd = openat(dfd, ".", O_CLOEXEC|O_WRONLY|O_TMPFILE, 0400);
112 if (fd < 0) {
113 log_debug_errno(errno, "Failed to create temporary credential file with O_TMPFILE, proceeding without: %m");
114
115 if (asprintf(&t, "credential.secret.%016" PRIx64, random_u64()) < 0)
116 return -ENOMEM;
117
118 fd = openat(dfd, t, O_CLOEXEC|O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0400);
119 if (fd < 0)
120 return -errno;
121 }
122
123 r = chattr_secret(fd, 0);
124 if (r < 0)
125 log_debug_errno(r, "Failed to set file attributes for secrets file, ignoring: %m");
126
127 buf = (struct credential_host_secret_format) {
128 .machine_id = machine_id,
129 };
130
131 r = genuine_random_bytes(buf.data, sizeof(buf.data), RANDOM_BLOCK);
132 if (r < 0)
133 goto finish;
134
135 r = loop_write(fd, &buf, sizeof(buf), false);
136 if (r < 0)
137 goto finish;
138
139 if (fsync(fd) < 0) {
140 r = -errno;
141 goto finish;
142 }
143
144 if (t) {
145 r = rename_noreplace(dfd, t, dfd, fn);
146 if (r < 0)
147 goto finish;
148
149 t = mfree(t);
150 } else if (linkat(fd, "", dfd, fn, AT_EMPTY_PATH) < 0) {
151 r = -errno;
152 goto finish;
153 }
154
155 if (fsync(dfd) < 0) {
156 r = -errno;
157 goto finish;
158 }
159
160 if (ret_data) {
161 void *copy;
162
163 copy = memdup(buf.data, sizeof(buf.data));
164 if (!copy) {
165 r = -ENOMEM;
166 goto finish;
167 }
168
169 *ret_data = copy;
170 }
171
172 if (ret_size)
173 *ret_size = sizeof(buf.data);
174
175 r = 0;
176
177 finish:
178 if (t && unlinkat(dfd, t, 0) < 0)
179 log_debug_errno(errno, "Failed to remove temporary credential key: %m");
180
181 explicit_bzero_safe(&buf, sizeof(buf));
182 return r;
183 }
184
185 int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size) {
186 _cleanup_free_ char *_dirname = NULL, *_filename = NULL;
187 _cleanup_close_ int dfd = -1;
188 sd_id128_t machine_id;
189 const char *dirname, *filename;
190 int r;
191
192 r = sd_id128_get_machine_app_specific(credential_app_id, &machine_id);
193 if (r < 0)
194 return r;
195
196 const char *e = secure_getenv("SYSTEMD_CREDENTIAL_SECRET");
197 if (e) {
198 if (!path_is_normalized(e))
199 return -EINVAL;
200 if (!path_is_absolute(e))
201 return -EINVAL;
202
203 r = path_extract_directory(e, &_dirname);
204 if (r < 0)
205 return r;
206
207 r = path_extract_filename(e, &_filename);
208 if (r < 0)
209 return r;
210
211 dirname = _dirname;
212 filename = _filename;
213 } else {
214 dirname = "/var/lib/systemd";
215 filename = "credential.secret";
216 }
217
218 mkdir_parents(dirname, 0755);
219 dfd = open_mkdir_at(AT_FDCWD, dirname, O_CLOEXEC, 0755);
220 if (dfd < 0)
221 return log_debug_errno(dfd, "Failed to create or open directory '%s': %m", dirname);
222
223 if (FLAGS_SET(flags, CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS)) {
224 r = fd_is_temporary_fs(dfd);
225 if (r < 0)
226 return log_debug_errno(r, "Failed to check directory '%s': %m", dirname);
227 if (r > 0)
228 return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
229 "Directory '%s' is on a temporary file system, refusing.", dirname);
230 }
231
232 for (unsigned attempt = 0;; attempt++) {
233 _cleanup_(erase_and_freep) struct credential_host_secret_format *f = NULL;
234 _cleanup_close_ int fd = -1;
235 size_t l = 0;
236 ssize_t n = 0;
237 struct stat st;
238
239 if (attempt >= 3) /* Somebody is playing games with us */
240 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
241 "All attempts to create secret store in %s failed.", dirname);
242
243 fd = openat(dfd, filename, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW);
244 if (fd < 0) {
245 if (errno != ENOENT || !FLAGS_SET(flags, CREDENTIAL_SECRET_GENERATE))
246 return log_debug_errno(errno,
247 "Failed to open %s/%s: %m", dirname, filename);
248
249
250 r = make_credential_host_secret(dfd, machine_id, filename, ret, ret_size);
251 if (r == -EEXIST) {
252 log_debug_errno(r, "Credential secret %s/%s appeared while we were creating it, rereading.",
253 dirname, filename);
254 continue;
255 }
256 if (r < 0)
257 return log_debug_errno(r, "Failed to create credential secret %s/%s: %m",
258 dirname, filename);
259
260 return 0;
261 }
262
263 if (fstat(fd, &st) < 0)
264 return log_debug_errno(errno, "Failed to stat %s/%s: %m", dirname, filename);
265
266 r = stat_verify_regular(&st);
267 if (r < 0)
268 return log_debug_errno(r, "%s/%s is not a regular file: %m", dirname, filename);
269 if (st.st_nlink == 0) /* Deleted by now, try again */
270 continue;
271 if (st.st_nlink > 1)
272 /* Our deletion check won't work if hardlinked somewhere else */
273 return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
274 "%s/%s has too many links, refusing.",
275 dirname, filename);
276 if ((st.st_mode & 07777) != 0400)
277 /* Don't use file if not 0400 access mode */
278 return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
279 "%s/%s has permissive access mode, refusing.",
280 dirname, filename);
281 l = st.st_size;
282 if (l < offsetof(struct credential_host_secret_format, data) + 1)
283 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
284 "%s/%s is too small, refusing.", dirname, filename);
285 if (l > 16*1024*1024)
286 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG),
287 "%s/%s is too big, refusing.", dirname, filename);
288
289 f = malloc(l+1);
290 if (!f)
291 return log_oom_debug();
292
293 n = read(fd, f, l+1);
294 if (n < 0)
295 return log_debug_errno(errno,
296 "Failed to read %s/%s: %m", dirname, filename);
297 if ((size_t) n != l) /* What? The size changed? */
298 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
299 "Failed to read %s/%s: %m", dirname, filename);
300
301 if (sd_id128_equal(machine_id, f->machine_id)) {
302 size_t sz;
303
304 if (FLAGS_SET(flags, CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED)) {
305 r = fd_is_encrypted(fd);
306 if (r < 0)
307 log_debug_errno(r, "Failed to determine if credential secret file '%s/%s' is encrypted.",
308 dirname, filename);
309 else if (r == 0)
310 log_warning("Credential secret file '%s/%s' is not located on encrypted media, using anyway.",
311 dirname, filename);
312 }
313
314 sz = l - offsetof(struct credential_host_secret_format, data);
315 assert(sz > 0);
316
317 if (ret) {
318 void *copy;
319
320 assert(sz <= sizeof(f->data)); /* Ensure we don't read past f->data bounds */
321
322 copy = memdup(f->data, sz);
323 if (!copy)
324 return log_oom_debug();
325
326 *ret = copy;
327 }
328
329 if (ret_size)
330 *ret_size = sz;
331
332 return 0;
333 }
334
335 /* Hmm, this secret is from somewhere else. Let's delete the file. Let's first acquire a lock
336 * to ensure we are the only ones accessing the file while we delete it. */
337
338 if (flock(fd, LOCK_EX) < 0)
339 return log_debug_errno(errno,
340 "Failed to flock %s/%s: %m", dirname, filename);
341
342 /* Before we delete it check that the file is still linked into the file system */
343 if (fstat(fd, &st) < 0)
344 return log_debug_errno(errno, "Failed to stat %s/%s: %m", dirname, filename);
345 if (st.st_nlink == 0) /* Already deleted by now? */
346 continue;
347 if (st.st_nlink != 1) /* Safety check, someone is playing games with us */
348 return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
349 "%s/%s unexpectedly has too many links.",
350 dirname, filename);
351 if (unlinkat(dfd, filename, 0) < 0)
352 return log_debug_errno(errno, "Failed to unlink %s/%s: %m", dirname, filename);
353
354 /* And now try again */
355 }
356 }
357
358 /* Construction is like this:
359 *
360 * A symmetric encryption key is derived from:
361 *
362 * 1. Either the "host" key (a key stored in /var/lib/credential.secret)
363 *
364 * 2. A key generated by letting the TPM2 calculate an HMAC hash of some nonce we pass to it, keyed
365 * by a key derived from its internal seed key.
366 *
367 * 3. The concatenation of the above.
368 *
369 * The above is hashed with SHA256 which is then used as encryption key for AES256-GCM. The encrypted
370 * credential is a short (unencrypted) header describing which of the three keys to use, the IV to use for
371 * AES256-GCM and some more meta information (sizes of certain objects) that is strictly speaking redundant,
372 * but kinda nice to have since we can have a more generic parser. If the TPM2 key is used this is followed
373 * by another (unencrypted) header, with information about the TPM2 policy used (specifically: the PCR mask
374 * to bind against, and a hash of the resulting policy — the latter being redundant, but speeding up things a
375 * bit, since we can more quickly refuse PCR state), followed by a sealed/exported TPM2 HMAC key. This is
376 * then followed by the encrypted data, which begins with a metadata header (which contains validity
377 * timestamps as well as the credential name), followed by the actual credential payload. The file ends in
378 * the AES256-GCM tag. To make things simple, the AES256-GCM AAD covers the main and the TPM2 header in
379 * full. This means the whole file is either protected by AAD, or is ciphertext, or is the tag. No
380 * unprotected data is included.
381 */
382
383 struct _packed_ encrypted_credential_header {
384 sd_id128_t id;
385 le32_t key_size;
386 le32_t block_size;
387 le32_t iv_size;
388 le32_t tag_size;
389 uint8_t iv[];
390 /* Followed by NUL bytes until next 8 byte boundary */
391 };
392
393 struct _packed_ tpm2_credential_header {
394 le64_t pcr_mask; /* Note that the spec for PC Clients only mandates 24 PCRs, and that's what systems
395 * generally have. But keep the door open for more. */
396 le16_t pcr_bank; /* For now, either TPM2_ALG_SHA256 or TPM2_ALG_SHA1 */
397 le16_t primary_alg; /* Primary key algorithm (either TPM2_ALG_RSA or TPM2_ALG_ECC for now) */
398 le32_t blob_size;
399 le32_t policy_hash_size;
400 uint8_t policy_hash_and_blob[];
401 /* Followed by NUL bytes until next 8 byte boundary */
402 };
403
404 struct _packed_ metadata_credential_header {
405 le64_t timestamp;
406 le64_t not_after;
407 le32_t name_size;
408 char name[];
409 /* Followed by NUL bytes until next 8 byte boundary */
410 };
411
412 /* Some generic limit for parts of the encrypted credential for which we don't know the right size ahead of
413 * time, but where we are really sure it won't be larger than this. Should be larger than any possible IV,
414 * padding, tag size and so on. This is purely used for early filtering out of invalid sizes. */
415 #define CREDENTIAL_FIELD_SIZE_MAX (16U*1024U)
416
417 static int sha256_hash_host_and_tpm2_key(
418 const void *host_key,
419 size_t host_key_size,
420 const void *tpm2_key,
421 size_t tpm2_key_size,
422 uint8_t ret[static SHA256_DIGEST_LENGTH]) {
423
424 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md = NULL;
425 unsigned l;
426
427 assert(host_key_size == 0 || host_key);
428 assert(tpm2_key_size == 0 || tpm2_key);
429 assert(ret);
430
431 /* Combines the host key and the TPM2 HMAC hash into a SHA256 hash value we'll use as symmetric encryption key. */
432
433 md = EVP_MD_CTX_new();
434 if (!md)
435 return log_oom();
436
437 if (EVP_DigestInit_ex(md, EVP_sha256(), NULL) != 1)
438 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initial SHA256 context.");
439
440 if (host_key && EVP_DigestUpdate(md, host_key, host_key_size) != 1)
441 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to hash host key.");
442
443 if (tpm2_key && EVP_DigestUpdate(md, tpm2_key, tpm2_key_size) != 1)
444 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to hash TPM2 key.");
445
446 assert(EVP_MD_CTX_size(md) == SHA256_DIGEST_LENGTH);
447
448 if (EVP_DigestFinal_ex(md, ret, &l) != 1)
449 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to finalize SHA256 hash.");
450
451 assert(l == SHA256_DIGEST_LENGTH);
452 return 0;
453 }
454
455 int encrypt_credential_and_warn(
456 sd_id128_t with_key,
457 const char *name,
458 usec_t timestamp,
459 usec_t not_after,
460 const char *tpm2_device,
461 uint32_t tpm2_pcr_mask,
462 const void *input,
463 size_t input_size,
464 void **ret,
465 size_t *ret_size) {
466
467 _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL;
468 _cleanup_(erase_and_freep) void *host_key = NULL, *tpm2_key = NULL;
469 size_t host_key_size = 0, tpm2_key_size = 0, tpm2_blob_size = 0, tpm2_policy_hash_size = 0, output_size, p, ml;
470 _cleanup_free_ void *tpm2_blob = NULL, *tpm2_policy_hash = NULL, *iv = NULL, *output = NULL;
471 _cleanup_free_ struct metadata_credential_header *m = NULL;
472 uint16_t tpm2_pcr_bank = 0, tpm2_primary_alg = 0;
473 struct encrypted_credential_header *h;
474 int ksz, bsz, ivsz, tsz, added, r;
475 uint8_t md[SHA256_DIGEST_LENGTH];
476 const EVP_CIPHER *cc;
477 #if HAVE_TPM2
478 bool try_tpm2 = false;
479 #endif
480 sd_id128_t id;
481
482 assert(input || input_size == 0);
483 assert(ret);
484 assert(ret_size);
485
486 if (!sd_id128_in_set(with_key,
487 SD_ID128_NULL,
488 CRED_AES256_GCM_BY_HOST,
489 CRED_AES256_GCM_BY_TPM2_HMAC,
490 CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC))
491 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid key type: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(with_key));
492
493 if (name && !credential_name_valid(name))
494 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name);
495
496 if (not_after != USEC_INFINITY && timestamp != USEC_INFINITY && not_after < timestamp)
497 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before it is valid (" USEC_FMT " < " USEC_FMT ").", not_after, timestamp);
498
499 if (DEBUG_LOGGING) {
500 char buf[FORMAT_TIMESTAMP_MAX];
501
502 if (name)
503 log_debug("Including credential name '%s' in encrypted credential.", name);
504 if (timestamp != USEC_INFINITY)
505 log_debug("Including timestamp '%s' in encrypted credential.", format_timestamp(buf, sizeof(buf), timestamp));
506 if (not_after != USEC_INFINITY)
507 log_debug("Including not-after timestamp '%s' in encrypted credential.", format_timestamp(buf, sizeof(buf), not_after));
508 }
509
510 if (sd_id128_is_null(with_key) ||
511 sd_id128_in_set(with_key, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC)) {
512
513 r = get_credential_host_secret(
514 CREDENTIAL_SECRET_GENERATE|
515 CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED|
516 (sd_id128_is_null(with_key) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
517 &host_key,
518 &host_key_size);
519 if (r == -ENOMEDIUM && sd_id128_is_null(with_key))
520 log_debug_errno(r, "Credential host secret location on temporary file system, not using.");
521 else if (r < 0)
522 return log_error_errno(r, "Failed to determine local credential host secret: %m");
523 }
524
525 #if HAVE_TPM2
526 if (sd_id128_is_null(with_key)) {
527 /* If automatic mode is selected and we are running in a container, let's not try TPM2. OTOH
528 * if user picks TPM2 explicitly, let's always honour the request and try. */
529
530 r = detect_container();
531 if (r < 0)
532 log_debug_errno(r, "Failed to determine whether we are running in a container, ignoring: %m");
533 else if (r > 0)
534 log_debug("Running in container, not attempting to use TPM2.");
535
536 try_tpm2 = r <= 0;
537 }
538
539 if (try_tpm2 ||
540 sd_id128_in_set(with_key, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC)) {
541
542 r = tpm2_seal(tpm2_device,
543 tpm2_pcr_mask,
544 NULL,
545 &tpm2_key,
546 &tpm2_key_size,
547 &tpm2_blob,
548 &tpm2_blob_size,
549 &tpm2_policy_hash,
550 &tpm2_policy_hash_size,
551 &tpm2_pcr_bank,
552 &tpm2_primary_alg);
553 if (r < 0) {
554 if (!sd_id128_is_null(with_key))
555 return r;
556
557 log_debug_errno(r, "TPM2 sealing didn't work, not using: %m");
558 }
559
560 assert(tpm2_blob_size <= CREDENTIAL_FIELD_SIZE_MAX);
561 assert(tpm2_policy_hash_size <= CREDENTIAL_FIELD_SIZE_MAX);
562 }
563 #endif
564
565 if (sd_id128_is_null(with_key)) {
566 /* Let's settle the key type in auto mode now. */
567
568 if (host_key && tpm2_key)
569 id = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC;
570 else if (tpm2_key)
571 id = CRED_AES256_GCM_BY_TPM2_HMAC;
572 else if (host_key)
573 id = CRED_AES256_GCM_BY_HOST;
574 else
575 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
576 "TPM2 not available and host key located on temporary file system, no encryption key available.");
577 } else
578 id = with_key;
579
580 /* Let's now take the host key and the TPM2 key and hash it together, to use as encryption key for the data */
581 r = sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
582 if (r < 0)
583 return r;
584
585 assert_se(cc = EVP_aes_256_gcm());
586
587 ksz = EVP_CIPHER_key_length(cc);
588 assert(ksz == sizeof(md));
589
590 bsz = EVP_CIPHER_block_size(cc);
591 assert(bsz > 0);
592 assert((size_t) bsz <= CREDENTIAL_FIELD_SIZE_MAX);
593
594 ivsz = EVP_CIPHER_iv_length(cc);
595 if (ivsz > 0) {
596 assert((size_t) ivsz <= CREDENTIAL_FIELD_SIZE_MAX);
597
598 iv = malloc(ivsz);
599 if (!iv)
600 return log_oom();
601
602 r = genuine_random_bytes(iv, ivsz, RANDOM_BLOCK);
603 if (r < 0)
604 return log_error_errno(r, "Failed to acquired randomized IV: %m");
605 }
606
607 tsz = 16; /* FIXME: On OpenSSL 3 there is EVP_CIPHER_CTX_get_tag_length(), until then let's hardcode this */
608
609 context = EVP_CIPHER_CTX_new();
610 if (!context)
611 return log_error_errno(SYNTHETIC_ERRNO(ENOMEM), "Failed to allocate encryption object: %s",
612 ERR_error_string(ERR_get_error(), NULL));
613
614 if (EVP_EncryptInit_ex(context, cc, NULL, md, iv) != 1)
615 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize encryption context: %s",
616 ERR_error_string(ERR_get_error(), NULL));
617
618 /* Just an upper estimate */
619 output_size =
620 ALIGN8(offsetof(struct encrypted_credential_header, iv) + ivsz) +
621 ALIGN8(tpm2_key ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob_size + tpm2_policy_hash_size : 0) +
622 ALIGN8(offsetof(struct metadata_credential_header, name) + strlen_ptr(name)) +
623 input_size + 2U * (size_t) bsz +
624 tsz;
625
626 output = malloc0(output_size);
627 if (!output)
628 return log_oom();
629
630 h = (struct encrypted_credential_header*) output;
631 h->id = id;
632 h->block_size = htole32(bsz);
633 h->key_size = htole32(ksz);
634 h->tag_size = htole32(tsz);
635 h->iv_size = htole32(ivsz);
636 memcpy(h->iv, iv, ivsz);
637
638 p = ALIGN8(offsetof(struct encrypted_credential_header, iv) + ivsz);
639
640 if (tpm2_key) {
641 struct tpm2_credential_header *t;
642
643 t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
644 t->pcr_mask = htole64(tpm2_pcr_mask);
645 t->pcr_bank = htole16(tpm2_pcr_bank);
646 t->primary_alg = htole16(tpm2_primary_alg);
647 t->blob_size = htole32(tpm2_blob_size);
648 t->policy_hash_size = htole32(tpm2_policy_hash_size);
649 memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
650 memcpy(t->policy_hash_and_blob + tpm2_blob_size, tpm2_policy_hash, tpm2_policy_hash_size);
651
652 p += ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob_size + tpm2_policy_hash_size);
653 }
654
655 /* Pass the encrypted + TPM2 header as AAD */
656 if (EVP_EncryptUpdate(context, NULL, &added, output, p) != 1)
657 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to write AAD data: %s",
658 ERR_error_string(ERR_get_error(), NULL));
659
660 /* Now construct the metadata header */
661 ml = strlen_ptr(name);
662 m = malloc0(ALIGN8(offsetof(struct metadata_credential_header, name) + ml));
663 if (!m)
664 return log_oom();
665
666 m->timestamp = htole64(timestamp);
667 m->not_after = htole64(not_after);
668 m->name_size = htole32(ml);
669 memcpy_safe(m->name, name, ml);
670
671 /* And encrypt the metadata header */
672 if (EVP_EncryptUpdate(context, (uint8_t*) output + p, &added, (const unsigned char*) m, ALIGN8(offsetof(struct metadata_credential_header, name) + ml)) != 1)
673 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to encrypt metadata header: %s",
674 ERR_error_string(ERR_get_error(), NULL));
675
676 assert(added >= 0);
677 assert((size_t) added <= output_size - p);
678 p += added;
679
680 /* Then encrypt the plaintext */
681 if (EVP_EncryptUpdate(context, (uint8_t*) output + p, &added, input, input_size) != 1)
682 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to encrypt data: %s",
683 ERR_error_string(ERR_get_error(), NULL));
684
685 assert(added >= 0);
686 assert((size_t) added <= output_size - p);
687 p += added;
688
689 /* Finalize */
690 if (EVP_EncryptFinal_ex(context, (uint8_t*) output + p, &added) != 1)
691 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to finalize data encryption: %s",
692 ERR_error_string(ERR_get_error(), NULL));
693
694 assert(added >= 0);
695 assert((size_t) added <= output_size - p);
696 p += added;
697
698 assert(p <= output_size - tsz);
699
700 /* Append tag */
701 if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_GET_TAG, tsz, (uint8_t*) output + p) != 1)
702 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get tag: %s",
703 ERR_error_string(ERR_get_error(), NULL));
704
705 p += tsz;
706 assert(p <= output_size);
707
708 if (DEBUG_LOGGING && input_size > 0) {
709 size_t base64_size;
710
711 base64_size = DIV_ROUND_UP(p * 4, 3); /* Include base64 size increase in debug output */
712 assert(base64_size >= input_size);
713 log_debug("Input of %zu bytes grew to output of %zu bytes (+%2zu%%).", input_size, base64_size, base64_size * 100 / input_size - 100);
714 }
715
716 *ret = TAKE_PTR(output);
717 *ret_size = p;
718
719 return 0;
720 }
721
722 int decrypt_credential_and_warn(
723 const char *validate_name,
724 usec_t validate_timestamp,
725 const char *tpm2_device,
726 const void *input,
727 size_t input_size,
728 void **ret,
729 size_t *ret_size) {
730
731 _cleanup_(erase_and_freep) void *host_key = NULL, *tpm2_key = NULL, *plaintext = NULL;
732 _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL;
733 size_t host_key_size = 0, tpm2_key_size = 0, plaintext_size, p, hs;
734 struct encrypted_credential_header *h;
735 struct metadata_credential_header *m;
736 uint8_t md[SHA256_DIGEST_LENGTH];
737 bool with_tpm2, with_host_key;
738 const EVP_CIPHER *cc;
739 int r, added;
740
741 assert(input || input_size == 0);
742 assert(ret);
743 assert(ret_size);
744
745 h = (struct encrypted_credential_header*) input;
746
747 /* The ID must fit in, for the current and all future formats */
748 if (input_size < sizeof(h->id))
749 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
750
751 with_host_key = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC);
752 with_tpm2 = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC);
753
754 if (!with_host_key && !with_tpm2)
755 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unknown encryption format, or corrupted data: %m");
756
757 /* Now we know the minimum header size */
758 if (input_size < offsetof(struct encrypted_credential_header, iv))
759 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
760
761 /* Verify some basic header values */
762 if (le32toh(h->key_size) != sizeof(md))
763 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected key size in header.");
764 if (le32toh(h->block_size) <= 0 || le32toh(h->block_size) > CREDENTIAL_FIELD_SIZE_MAX)
765 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected block size in header.");
766 if (le32toh(h->iv_size) > CREDENTIAL_FIELD_SIZE_MAX)
767 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "IV size too large.");
768 if (le32toh(h->tag_size) != 16) /* FIXME: On OpenSSL 3, let's verify via EVP_CIPHER_CTX_get_tag_length() */
769 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected tag size in header.");
770
771 /* Ensure we have space for the full header now (we don't know the size of the name hence this is a
772 * lower limit only) */
773 if (input_size <
774 ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
775 ALIGN8((with_tpm2 ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) : 0)) +
776 ALIGN8(offsetof(struct metadata_credential_header, name)) +
777 le32toh(h->tag_size))
778 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
779
780 p = ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size));
781
782 if (with_tpm2) {
783 #if HAVE_TPM2
784 struct tpm2_credential_header* t = (struct tpm2_credential_header*) ((uint8_t*) input + p);
785
786 if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
787 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
788 if (!tpm2_pcr_bank_to_string(le16toh(t->pcr_bank)))
789 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR bank invalid or not supported");
790 if (!tpm2_primary_alg_to_string(le16toh(t->primary_alg)))
791 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 primary key algorithm invalid or not supported.");
792 if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
793 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
794 if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
795 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 policy hash size.");
796
797 /* Ensure we have space for the full TPM2 header now (still don't know the name, and its size
798 * though, hence still just a lower limit test only) */
799 if (input_size <
800 ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
801 ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + le32toh(t->blob_size) + le32toh(t->policy_hash_size)) +
802 ALIGN8(offsetof(struct metadata_credential_header, name)) +
803 le32toh(h->tag_size))
804 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
805
806 r = tpm2_unseal(tpm2_device,
807 le64toh(t->pcr_mask),
808 le16toh(t->pcr_bank),
809 le16toh(t->primary_alg),
810 t->policy_hash_and_blob,
811 le32toh(t->blob_size),
812 t->policy_hash_and_blob + le32toh(t->blob_size),
813 le32toh(t->policy_hash_size),
814 NULL,
815 &tpm2_key,
816 &tpm2_key_size);
817 if (r < 0)
818 return r;
819
820 p += ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) +
821 le32toh(t->blob_size) +
822 le32toh(t->policy_hash_size));
823 #else
824 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Credential requires TPM2 support, but TPM2 support not available.");
825 #endif
826 }
827
828 if (with_host_key) {
829 r = get_credential_host_secret(
830 0,
831 &host_key,
832 &host_key_size);
833 if (r < 0)
834 return log_error_errno(r, "Failed to determine local credential key: %m");
835 }
836
837 sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
838
839 assert_se(cc = EVP_aes_256_gcm());
840
841 /* Make sure cipher expectations match the header */
842 if (EVP_CIPHER_key_length(cc) != (int) le32toh(h->key_size))
843 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected key size in header.");
844 if (EVP_CIPHER_block_size(cc) != (int) le32toh(h->block_size))
845 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected block size in header.");
846
847 context = EVP_CIPHER_CTX_new();
848 if (!context)
849 return log_error_errno(SYNTHETIC_ERRNO(ENOMEM), "Failed to allocate decryption object: %s",
850 ERR_error_string(ERR_get_error(), NULL));
851
852 if (EVP_DecryptInit_ex(context, cc, NULL, NULL, NULL) != 1)
853 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize decryption context: %s",
854 ERR_error_string(ERR_get_error(), NULL));
855
856 if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_IVLEN, le32toh(h->iv_size), NULL) != 1)
857 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set IV size on decryption context: %s",
858 ERR_error_string(ERR_get_error(), NULL));
859
860 if (EVP_DecryptInit_ex(context, NULL, NULL, md, h->iv) != 1)
861 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set IV and key: %s",
862 ERR_error_string(ERR_get_error(), NULL));
863
864 if (EVP_DecryptUpdate(context, NULL, &added, input, p) != 1)
865 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to write AAD data: %s",
866 ERR_error_string(ERR_get_error(), NULL));
867
868 plaintext = malloc(input_size - p - le32toh(h->tag_size));
869 if (!plaintext)
870 return -ENOMEM;
871
872 if (EVP_DecryptUpdate(
873 context,
874 plaintext,
875 &added,
876 (uint8_t*) input + p,
877 input_size - p - le32toh(h->tag_size)) != 1)
878 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decrypt data: %s",
879 ERR_error_string(ERR_get_error(), NULL));
880
881 assert(added >= 0);
882 assert((size_t) added <= input_size - p - le32toh(h->tag_size));
883 plaintext_size = added;
884
885 if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_TAG, le32toh(h->tag_size), (uint8_t*) input + input_size - le32toh(h->tag_size)) != 1)
886 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set tag: %s",
887 ERR_error_string(ERR_get_error(), NULL));
888
889 if (EVP_DecryptFinal_ex(context, (uint8_t*) plaintext + plaintext_size, &added) != 1)
890 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Decryption failed (incorrect key?): %s",
891 ERR_error_string(ERR_get_error(), NULL));
892
893 plaintext_size += added;
894
895 if (plaintext_size < ALIGN8(offsetof(struct metadata_credential_header, name)))
896 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Metadata header incomplete.");
897
898 m = plaintext;
899
900 if (le64toh(m->timestamp) != USEC_INFINITY &&
901 le64toh(m->not_after) != USEC_INFINITY &&
902 le64toh(m->timestamp) >= le64toh(m->not_after))
903 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Timestamps of credential are not in order, refusing.");
904
905 if (le32toh(m->name_size) > CREDENTIAL_NAME_MAX)
906 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Embedded credential name too long, refusing.");
907
908 hs = ALIGN8(offsetof(struct metadata_credential_header, name) + le32toh(m->name_size));
909 if (plaintext_size < hs)
910 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Metadata header incomplete.");
911
912 if (le32toh(m->name_size) > 0) {
913 _cleanup_free_ char *embedded_name = NULL;
914
915 if (memchr(m->name, 0, le32toh(m->name_size)))
916 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Embedded credential name contains NUL byte, refusing.");
917
918 embedded_name = memdup_suffix0(m->name, le32toh(m->name_size));
919 if (!embedded_name)
920 return log_oom();
921
922 if (!credential_name_valid(embedded_name))
923 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Embedded credential name is not valid, refusing.");
924
925 if (validate_name && !streq(embedded_name, validate_name)) {
926
927 r = getenv_bool_secure("SYSTEMD_CREDENTIAL_VALIDATE_NAME");
928 if (r < 0 && r != -ENXIO)
929 log_debug_errno(r, "Failed to parse $SYSTEMD_CREDENTIAL_VALIDATE_NAME: %m");
930 if (r != 0)
931 return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Embedded credential name '%s' does not match filename '%s', refusing.", embedded_name, validate_name);
932
933 log_debug("Embedded credential name '%s' does not match expected name '%s', but configured to use credential anyway.", embedded_name, validate_name);
934 }
935 }
936
937 if (validate_timestamp != USEC_INFINITY) {
938 if (le64toh(m->timestamp) != USEC_INFINITY && le64toh(m->timestamp) > validate_timestamp)
939 log_debug("Credential timestamp is from the future, assuming clock skew.");
940
941 if (le64toh(m->not_after) != USEC_INFINITY && le64toh(m->not_after) < validate_timestamp) {
942
943 r = getenv_bool_secure("SYSTEMD_CREDENTIAL_VALIDATE_NOT_AFTER");
944 if (r < 0 && r != -ENXIO)
945 log_debug_errno(r, "Failed to parse $SYSTEMD_CREDENTIAL_VALIDATE_NOT_AFTER: %m");
946 if (r != 0)
947 return log_error_errno(SYNTHETIC_ERRNO(ESTALE), "Credential's time passed, refusing to use.");
948
949 log_debug("Credential not-after timestamp has passed, but configured to use credential anyway.");
950 }
951 }
952
953 if (ret) {
954 char *without_metadata;
955
956 without_metadata = memdup((uint8_t*) plaintext + hs, plaintext_size - hs);
957 if (!without_metadata)
958 return log_oom();
959
960 *ret = without_metadata;
961 }
962
963 if (ret_size)
964 *ret_size = plaintext_size - hs;
965
966 return 0;
967 }
968
969 #else
970
971 int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size) {
972 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
973 }
974
975 int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_pcr_mask, const void *input, size_t input_size, void **ret, size_t *ret_size) {
976 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
977 }
978
979 int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const void *input, size_t input_size, void **ret, size_t *ret_size) {
980 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
981 }
982
983 #endif