]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds: query OpenSSL for GCM tag length
authordongshengyuan <545258830@qq.com>
Mon, 27 Jul 2026 02:29:32 +0000 (10:29 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 27 Jul 2026 10:19:31 +0000 (19:19 +0900)
Follow-up for: 21bc0b6fa1de44b520353b935bf14160f9f70591

Follow-up for: 99d0a9fdb08d0291dcd06a279bf6e2597f651244

src/shared/creds-util.c
src/shared/crypto-util.c
src/shared/crypto-util.h

index bbba1c3eae66d511ac21e207ff0744687d85d799..57eb8681f2c5eb53a2ae3083cbeb8a5c6a4eb07b 100644 (file)
@@ -1107,8 +1107,6 @@ int encrypt_credential_and_warn(
                         return log_error_errno(r, "Failed to acquired randomized IV: %m");
         }
 
-        tsz = 16; /* FIXME: On OpenSSL 3 there is EVP_CIPHER_CTX_get_tag_length(), until then let's hardcode this */
-
         context = sym_EVP_CIPHER_CTX_new();
         if (!context)
                 return log_openssl_errors(LOG_ERR, "Failed to allocate encryption object");
@@ -1116,6 +1114,10 @@ int encrypt_credential_and_warn(
         if (sym_EVP_EncryptInit_ex(context, cc, NULL, md, iv.iov_base) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to initialize encryption context");
 
+        tsz = sym_EVP_CIPHER_CTX_get_tag_length(context);
+        if (tsz <= 0 || (size_t) tsz > CREDENTIAL_FIELD_SIZE_MAX)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid tag size reported by OpenSSL.");
+
         /* Just an upper estimate */
         output.iov_len =
                 ALIGN8(offsetof(struct encrypted_credential_header, iv) + ivsz) +
@@ -1336,8 +1338,9 @@ int decrypt_credential_and_warn(
         struct metadata_credential_header *m;
         uint8_t md[SHA256_DIGEST_LENGTH];
         const EVP_CIPHER *cc;
+        uint32_t tag_size;
         size_t p, hs;
-        int r, added;
+        int r, added, tsz;
 
         assert(iovec_is_valid(input));
         assert(ret);
@@ -1405,7 +1408,9 @@ int decrypt_credential_and_warn(
                 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected block size in header.");
         if (le32toh(h->iv_size) > CREDENTIAL_FIELD_SIZE_MAX)
                 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "IV size too large.");
-        if (le32toh(h->tag_size) != 16) /* FIXME: On OpenSSL 3, let's verify via EVP_CIPHER_CTX_get_tag_length() */
+
+        tag_size = le32toh(h->tag_size);
+        if (tag_size == 0 || tag_size > CREDENTIAL_FIELD_SIZE_MAX)
                 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected tag size in header.");
 
         /* Ensure we have space for the full header now (we don't know the size of the name hence this is a
@@ -1417,7 +1422,7 @@ int decrypt_credential_and_warn(
             ALIGN8(CRED_KEY_REQUIRES_TPM2_PINNED_SRK(h->id) ? offsetof(struct tpm2_pinned_srk_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))
+            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));
@@ -1448,7 +1453,7 @@ int decrypt_credential_and_warn(
                     ALIGN8(CRED_KEY_REQUIRES_TPM2_PINNED_SRK(h->id) ? offsetof(struct tpm2_pinned_srk_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))
+                    tag_size)
                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
 
                 p += ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) +
@@ -1469,7 +1474,7 @@ int decrypt_credential_and_warn(
                             ALIGN8(CRED_KEY_REQUIRES_TPM2_PINNED_SRK(h->id) ? offsetof(struct tpm2_pinned_srk_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))
+                            tag_size)
                                 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
 
                         p += ALIGN8(offsetof(struct tpm2_public_key_credential_header, data) +
@@ -1487,7 +1492,7 @@ int decrypt_credential_and_warn(
                             ALIGN8(offsetof(struct tpm2_pinned_srk_credential_header, data) + le32toh(z_srk->size)) +
                             ALIGN8(CRED_KEY_IS_SCOPED(h->id) ? sizeof(struct scoped_credential_header) : 0) +
                             ALIGN8(offsetof(struct metadata_credential_header, name)) +
-                            le32toh(h->tag_size))
+                            tag_size)
                                 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
 
                         p += ALIGN8(offsetof(struct tpm2_pinned_srk_credential_header, data) +
@@ -1538,7 +1543,7 @@ int decrypt_credential_and_warn(
                     p +
                     sizeof(struct scoped_credential_header) +
                     ALIGN8(offsetof(struct metadata_credential_header, name)) +
-                    le32toh(h->tag_size))
+                    tag_size)
                         return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
 
                 p += sizeof(struct scoped_credential_header);
@@ -1580,6 +1585,12 @@ int decrypt_credential_and_warn(
         if (sym_EVP_DecryptInit_ex(context, cc, NULL, NULL, NULL) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to initialize decryption context");
 
+        tsz = sym_EVP_CIPHER_CTX_get_tag_length(context);
+        if (tsz <= 0 || (size_t) tsz > CREDENTIAL_FIELD_SIZE_MAX)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid tag size reported by OpenSSL.");
+        if (tag_size != (uint32_t) tsz)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected tag size in header.");
+
         if (sym_EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_IVLEN, le32toh(h->iv_size), NULL) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to set IV size on decryption context");
 
@@ -1589,7 +1600,7 @@ int decrypt_credential_and_warn(
         if (sym_EVP_DecryptUpdate(context, NULL, &added, input->iov_base, p) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to write AAD data");
 
-        plaintext.iov_base = malloc(input->iov_len - p - le32toh(h->tag_size));
+        plaintext.iov_base = malloc(input->iov_len - p - tag_size);
         if (!plaintext.iov_base)
                 return -ENOMEM;
 
@@ -1598,14 +1609,14 @@ int decrypt_credential_and_warn(
                             plaintext.iov_base,
                             &added,
                             (uint8_t*) input->iov_base + p,
-                            input->iov_len - p - le32toh(h->tag_size)) != 1)
+                            input->iov_len - p - tag_size) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to decrypt data");
 
         assert(added >= 0);
-        assert((size_t) added <= input->iov_len - p - le32toh(h->tag_size));
+        assert((size_t) added <= input->iov_len - p - tag_size);
         plaintext.iov_len = added;
 
-        if (sym_EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_TAG, le32toh(h->tag_size), (uint8_t*) input->iov_base + input->iov_len - le32toh(h->tag_size)) != 1)
+        if (sym_EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_TAG, tag_size, (uint8_t*) input->iov_base + input->iov_len - tag_size) != 1)
                 return log_openssl_errors(LOG_ERR, "Failed to set tag");
 
         if (sym_EVP_DecryptFinal_ex(context, (uint8_t*) plaintext.iov_base + plaintext.iov_len, &added) != 1) {
index b3053e7f1d1000061b8de3aa6f1fa861cb9d7919..1c1c4249e186673905ddeba531eae829416b811c 100644 (file)
@@ -126,6 +126,7 @@ static DLSYM_PROTOTYPE(ERR_peek_last_error) = NULL;
 DLSYM_PROTOTYPE(EVP_CIPHER_CTX_ctrl) = NULL;
 DLSYM_PROTOTYPE(EVP_CIPHER_CTX_free) = NULL;
 static DLSYM_PROTOTYPE(EVP_CIPHER_CTX_get_block_size) = NULL;
+DLSYM_PROTOTYPE(EVP_CIPHER_CTX_get_tag_length) = NULL;
 DLSYM_PROTOTYPE(EVP_CIPHER_CTX_new) = NULL;
 static DLSYM_PROTOTYPE(EVP_CIPHER_fetch) = NULL;
 DLSYM_PROTOTYPE(EVP_CIPHER_free) = NULL;
@@ -450,6 +451,7 @@ int dlopen_libcrypto(int log_level) {
                         DLSYM_ARG(EVP_CIPHER_CTX_ctrl),
                         DLSYM_ARG(EVP_CIPHER_CTX_free),
                         DLSYM_ARG(EVP_CIPHER_CTX_get_block_size),
+                        DLSYM_ARG(EVP_CIPHER_CTX_get_tag_length),
                         DLSYM_ARG(EVP_CIPHER_CTX_new),
                         DLSYM_ARG(EVP_CIPHER_fetch),
                         DLSYM_ARG(EVP_CIPHER_free),
index a49c39e50ecb53ae36a7ef3218748b492828ba3b..28a0eaf5bd518f69530a38de7d1035adea47924a 100644 (file)
@@ -132,6 +132,7 @@ extern DLSYM_PROTOTYPE(ERR_error_string_n);
 extern DLSYM_PROTOTYPE(ERR_get_error);
 extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_ctrl);
 extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_free);
+extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_get_tag_length);
 extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_new);
 extern DLSYM_PROTOTYPE(EVP_CIPHER_free);
 extern DLSYM_PROTOTYPE(EVP_CIPHER_get_block_size);