I'm using a TPM to generate key pairs on-the-fly and eventually I'd want to format and output the public portion of a pair to a file, so it can be used easily by third parties.
To address the TPM, I'm using the TSS.MSR C++ API
After successfully creating a RSA2048 primary key with the following template:
TPMT_PUBLIC keyDescription(TPM_ALG_ID::SHA256,
TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM |
TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth,
nullVector,
TPMS_RSA_PARMS(TPMT_SYM_DEF_OBJECT(TPM_ALG_ID::_NULL, 0, TPM_ALG_ID::_NULL),
TPMS_SCHEME_RSASSA(TPM_ALG_ID::SHA256), 2048, 65537),
TPM2B_PUBLIC_KEY_RSA(nullVector));
output of tpm.ReadPublic(primaryKey)
reads as follows:
class ReadPublicResponse
{
UINT16 outPublicSize = 0xffff (65535)
TPMT_PUBLIC outPublic = class TPMT_PUBLIC
{
TPM_ALG_ID type = RSA (0x1)
TPM_ALG_ID nameAlg = SHA256 (0xb)
TPMA_OBJECT objectAttributes = fixedTPM |
fixedParent |
sensitiveDataOrigin |
userWithAuth |
encrypt
(0x40072)
UINT16 authPolicySize = 0x00 (0)
BYTE[] authPolicy = []
TPMU_PUBLIC_PARMS parameters = class TPMS_RSA_PARMS
{
TPMT_SYM_DEF_OBJECT symmetric = class TPMT_SYM_DEF_OBJECT
{
TPM_ALG_ID algorithm = _NULL (0x10)
UINT16 keyBits = 0xcdcd (52685)
TPM_ALG_ID mode = ? (0xcdcd)
}
TPM_ALG_ID schemeScheme = RSASSA (0x14)
TPMU_ASYM_SCHEME scheme = class TPMS_SIG_SCHEME_RSASSA
{
TPM_ALG_ID hashAlg = SHA256 (0xb)
}
UINT16 keyBits = 0x800 (2048)
UINT32 exponent = 0x10001 (65537)
}
TPMU_PUBLIC_ID unique = class TPM2B_PUBLIC_KEY_RSA
{
UINT16 size = 0x100 (256)
BYTE[] buffer = [a1f2152a f32f05ba fb8bd712 dde41bbc 1ec60134 dfba6dc3 88d18215 9affe8b0 5ca27d55 488d65df 8ac87496 4afe003c 701a82b0 5422797e 82347463 81a89a68 08066973 27ed9454 6efe12c8 ed454a3d 7ef3991f 04639a10 dafb6261 56
3fabb1 2f81feb0 0e2bd6f7 bb0ea93c ec735371 53578dce 939486a2 a77c740b 69cef375 b34b3b5e 6a7224f9 3444873a 2c5de6b5 a1e954ec 2e8db8ad 16876137 f3101c84 fcf0009c e338d83c a94f6dca a25098d0 0a120c03 bc165a51 adf09476 4ec22a0d 0c8ab5c1 34e819
40 3255404e 884817a8 9eb1c705 e2f3f36b 772d71e5 3ea42bef 310eb972 91734553 276b7cbf 00d2a471 a698478b 0d7daa3b 3abd1c39 6f877c5f]
}
}
UINT16 nameSize = 0x22 (34)
BYTE[] name = [000b04d3 b7e1a981 edcb0ab7 0b3a613c aece385b 1137807b c5ecdf35 4999f70f 4abd]
UINT16 qualifiedNameSize = 0x22 (34)
BYTE[] qualifiedName = [000b9017 ad0262c1 ebf46346 edf8046a 0784ce4b c7a3c446 5d6b087c 5e55133d 9fa0]
}
What's the simplest way of serializing the key data into something a third party can comprehend (pem, der, ...) - do I have everything I need?
This can be achieved with libraries such as Botan or OpenSSL. It is quite straight forward with Botan:
auto rsaPublicKey = Botan::RSA_PublicKey(Botan::BigInt(modulus), exponent);
std::cout << Botan::X509::PEM_encode(rsaPublicKey);
Output:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjpnwa0nQEcizailiN487
K5xazxax7vqNuxdgJnVb8sOG0jLCpLuLpsit5MD7V8q9ks7GLRrSSc1cam0H1C0a
v9NHZTlAP+KGI1h68xDS8kr08Af3GHN7pnbR4nh5kez/3nNMx7mEmenUZ4+YmouF
xBotH2ZhwOhs/Mw1IGw29c3lI6hvGwcHfGPHPTRKQoN6QG4IFQLNI+eF9W5YJXhA
rDFNn1IodQ6OsIYg3te2HeyqVS7B5UQSOJr4UG8+/I08FRiQ2D4Jeb6Fz6jQsznc
ng6zqNfgBGkSQWuLisd0QRjI3ekdubIAENPKahRHbmQdzjnhhpCimy7XcuA55aZN
5wIDAQAB
-----END PUBLIC KEY-----
Additionally, verify the key is not ill-formed with openSSL:
$ openssl rsa -pubin -in pubkey.pem -text --noout