libnm/crypto: accept TPM2-wrapped PEM keys

Some tools that NM can interact with (eg. openconnect) have added
automated support to handle TPM2-wrapped PEM keys as drop-in
replacements for ordinary key files. Make sure that NM doesn't reject
these keys upfront. We cannot reliably assume NM to be able to unwrap
and validate the key. Therefore, accept any key as long as the PEM
header and trailer look ok.
This commit is contained in:
Daniel Kobras
2019-06-24 12:09:12 +02:00
committed by Beniamino Galvani
parent 68ad9aabf8
commit 107ba8e00c
3 changed files with 76 additions and 3 deletions

View File

@@ -49,6 +49,12 @@
#define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
#define PEM_PKCS8_DEC_KEY_END "-----END PRIVATE KEY-----"
#define PEM_TPM2_WRAPPED_KEY_BEGIN "-----BEGIN TSS2 PRIVATE KEY-----"
#define PEM_TPM2_WRAPPED_KEY_END "-----END TSS2 PRIVATE KEY-----"
#define PEM_TPM2_OLD_WRAPPED_KEY_BEGIN "-----BEGIN TSS2 KEY BLOB-----"
#define PEM_TPM2_OLD_WRAPPED_KEY_END "-----END TSS2 KEY BLOB-----"
/*****************************************************************************/
static const NMCryptoCipherInfo cipher_infos[] = {
@@ -386,6 +392,43 @@ parse_pkcs8_key_file (const guint8 *data,
return TRUE;
}
static gboolean
parse_tpm2_wrapped_key_file (const guint8 *data,
gsize data_len,
gboolean *out_encrypted,
GError **error)
{
gsize start = 0, end = 0;
const char *start_tag = NULL, *end_tag = NULL;
nm_assert (out_encrypted);
if (find_tag (PEM_TPM2_WRAPPED_KEY_BEGIN, data, data_len, 0, &start)) {
start_tag = PEM_TPM2_WRAPPED_KEY_BEGIN;
end_tag = PEM_TPM2_WRAPPED_KEY_END;
} else if (find_tag (PEM_TPM2_OLD_WRAPPED_KEY_BEGIN, data, data_len, 0, &start)) {
start_tag = PEM_TPM2_OLD_WRAPPED_KEY_BEGIN;
end_tag = PEM_TPM2_OLD_WRAPPED_KEY_END;
} else {
g_set_error_literal (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Failed to find expected TSS start tag."));
return FALSE;
}
start += strlen (start_tag);
if (!find_tag (end_tag, data, data_len, start, &end)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Failed to find expected TSS end tag '%s'."),
end_tag);
return FALSE;
}
*out_encrypted = FALSE;
return TRUE;
}
static gboolean
file_read_contents (const char *filename,
NMSecretPtr *out_contents,
@@ -824,6 +867,8 @@ nm_crypto_verify_private_key_data (const guint8 *data,
if ( !password
|| _nm_crypto_verify_pkcs8 (parsed.bin, parsed.len, is_encrypted, password, error))
format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
} else if (parse_tpm2_wrapped_key_file (data, data_len, &is_encrypted, NULL)) {
format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
} else {
NMCryptoCipherType cipher;
nm_auto_free_secret char *iv = NULL;

View File

@@ -0,0 +1,14 @@
-----BEGIN TSS2 PRIVATE KEY-----
MIICEwYGZ4EFCgEDoAMBAQECBQCBAAABBIIBGAEWAAEACwACBEAAAAAQABAIAAAA
AAABAOJdEXw1LO6JWskHBSYQc1NfJAe9DOAyLA4XbXI5asQ8aNbmL51DP9mQQpqq
a1CSRZAIuuorMxyRBBAFpF4OZqjNd/Nskp3iMmifr5yqAYZ3M31MqlBFiiyctqKp
VwIChwsIbKelrsXbty1icP2CH+k4w/nPymPjnfYtgpMe8QW8n6U156ujIdJcISds
QFcl3nrDnD1IumX0/LfanQrRDVSI+m6szvTrdsPMtGeaNMnlz0gx74auo7/CgEjX
69xjPvQpNLHO/nV4EHSdfXH3LamcpWO8aEAVne3MFFA9V0bpv7uKoGhRjssD9kSr
PQzNXfjHpkcOLeH4pzxDMFXDIGUEgeAA3gAgrCL3RRcBryFXToo9ZN3/f4EeeEjK
58ejYomsxqvckhgAEMxbT26fo2h27b4KPlnUpoiL2JPLB0Xz6PJAF8n0YdJUO381
xhzPTIQop81BxljTLV2C9WGns5bWDPW9ItEbv4UalEwFfxsW4Ma5smLWn3A1UwVN
Z1cW/oUx+3nOCF1TZgbMPszToqCPlpIHd9vO709qpSyULIUkZLHS6PUM7ESY5U81
f4BITxJR+aYaqErni/FDLsDVP0MQ3CuFHeUDHI0uEzzbfurYFjpp9+caaoWuZzpg
VYV5pjPdgg==
-----END TSS2 PRIVATE KEY-----

View File

@@ -35,6 +35,7 @@
#define TEST_CERT_DIR NM_BUILD_SRCDIR"/libnm-core/tests/certs"
#define TEST_WIRED_TLS_CA_CERT TEST_CERT_DIR"/test-ca-cert.pem"
#define TEST_WIRED_TLS_PRIVKEY TEST_CERT_DIR"/test-key-and-cert.pem"
#define TEST_WIRED_TLS_TPM2KEY TEST_CERT_DIR"/test-tpm2wrapped-key.pem"
/*****************************************************************************/
@@ -377,15 +378,15 @@ _test_8021x_cert_check_blob_full (NMConnection *con, const void *data, gsize len
#define _test_8021x_cert_check_blob(con, data) _test_8021x_cert_check_blob_full(con, data, NM_STRLEN (data))
static void
test_8021x_cert (void)
_test_8021x_cert_from_files (const char *cert, const char *key)
{
NMSetting8021x *s_8021x;
gs_unref_object NMConnection *con = nmtst_create_minimal_connection ("test-cert", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
GError *error = NULL;
gboolean success;
NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
gs_free char *full_TEST_WIRED_TLS_CA_CERT = nmtst_file_resolve_relative_path (TEST_WIRED_TLS_CA_CERT, NULL);
gs_free char *full_TEST_WIRED_TLS_PRIVKEY = nmtst_file_resolve_relative_path (TEST_WIRED_TLS_PRIVKEY, NULL);
gs_free char *full_TEST_WIRED_TLS_CA_CERT = nmtst_file_resolve_relative_path (cert, NULL);
gs_free char *full_TEST_WIRED_TLS_PRIVKEY = nmtst_file_resolve_relative_path (key, NULL);
/* test writing/reading of certificates of NMSetting8021x */
@@ -444,6 +445,18 @@ test_8021x_cert (void)
}
static void
test_8021x_cert (void)
{
_test_8021x_cert_from_files (TEST_WIRED_TLS_CA_CERT, TEST_WIRED_TLS_PRIVKEY);
}
static void
test_8021x_cert_tpm2key (void)
{
_test_8021x_cert_from_files (TEST_WIRED_TLS_CA_CERT, TEST_WIRED_TLS_TPM2KEY);
}
/*****************************************************************************/
static void
@@ -850,6 +863,7 @@ int main (int argc, char **argv)
g_test_add_func ("/core/keyfile/encode_key", test_encode_key);
g_test_add_func ("/core/keyfile/test_8021x_cert", test_8021x_cert);
g_test_add_func ("/core/keyfile/test_8021x_cert_tpm2key", test_8021x_cert_tpm2key);
g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read);
g_test_add_func ("/core/keyfile/test_team_conf_read/valid", test_team_conf_read_valid);
g_test_add_func ("/core/keyfile/test_team_conf_read/invalid", test_team_conf_read_invalid);