creds: decode Base64 when reading encrypted credentials
Encrypted credentials produced by systemd-creds are stored as Base64. Decode them before decrypting in read_credential_with_decryption(), while leaving plaintext credentials unchanged and retaining their precedence. Bound the decoded encrypted input and report oversized credentials explicitly. Match the plaintext reader's string semantics by rejecting embedded NUL bytes when no size output is requested, while preserving binary payloads for callers that request their size. Add regression coverage for missing and malformed credentials, plaintext precedence, decoded size boundaries, single-line and wrapped Base64, empty strings, and binary data. Keep test outputs and host secrets scoped to private fixtures. Fixes #43621
This commit is contained in:
+18
-8
@@ -180,7 +180,7 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
|
||||
}
|
||||
|
||||
int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size) {
|
||||
_cleanup_(iovec_done_erase) struct iovec ret_iovec = {};
|
||||
_cleanup_(iovec_done_erase) struct iovec decrypted = {};
|
||||
_cleanup_(erase_and_freep) void *data = NULL;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
size_t sz = 0;
|
||||
@@ -218,16 +218,20 @@ int read_credential_with_decryption(const char *name, void **ret, size_t *ret_si
|
||||
if (!fn)
|
||||
return log_oom();
|
||||
|
||||
/* Encrypted credentials are stored as Base64, unlike the plaintext credentials checked above. */
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, fn,
|
||||
UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE,
|
||||
UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER,
|
||||
NULL,
|
||||
(char**) &data, &sz);
|
||||
if (r == -ENOENT)
|
||||
goto not_found;
|
||||
if (r == -E2BIG)
|
||||
return log_error_errno(r, "Encrypted credential '%s' exceeds the size limit.", name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read encrypted credential data: %m");
|
||||
return log_error_errno(
|
||||
r, "Failed to read or Base64-decode encrypted credential '%s': %m", name);
|
||||
|
||||
if (geteuid() != 0)
|
||||
r = ipc_decrypt_credential(
|
||||
@@ -236,7 +240,7 @@ int read_credential_with_decryption(const char *name, void **ret, size_t *ret_si
|
||||
getuid(),
|
||||
&IOVEC_MAKE(data, sz),
|
||||
CREDENTIAL_ANY_SCOPE,
|
||||
&ret_iovec);
|
||||
&decrypted);
|
||||
else
|
||||
r = decrypt_credential_and_warn(
|
||||
name,
|
||||
@@ -246,14 +250,20 @@ int read_credential_with_decryption(const char *name, void **ret, size_t *ret_si
|
||||
getuid(),
|
||||
&IOVEC_MAKE(data, sz),
|
||||
CREDENTIAL_ANY_SCOPE,
|
||||
&ret_iovec);
|
||||
&decrypted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Match read_credential(): without a size output, the caller expects a string. */
|
||||
if (!ret_size && decrypted.iov_len > 0 && memchr(decrypted.iov_base, 0, decrypted.iov_len))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Decrypted credential '%s' contains embedded NUL bytes, refusing.", name);
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(ret_iovec.iov_base);
|
||||
*ret = TAKE_PTR(decrypted.iov_base);
|
||||
if (ret_size)
|
||||
*ret_size = ret_iovec.iov_len;
|
||||
*ret_size = decrypted.iov_len;
|
||||
|
||||
return 1; /* found */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user