creds-util: optionally, allow NULL credentials even with TPM
authorLennart Poettering <lennart@poettering.net>
Mon, 20 Nov 2023 17:00:35 +0000 (18:00 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 5 Jan 2024 16:20:05 +0000 (17:20 +0100)
src/core/exec-credential.c
src/creds/creds.c
src/shared/creds-util.c
src/shared/creds-util.h

index 513087d06925bdc0024ed8ace033f2dca39a739c..4aa3e35bd85bdff7ee564e6d2c09ecf86e21b274 100644 (file)
@@ -283,6 +283,7 @@ static int maybe_decrypt_and_write_credential(
                                 /* tpm2_device= */ NULL,
                                 /* tpm2_signature_path= */ NULL,
                                 &IOVEC_MAKE(data, size),
+                                /* flags= */ 0,
                                 &plaintext);
                 if (r < 0)
                         return r;
@@ -708,6 +709,7 @@ static int acquire_credentials(
                                         /* tpm2_device= */ NULL,
                                         /* tpm2_signature_path= */ NULL,
                                         &IOVEC_MAKE(sc->data, sc->size),
+                                        /* flags= */ 0,
                                         &plaintext);
                         if (r < 0)
                                 return r;
index 01b2844dd301a873334b346859627580aac296bd..c9d1a6e8d94f3029db33005b885329bd581a8bd2 100644 (file)
@@ -429,6 +429,7 @@ static int verb_cat(int argc, char **argv, void *userdata) {
                                         arg_tpm2_device,
                                         arg_tpm2_signature,
                                         &IOVEC_MAKE(data, size),
+                                        /* flags= */ 0,
                                         &plaintext);
                         if (r < 0)
                                 return r;
@@ -501,6 +502,7 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
                         arg_tpm2_public_key,
                         arg_tpm2_public_key_pcr_mask,
                         &plaintext,
+                        /* flags= */ 0,
                         &output);
         if (r < 0)
                 return r;
@@ -589,6 +591,7 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
                         arg_tpm2_device,
                         arg_tpm2_signature,
                         &input,
+                        /* flags= */ 0,
                         &plaintext);
         if (r < 0)
                 return r;
@@ -1029,6 +1032,7 @@ static int vl_method_encrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
                         arg_tpm2_public_key,
                         arg_tpm2_public_key_pcr_mask,
                         p.text ? &IOVEC_MAKE_STRING(p.text) : &p.data,
+                        /* flags= */ 0,
                         &output);
         if (r < 0)
                 return r;
@@ -1103,6 +1107,7 @@ static int vl_method_decrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
                         arg_tpm2_device,
                         arg_tpm2_signature,
                         &p.blob,
+                        /* flags= */ 0,
                         &output);
         if (r == -EBADMSG)
                 return varlink_error(link, "io.systemd.Credentials.BadFormat", NULL);
index 716543a2a78933811bf6185a8e5288612c634716..08d915cb8da82e993f0feefe9e8abcf226fa67dd 100644 (file)
@@ -193,6 +193,7 @@ int read_credential_with_decryption(const char *name, void **ret, size_t *ret_si
                         /* tpm2_device = */ NULL,
                         /* tpm2_signature_path = */ NULL,
                         &IOVEC_MAKE(data, sz),
+                        /* flags= */ 0,
                         &ret_iovec);
         if (r < 0)
                 return r;
@@ -723,6 +724,7 @@ int encrypt_credential_and_warn(
                 const char *tpm2_pubkey_path,
                 uint32_t tpm2_pubkey_pcr_mask,
                 const struct iovec *input,
+                CredentialFlags flags,
                 struct iovec *ret) {
 
         _cleanup_(iovec_done) struct iovec tpm2_blob = {}, tpm2_policy_hash = {}, iv = {}, pubkey = {};
@@ -901,7 +903,7 @@ int encrypt_credential_and_warn(
         } else
                 id = with_key;
 
-        if (sd_id128_equal(id, CRED_AES256_GCM_BY_NULL))
+        if (sd_id128_equal(id, CRED_AES256_GCM_BY_NULL) && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL))
                 log_warning("Using a null key for encryption and signing. Confidentiality or authenticity will not be provided.");
 
         /* Let's now take the host key and the TPM2 key and hash it together, to use as encryption key for the data */
@@ -1065,6 +1067,7 @@ int decrypt_credential_and_warn(
                 const char *tpm2_device,
                 const char *tpm2_signature_path,
                 const struct iovec *input,
+                CredentialFlags flags,
                 struct iovec *ret) {
 
         _cleanup_(iovec_done_erase) struct iovec host_key = {}, plaintext = {}, tpm2_key = {};
@@ -1101,7 +1104,7 @@ int decrypt_credential_and_warn(
                         return log_error_errno(r, "Failed to load pcr signature: %m");
         }
 
-        if (with_null) {
+        if (with_null && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL)) {
                 /* So this is a credential encrypted with a zero length key. We support this to cover for the
                  * case where neither a host key not a TPM2 are available (specifically: initrd environments
                  * where the host key is not yet accessible and no TPM2 chip exists at all), to minimize
@@ -1230,7 +1233,7 @@ int decrypt_credential_and_warn(
                         return log_error_errno(r, "Failed to determine local credential key: %m");
         }
 
-        if (with_null)
+        if (with_null && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL))
                 log_warning("Warning: using a null key for decryption and authentication. Confidentiality or authenticity are not provided.");
 
         sha256_hash_host_and_tpm2_key(&host_key, &tpm2_key, md);
@@ -1366,11 +1369,11 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
 }
 
-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_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, struct iovec *ret) {
+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_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, CredentialFlags flags, struct iovec *ret) {
         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
 }
 
-int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, struct iovec *ret) {
+int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, CredentialFlags flags, struct iovec *ret) {
         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
 }
 
index 38d5086e8cf5b2ba8c5c10935e7ff3d0fc719ed2..9362d4e52c4c72109fe563490eedadf553803f0b 100644 (file)
@@ -57,6 +57,10 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret);
 
 int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed);
 
+typedef enum CredentialFlags {
+        CREDENTIAL_ALLOW_NULL = 1 << 0, /* allow decryption of NULL key, even if TPM is around */
+} CredentialFlags;
+
 /* The four modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of
  * both, as well as one with a fixed zero length key if TPM2 is missing (the latter of course provides no
  * authenticity or confidentiality, but is still useful for integrity protection, and makes things simpler
@@ -77,5 +81,5 @@ int get_credential_user_password(const char *username, char **ret_password, bool
 #define _CRED_AUTO                            SD_ID128_MAKE(a2,19,cb,07,85,b2,4c,04,b1,6d,18,ca,b9,d2,ee,01)
 #define _CRED_AUTO_INITRD                     SD_ID128_MAKE(02,dc,8e,de,3a,02,43,ab,a9,ec,54,9c,05,e6,a0,71)
 
-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_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, struct iovec *ret);
-int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, struct iovec *ret);
+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_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, CredentialFlags flags, struct iovec *ret);
+int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, CredentialFlags flags, struct iovec *ret);