/* Only one of these two flags may be set at the same time */
assert(!FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL) || !FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL));
- if (!sd_id128_in_set(with_key,
- _CRED_AUTO,
- _CRED_AUTO_INITRD,
- _CRED_AUTO_SCOPED,
- CRED_AES256_GCM_BY_HOST,
- CRED_AES256_GCM_BY_HOST_SCOPED,
- CRED_AES256_GCM_BY_TPM2_HMAC,
- CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED,
- CRED_AES256_GCM_BY_NULL))
+ if (!CRED_KEY_IS_VALID(with_key) && !CRED_KEY_IS_AUTO(with_key))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid key type: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(with_key));
if (name && !credential_name_valid(name))
log_debug("Including not-after timestamp '%s' in encrypted credential.", format_timestamp(buf, sizeof(buf), not_after));
}
- if (sd_id128_in_set(with_key,
- _CRED_AUTO_SCOPED,
- CRED_AES256_GCM_BY_HOST_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)) {
+ if (CRED_KEY_IS_SCOPED(with_key)) {
if (!uid_is_valid(uid))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Scoped credential key type "SD_ID128_FORMAT_STR" selected, but no UID specified.", SD_ID128_FORMAT_VAL(with_key));
} else
uid = UID_INVALID;
- if (sd_id128_in_set(with_key,
- _CRED_AUTO,
- _CRED_AUTO_SCOPED,
- CRED_AES256_GCM_BY_HOST,
- CRED_AES256_GCM_BY_HOST_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)) {
+ if (CRED_KEY_WANTS_HOST(with_key) || CRED_KEY_REQUIRES_HOST(with_key)) {
r = get_credential_host_secret(
CREDENTIAL_SECRET_GENERATE|
CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED|
- (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_SCOPED) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
+ (CRED_KEY_WANTS_HOST(with_key) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
&host_key);
- if (r == -ENOMEDIUM && sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_SCOPED))
+ if (r == -ENOMEDIUM && CRED_KEY_WANTS_HOST(with_key))
log_debug_errno(r, "Credential host secret location on temporary file system, not using.");
else if (r < 0)
return log_error_errno(r, "Failed to determine local credential host secret: %m");
#if HAVE_TPM2
bool try_tpm2;
- if (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD, _CRED_AUTO_SCOPED)) {
+ if (CRED_KEY_WANTS_TPM2(with_key)) {
/* If automatic mode is selected lets see if a TPM2 it is present. If we are running in a
* container tpm2_support will detect this, and will return a different flag combination of
* TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */
if (!try_tpm2)
log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2.");
} else
- try_tpm2 = sd_id128_in_set(with_key,
- CRED_AES256_GCM_BY_TPM2_HMAC,
- CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED);
+ try_tpm2 = CRED_KEY_REQUIRES_TPM2(with_key);
if (try_tpm2) {
- if (sd_id128_in_set(with_key,
- _CRED_AUTO,
- _CRED_AUTO_INITRD,
- _CRED_AUTO_SCOPED,
- CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK,
- CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)) {
+ if (CRED_KEY_WANTS_TPM2_PK(with_key) || CRED_KEY_REQUIRES_TPM2_PK(with_key)) {
/* Load public key for PCR policies, if one is specified, or explicitly requested */
r = tpm2_load_pcr_public_key(tpm2_pubkey_path, &pubkey.iov_base, &pubkey.iov_len);
if (r < 0) {
- if (tpm2_pubkey_path || r != -ENOENT || !sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD, _CRED_AUTO_SCOPED))
+ if (r != -ENOENT || tpm2_pubkey_path || CRED_KEY_REQUIRES_TPM2_PK(with_key))
return log_error_errno(r, "Failed to read TPM PCR public key: %m");
log_debug_errno(r, "Failed to read TPM2 PCR public key, proceeding without: %m");
}
#endif
- if (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD, _CRED_AUTO_SCOPED)) {
+ if (CRED_KEY_IS_AUTO(with_key)) {
/* Let's settle the key type in auto mode now. */
if (iovec_is_set(&host_key) && iovec_is_set(&tpm2_key))
struct encrypted_credential_header *h;
struct metadata_credential_header *m;
uint8_t md[SHA256_DIGEST_LENGTH];
- bool with_tpm2, with_tpm2_pk, with_host_key, with_null, with_scope;
const EVP_CIPHER *cc;
size_t p, hs;
int r, added;
if (input->iov_len < sizeof(h->id))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
- with_host_key = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_SCOPED, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED);
- with_tpm2_pk = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED);
- with_tpm2 = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED) || with_tpm2_pk;
- with_null = sd_id128_equal(h->id, CRED_AES256_GCM_BY_NULL);
- with_scope = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_HOST_SCOPED, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED);
-
- if (!with_host_key && !with_tpm2 && !with_null)
+ if (!CRED_KEY_IS_VALID(h->id))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unknown encryption format, or corrupted data.");
- if (with_tpm2_pk) {
+ if (CRED_KEY_REQUIRES_TPM2_PK(h->id)) {
r = tpm2_load_pcr_signature(tpm2_signature_path, &signature_json);
if (r == -ENOENT)
return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN), "Couldn't find PCR signature file: %m");
return log_error_errno(r, "Failed to load PCR signature: %m");
}
- if (with_null) {
+ if (sd_id128_equal(h->id, CRED_AES256_GCM_BY_NULL)) {
if (FLAGS_SET(flags, CREDENTIAL_REFUSE_NULL))
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON),
"Credential uses null key, but that's not allowed, refusing.");
}
}
- if (with_scope) {
+ if (CRED_KEY_IS_SCOPED(h->id)) {
if (!uid_is_valid(uid))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Encrypted file is scoped to a user, but no user selected.");
} else {
* lower limit only) */
if (input->iov_len <
ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
- ALIGN8(with_tpm2 ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) : 0) +
- ALIGN8(with_tpm2_pk ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
- ALIGN8(with_scope ? sizeof(struct scoped_credential_header) : 0) +
+ ALIGN8(CRED_KEY_REQUIRES_TPM2(h->id) ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) : 0) +
+ ALIGN8(CRED_KEY_REQUIRES_TPM2_PK(h->id) ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
+ ALIGN8(CRED_KEY_IS_SCOPED(h->id) ? sizeof(struct scoped_credential_header) : 0) +
ALIGN8(offsetof(struct metadata_credential_header, name)) +
le32toh(h->tag_size))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
p = ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size));
- if (with_tpm2) {
+ if (CRED_KEY_REQUIRES_TPM2(h->id)) {
#if HAVE_TPM2
struct tpm2_credential_header* t = (struct tpm2_credential_header*) ((uint8_t*) input->iov_base + p);
struct tpm2_public_key_credential_header *z = NULL;
if (input->iov_len <
p +
ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + le32toh(t->blob_size) + le32toh(t->policy_hash_size)) +
- ALIGN8(with_tpm2_pk ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
- ALIGN8(with_scope ? sizeof(struct scoped_credential_header) : 0) +
+ ALIGN8(CRED_KEY_REQUIRES_TPM2_PK(h->id) ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
+ ALIGN8(CRED_KEY_IS_SCOPED(h->id) ? sizeof(struct scoped_credential_header) : 0) +
ALIGN8(offsetof(struct metadata_credential_header, name)) +
le32toh(h->tag_size))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
le32toh(t->blob_size) +
le32toh(t->policy_hash_size));
- if (with_tpm2_pk) {
+ if (CRED_KEY_REQUIRES_TPM2_PK(h->id)) {
z = (struct tpm2_public_key_credential_header*) ((uint8_t*) input->iov_base + p);
if (!TPM2_PCR_MASK_VALID(le64toh(z->pcr_mask)) || le64toh(z->pcr_mask) == 0)
if (input->iov_len <
p +
ALIGN8(offsetof(struct tpm2_public_key_credential_header, data) + le32toh(z->size)) +
- ALIGN8(with_scope ? sizeof(struct scoped_credential_header) : 0) +
+ ALIGN8(CRED_KEY_IS_SCOPED(h->id) ? sizeof(struct scoped_credential_header) : 0) +
ALIGN8(offsetof(struct metadata_credential_header, name)) +
le32toh(h->tag_size))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
#endif
}
- if (with_scope) {
+ if (CRED_KEY_IS_SCOPED(h->id)) {
struct scoped_credential_header* sh = (struct scoped_credential_header*) ((uint8_t*) input->iov_base + p);
if (le64toh(sh->flags) != SCOPE_HASH_DATA_BASE_FLAGS)
p += sizeof(struct scoped_credential_header);
}
- if (with_host_key) {
+ if (CRED_KEY_REQUIRES_HOST(h->id)) {
r = get_credential_host_secret(/* flags= */ 0, &host_key);
if (r < 0)
return log_error_errno(r, "Failed to determine local credential key: %m");
}
- if (with_null && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL))
+ if (sd_id128_equal(h->id, CRED_AES256_GCM_BY_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);
- if (with_scope) {
+ if (CRED_KEY_IS_SCOPED(h->id)) {
r = mangle_uid_into_key(uid, md);
if (r < 0)
return r;
SD_ID128_MAKE(ad,bc,4c,a3,ef,b6,42,01,ba,88,1b,6f,2e,40,95,ea)
#define CRED_AES256_GCM_BY_NULL SD_ID128_MAKE(05,84,69,da,f6,f5,43,24,80,05,49,da,0f,8e,a2,fb)
-/* Two special IDs to pick a general automatic mode (i.e. tpm2+host if TPM2 exists, only host otherwise) or
- * an initrd-specific automatic mode (i.e. tpm2 if firmware can do it, otherwise fixed zero-length key, and
- * never involve host keys). These IDs will never be stored on disk, but are useful only internally while
- * figuring out what precisely to write to disk. To mark that these aren't a "real" type, we'll prefix them
- * with an underscore. */
+/* Five special IDs to pick a general automatic mode. These IDs will never be stored on disk, but are useful
+ * only internally while figuring out what precisely to write to disk. To mark that these aren't a "real"
+ * type, we'll prefix them with an underscore. */
+
+/* Use TPM2 if available + host if available and on physical media. If neither are available, fail. */
#define _CRED_AUTO SD_ID128_MAKE(a2,19,cb,07,85,b2,4c,04,b1,6d,18,ca,b9,d2,ee,01)
+
+/* Use best TPM2, and do not use host, and fail if no TPM */
+#define _CRED_AUTO_TPM2 SD_ID128_MAKE(45,f3,a6,7e,0c,12,42,56,a4,ee,75,eb,44,c6,5a,6f)
+
+/* Use TPM2 *and* host, and fail if one of the two isn't available. */
+#define _CRED_AUTO_HOST_AND_TPM2 SD_ID128_MAKE(da,f6,7a,60,d3,eb,47,b3,a9,be,2f,d5,fe,c2,15,22)
+
+/* Like _CRED_AUTO_TPM2, but uses "null" if not TPM is around */
#define _CRED_AUTO_INITRD SD_ID128_MAKE(02,dc,8e,de,3a,02,43,ab,a9,ec,54,9c,05,e6,a0,71)
+
+/* Like _CRED_AUTO, but with per-UID scoping */
#define _CRED_AUTO_SCOPED SD_ID128_MAKE(23,88,96,85,6f,74,48,8a,9c,78,6f,6a,b0,e7,3b,6a)
+#define CRED_KEY_IS_VALID(key) \
+ sd_id128_in_set((key), \
+ CRED_AES256_GCM_BY_HOST, \
+ CRED_AES256_GCM_BY_HOST_SCOPED, \
+ CRED_AES256_GCM_BY_TPM2_HMAC, \
+ CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED, \
+ CRED_AES256_GCM_BY_NULL)
+#define CRED_KEY_IS_AUTO(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO, \
+ _CRED_AUTO_TPM2, \
+ _CRED_AUTO_HOST_AND_TPM2, \
+ _CRED_AUTO_INITRD, \
+ _CRED_AUTO_SCOPED)
+#define CRED_KEY_IS_SCOPED(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)
+#define CRED_KEY_REQUIRES_HOST(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO_HOST_AND_TPM2, \
+ CRED_AES256_GCM_BY_HOST, \
+ CRED_AES256_GCM_BY_HOST_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)
+#define CRED_KEY_WANTS_HOST(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO, \
+ _CRED_AUTO_SCOPED)
+#define CRED_KEY_REQUIRES_TPM2(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO_TPM2, \
+ _CRED_AUTO_HOST_AND_TPM2, \
+ CRED_AES256_GCM_BY_TPM2_HMAC, \
+ CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_SCOPED, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)
+#define CRED_KEY_WANTS_TPM2(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO, \
+ _CRED_AUTO_INITRD, \
+ _CRED_AUTO_SCOPED)
+#define CRED_KEY_REQUIRES_TPM2_PK(key) \
+ sd_id128_in_set((key), \
+ CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, \
+ CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK_SCOPED)
+#define CRED_KEY_WANTS_TPM2_PK(key) \
+ sd_id128_in_set((key), \
+ _CRED_AUTO, \
+ _CRED_AUTO_TPM2, \
+ _CRED_AUTO_HOST_AND_TPM2, \
+ _CRED_AUTO_INITRD, \
+ _CRED_AUTO_SCOPED)
+
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, uid_t uid, 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, uid_t uid, const struct iovec *input, CredentialFlags flags, struct iovec *ret);