creds-util: add new helper read_credential_with_decryption()

This is just like read_credential() but also looks into the encrypted
credential directory, not just the regular one.

Normally, we decrypt credentials at the moment we pass them to services.
From service PoV all credentials are hence decrypted credentials.

However, when we want to access credentials in a generator this logic
does not apply: here we have the regular and the encrypted credentials
directory. So far we didn't attempt to make use of credentials in
generators hence.

Let's address and add helper that looks into both directories, and talks
to the TPM if necessary to decrypt the credentials.
This commit is contained in:
Lennart Poettering 2023-06-23 21:48:15 +02:00
parent 0dea5b7719
commit 49e859b7c7
2 changed files with 76 additions and 1 deletions

View file

@ -125,6 +125,80 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
(char**) ret, ret_size);
}
int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size) {
_cleanup_(erase_and_freep) void *data = NULL;
_cleanup_free_ char *fn = NULL;
size_t sz = 0;
const char *d;
int r;
assert(ret);
/* Just like read_credential() but will also look for encrypted credentials. Note that services only
* receive decrypted credentials, hence use read_credential() for those. This helper here is for
* generators, i.e. code that runs outside of service context, and thus has no decrypted credentials
* yet.
*
* Note that read_credential_harder_and_warn() logs on its own, while read_credential() does not!
* (It's a lot more complex and error prone given its TPM2 connectivty, and is generally called from
* generators only where logging is OK).
*
* Error handling is also a bit different: if we can't find a credential we'll return 0 and NULL
* pointers/zero size, rather than -ENXIO/-ENOENT. */
if (!credential_name_valid(name))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name);
r = read_credential(name, ret, ret_size);
if (r >= 0)
return 1; /* found */
if (!IN_SET(r, -ENXIO, -ENOENT))
return log_error_errno(r, "Failed read unencrypted credential '%s': %m", name);
r = get_encrypted_credentials_dir(&d);
if (r == -ENXIO)
goto not_found;
if (r < 0)
return log_error_errno(r, "Failed to determine encrypted credentials directory: %m");
fn = path_join(d, name);
if (!fn)
return log_oom();
r = read_full_file_full(
AT_FDCWD, fn,
UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE,
NULL,
(char**) data, &sz);
if (r == -ENOENT)
goto not_found;
if (r < 0)
return log_error_errno(r, "Failed to read encrypted credential data: %m");
r = decrypt_credential_and_warn(
name,
now(CLOCK_REALTIME),
/* tpm2_device = */ NULL,
/* tpm2_signature_path = */ NULL,
data,
sz,
ret,
ret_size);
if (r < 0)
return r;
return 1; /* found */
not_found:
*ret = NULL;
if (ret_size)
*ret_size = 0;
return 0; /* not found */
}
int read_credential_strings_many_internal(
const char *first_name, char **first_value,
...) {

View file

@ -35,7 +35,8 @@ int get_encrypted_credentials_dir(const char **ret);
#define SYSTEM_CREDENTIALS_DIRECTORY "/run/credentials/@system"
#define ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY "/run/credentials/@encrypted"
int read_credential(const char *name, void **ret, size_t *ret_size);
int read_credential(const char *name, void **ret, size_t *ret_size); /* use in services! */
int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size); /* use in generators + pid1! */
int read_credential_strings_many_internal(const char *first_name, char **first_value, ...);