From 3a1ece8da1fdf2e2ca003d324389a2ed54eda4dd Mon Sep 17 00:00:00 2001 From: John Bland <106998124+jpbland1@users.noreply.github.com> Date: Fri, 27 Jan 2023 17:17:19 -0500 Subject: [PATCH] Add RSA key import methods to handle PEM and DER encoding directly (#252) --- certs/example-rsa-key.pem | 28 ++++++++++++ certs/include.am | 3 +- examples/keygen/keyimport.c | 89 +++++++++++++++++++++++++++++++------ src/tpm2_wrap.c | 89 +++++++++++++++++++++++++++++++++++++ wolftpm/tpm2_wrap.h | 42 +++++++++++++++++ 5 files changed, 236 insertions(+), 15 deletions(-) create mode 100644 certs/example-rsa-key.pem diff --git a/certs/example-rsa-key.pem b/certs/example-rsa-key.pem new file mode 100644 index 00000000..b534c087 --- /dev/null +++ b/certs/example-rsa-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCePbYR1SIZAL/2 +8FYbgpxynENgvHACM9LczZnsgVkZYxx3O9DTba2VTxhMN21i/aocJCzZB35qvz+R +ickyvWBqPDXauJEn9icPXgSknqxzw0ZATzL0wbq/Tk5T+oITFFCGJ8/baFoktOKu +iP5H50Dx6X2W1qNHiLkbGq7NbXHA8YG2wzK9kwikowSXQVB7pZ5bgjW2q73vIGSs +eW802f7I/30wbf4oR1vfk4OQursT9sl2CFLNt5bJSw6lFTm4BOgC7Q3bpHPzC/YK +uFYWKGeQL9GCsEZVWHCM6vzek6SNwQ0eoQ0i9IuF0os/0nJDwdXEZX9OoBhFT717 +svlxDXpFAgMBAAECggEABYIV6Jx/5ZloVTbr9GSxP+8PDFq61mTJ6fwxJ7Gf8ZmI +1+Cp5fYrJOeeK6cBRIEabwTWV86iOKKEGrOOYJkFdmU2pbCngtnXZbpK1JUeYSAy +vZHULv9gWgDmipdNeE8Md4MCwfspqh3uxw8HNOcIlHMhd0Ls55RLhzVAUO/GliXz +5HIDhohyQAUvPvkwz1yrPNn5BQwMlJBARc2OKSKf+pJrlFw1KJWR9TKzGvRzMbI4 +gwrq9BZ5LCX5y6C7BpuzXdySHXofwihPNmi1KU/88cWhas2E0Xz+p+N/ifmkquTN +3EqzqKBW+xobryM6X9JfQ6has211eUaZKNuU2/idKQKBgQC5rymu0UKHuAkr4uPS +NLGmaWb4p+kDNxbVyzS2ENjtoJ6JyEo/pZQrTG4S/kCWFgGsuztCbx+1Kgk0Pgwi +znaGvcfrjiP9XE1oVfMifA2JmH+drjASyjPqNfsf0BKQtlk0nZXwUO/C1FQ5vUU4 +lpmpx4EhTnucQ9E7r0+uXnQHTQKBgQDaKh4bBV7dLBF4ZxwCdydMMSZkBgckBiH7 +83BvyLW6I0GKXcFTa7KKLgTj41pXeWh6bmM9365+Cr8fxTZop28EfGRYFBMp08/g +wHpmS3NZ4moSgirJ+PhZsH+nBq89W75INR7BqV4SAc3n4lcwv9eBL9q0Q/YJZ1ph +NCKvz79y2QKBgFyDFPVwdQFBg/BFntRARLJwmUkR/1oGvG3QTHbZdfsOp25mR/fl ++yiHb+AupOciF7uDnUbALsAILYXF1C4TR6JiM5T8wJmev0JYcEaiH+yJ+isJehIi +hDMQqglzlYxcDZ3VVbrh2FLtjvklf7Nt9SlNqNx7ScLVVw2xjrWFgbGRAoGBAMjo +Wnsl0fu6Noh74/Z9RmpLJQCd8HuDTk6ZHCVFX91/1D6ZIo0xM+U+hfBbkfnWa5m8 +CJaVZDrcqK+YTQfJkVo/N6VJL3Coh9qBRvbnat4OvQI4bzE6n3LxME1fwYeu8ifL +C3zq/R92G+n8rbDOKqbkq/KwV2bHkBrOCVeA6NzZAoGACztyZbS5jCuSlPqk/xoN +EzX9Cev/GipF5tZMeOcQlty+anPg3TC70O06yZ1SIJKLzOOyoPCUDNrM2M5TCaau +vT0vW1GeNAryc+q9aOmFT3AlZ93Tfst+90Q+NJecEEhkO43tU5S1ZK2iVf9XAOV6 +ovHegJU35IUeaoyg23HjFWU= +-----END PRIVATE KEY----- diff --git a/certs/include.am b/certs/include.am index b3b0c68f..20bdce06 100644 --- a/certs/include.am +++ b/certs/include.am @@ -7,4 +7,5 @@ EXTRA_DIST += \ certs/ca-rsa.cnf \ certs/ca-ecc.cnf \ certs/wolf-ca-ecc-cert.pem \ - certs/wolf-ca-rsa-cert.pem + certs/wolf-ca-rsa-cert.pem \ + certs/example-rsa-key.pem diff --git a/examples/keygen/keyimport.c b/examples/keygen/keyimport.c index 1c0cf8ca..88a67830 100644 --- a/examples/keygen/keyimport.c +++ b/examples/keygen/keyimport.c @@ -40,14 +40,16 @@ static void usage(void) { printf("Expected usage:\n"); - printf("./examples/keygen/keyimport [keyblob.bin] [-ecc/-rsa] [-aes/xor]\n"); + printf("./examples/keygen/keyimport [keyblob.bin] [-ecc/-rsa] [-pem/-der] [-aes/xor]\n"); printf("* -ecc: Use RSA or ECC for keys\n"); printf("* -aes/xor: Use Parameter Encryption\n"); + printf("* -pem=[keyfile]/der: Key encoding type, none for binary. Optional pem key file defaults to ./certs/example-rsa-key.pem\n"); } int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]) { int rc; + int i; WOLFTPM2_DEV dev; WOLFTPM2_KEY storage; /* SRK */ WOLFTPM2_KEYBLOB impKey; @@ -55,6 +57,14 @@ int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]) TPM_ALG_ID paramEncAlg = TPM_ALG_NULL; WOLFTPM2_SESSION tpmSession; const char* outputFile = "keyblob.bin"; + byte derEncode = 0; + +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + byte pemEncode = 0; + FILE* pemFile = NULL; + const char* pemName = "./certs/example-rsa-key.pem"; + char pemBuf[WOLFTPM2_MAX_BUFFER]; +#endif if (argc >= 2) { if (XSTRCMP(argv[1], "-?") == 0 || @@ -67,20 +77,41 @@ int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]) if (argv[1][0] != '-') outputFile = argv[1]; } - while (argc > 1) { - if (XSTRCMP(argv[argc-1], "-ecc") == 0) { + /* i = 1 to skip binary */ + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "-ecc") == 0) { alg = TPM_ALG_ECC; } - else if (XSTRCMP(argv[argc-1], "-aes") == 0) { + else if (XSTRCMP(argv[i], "-aes") == 0) { paramEncAlg = TPM_ALG_CFB; } - else if (XSTRCMP(argv[argc-1], "-xor") == 0) { + else if (XSTRCMP(argv[i], "-xor") == 0) { paramEncAlg = TPM_ALG_XOR; } - else { - printf("Warning: Unrecognized option: %s\n", argv[argc-1]); + else if (XSTRCMP(argv[i], "-der") == 0) { + derEncode = 1; + } +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + else if (XSTRCMP(argv[i], "-pem") == 0) { + pemEncode = 1; + printf("Warning: No pem file specified, using default: %s\n", pemName); + } + else if (XSTRNCMP(argv[i], "-pem=", XSTRLEN("-pem=")) == 0) { + pemEncode = 1; + + if (XSTRLEN(argv[i] + XSTRLEN("-pem=")) == 0) { + printf("Warning: No pem file specified, using default: %s\n", pemName); + } + else { + pemName = (const char*)(argv[i] + XSTRLEN("-pem=")); + printf("Warning: No pem file specified, using default: %s\n", pemName); + } + } +#endif + /* we already got outfile */ + else if (i == 1 && argv[1][0] != '-') { + printf("Warning: Unrecognized option: %s\n", argv[i]); } - argc--; } XMEMSET(&storage, 0, sizeof(storage)); @@ -91,6 +122,11 @@ int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]) printf("\tKey Blob: %s\n", outputFile); printf("\tAlgorithm: %s\n", TPM2_GetAlgName(alg)); printf("\tUse Parameter Encryption: %s\n", TPM2_GetAlgName(paramEncAlg)); +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + if (pemEncode) { + printf("\tUse Pem Keyfile: %s\n", pemName); + } +#endif rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); if (rc != TPM_RC_SUCCESS) { @@ -121,12 +157,37 @@ int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]) XMEMCPY(impKey.handle.auth.buffer, gKeyAuth, impKey.handle.auth.size); if (alg == TPM_ALG_RSA) { - /* Import raw RSA private key into TPM */ - rc = wolfTPM2_ImportRsaPrivateKey(&dev, &storage, &impKey, - kRsaKeyPubModulus, (word32)sizeof(kRsaKeyPubModulus), - kRsaKeyPubExponent, - kRsaKeyPrivQ, (word32)sizeof(kRsaKeyPrivQ), - TPM_ALG_NULL, TPM_ALG_NULL); + if (derEncode == 1) { + rc = wolfTPM2_RsaPrivateKeyImportDer(&dev, &storage, &impKey, + kRsaKeyPrivDer, sizeof(kRsaKeyPrivDer), TPM_ALG_NULL, + TPM_ALG_NULL); + } +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + else if (pemEncode == 1) { + pemFile = XFOPEN(pemName, "r"); + + if (pemFile == NULL) + printf("Failed to read pem file %s\n", pemName); + + if (rc == 0) + rc = (int)XFREAD(pemBuf, 1, sizeof(pemBuf), pemFile); + + if (rc > 0) { + rc = wolfTPM2_RsaPrivateKeyImportPem(&dev, &storage, &impKey, + pemBuf, rc, NULL, TPM_ALG_NULL, TPM_ALG_NULL); + } + + XFCLOSE(pemFile); + } +#endif + else { + /* Import raw RSA private key into TPM */ + rc = wolfTPM2_ImportRsaPrivateKey(&dev, &storage, &impKey, + kRsaKeyPubModulus, (word32)sizeof(kRsaKeyPubModulus), + kRsaKeyPubExponent, + kRsaKeyPrivQ, (word32)sizeof(kRsaKeyPrivQ), + TPM_ALG_NULL, TPM_ALG_NULL); + } } else if (alg == TPM_ALG_ECC) { /* Import raw ECC private key into TPM */ diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 249502bf..a642f089 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -1903,6 +1903,7 @@ int wolfTPM2_LoadRsaPrivateKey_ex(WOLFTPM2_DEV* dev, return rc; } + int wolfTPM2_LoadRsaPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEY* key, const byte* rsaPub, word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz) @@ -2059,6 +2060,94 @@ int wolfTPM2_ReadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, #ifndef WOLFTPM2_NO_WOLFCRYPT #ifndef NO_RSA +int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev, + const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* input, + word32 inSz, TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg) +{ + int rc = 0; + int initRc = -1; + RsaKey key[1]; + word32 idx = 0; + word32 e; + byte n[RSA_MAX_SIZE / 8]; + byte d[RSA_MAX_SIZE / 8]; + byte p[RSA_MAX_SIZE / 8]; + byte q[RSA_MAX_SIZE / 8]; + word32 eSz = (word32)sizeof(e); + word32 nSz = (word32)sizeof(n); + word32 dSz = (word32)sizeof(d); + word32 pSz = (word32)sizeof(p); + word32 qSz = (word32)sizeof(q); + + if (dev == NULL || parentKey == NULL || keyBlob == NULL || input == NULL || + inSz == 0) { + rc = BAD_FUNC_ARG; + } + + if (rc == 0) + rc = initRc = wc_InitRsaKey(key, NULL); + + if (rc == 0) + rc = wc_RsaPrivateKeyDecode(input, &idx, key, inSz); + + if (rc == 0) { + rc = wc_RsaExportKey(key, (byte*)&e, &eSz, n, &nSz, d, &dSz, p, &pSz, q, + &qSz); + } + + if (rc == 0) { + rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, keyBlob, n, nSz, e, q, + qSz, scheme, hashAlg); + } + + if (initRc == 0) + wc_FreeRsaKey(key); + + return rc; +} + +#ifndef WOLFTPM2_NO_HEAP + +int wolfTPM2_RsaPrivateKeyImportPem(WOLFTPM2_DEV* dev, + const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, + const char* input, word32 inSz, char* pass, + TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg) +{ + int rc = 0; + byte* derBuf; + word32 derSz; + + if (dev == NULL || parentKey == NULL || keyBlob == NULL || input == NULL || + inSz == 0) { + return BAD_FUNC_ARG; + } + + /* der size is base 64 decode length */ + derSz = inSz * 3 / 4 + 1; + + derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + return MEMORY_E; + + rc = wc_KeyPemToDer((byte*)input, inSz, derBuf, derSz, pass); + + /* returns the number of bytes */ + if (rc > 0) { + rc = wolfTPM2_RsaPrivateKeyImportDer(dev, parentKey, keyBlob, derBuf, + (word32)rc, scheme, hashAlg); + } + /* shouldn't be possible to have a 0 length der, check anyways */ + else if (rc == 0) { + rc = BAD_FUNC_ARG; + } + + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rc; +} + +#endif /* WOLFTPM2_NO_HEAP */ + int wolfTPM2_RsaKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey, RsaKey* wolfKey) { diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 3e36c345..f48c5213 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -1019,6 +1019,48 @@ WOLFTPM_API int wolfTPM2_SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE #ifndef WOLFTPM2_NO_WOLFCRYPT #ifndef NO_RSA +/*! + \ingroup wolfTPM2_Wrappers + \brief Helper function to import Der rsa key directly + + \return TPM_RC_SUCCESS: successful + \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) + \return BAD_FUNC_ARG: check the provided arguments + + \param dev pointer to a TPM2_DEV struct + \param parentKey pointer to a WOLFTPM2_KEY struct, pointing to a Primary Key or TPM Hierarchy + \param keyBlob pointer to a struct of WOLFTPM2_KEY type, to import the rsa key to + \param input buffer holding the rsa der + \param inSz length of the input der buffer + \param scheme value of TPMI_ALG_RSA_SCHEME type, specifying the RSA scheme + \param hashAlg value of TPMI_ALG_HASH type, specifying the TPM hashing algorithm +*/ +WOLFTPM_API int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev, + const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* input, + word32 inSz, TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Helper function to import Der rsa key directly + + \return TPM_RC_SUCCESS: successful + \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) + \return BAD_FUNC_ARG: check the provided arguments + + \param dev pointer to a TPM2_DEV struct + \param parentKey pointer to a WOLFTPM2_KEY struct, pointing to a Primary Key or TPM Hierarchy + \param keyBlob pointer to a struct of WOLFTPM2_KEY type, to import the rsa key to + \param input buffer holding the rsa pem + \param inSz length of the input pem buffer + \param pass optional password of the key + \param scheme value of TPMI_ALG_RSA_SCHEME type, specifying the RSA scheme + \param hashAlg value of TPMI_ALG_HASH type, specifying the TPM hashing algorithm +*/ +WOLFTPM_API int wolfTPM2_RsaPrivateKeyImportPem(WOLFTPM2_DEV* dev, + const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, + const char* input, word32 inSz, char* pass, + TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg); + /*! \ingroup wolfTPM2_Wrappers \brief Extract a RSA TPM key and convert it to a wolfcrypt key