Initial TPM 2.0 PCP_KEY_BLOB_WIN8 support

This commit is contained in:
Michael Grafnetter 2019-08-12 12:20:17 +02:00
parent cb9a874376
commit 5d1d3392fd
3 changed files with 66 additions and 3 deletions

View File

@ -265,7 +265,7 @@ namespace DSInternals.Common.Test
*/
[TestMethod]
public void KeyCredential_Parse_DeviceKey()
public void KeyCredential_Parse_DeviceKey_RSA()
{
byte[] blob = "0002000020000173E6BEB8A9B5B0828388476E7BFDD5F8E7A113EC0807EF25C0FBCF39CEB4311120000299DA9872C6EB63882C1200B3B2BECCF3C582418F9FC56905963ADA62E52DF3B31B0103525341310008000003000000000100000000000000000000010001B40D7085917A30D2F0D434FEF57477099FFFEBC79F28EB414BB75C86B4B5CAC0D9E6ACA86EB8126EDB724AF40FD773A7F14732A7ED862A0828A367194FB3D61EC6EA15CB450597F3BAA64E4974B255D0819E06B58B47C858C384B88E27D0EA52F962A592B115EEA3AA21A6A5185DD58F5D779118717FD07C8CAF50F5F078BFC3AED355BB2F78E8C48C4F6DA2BD679CDCD1C0ED8320F5BC9EC6545E4E7CD9AA7642E180E2A3AD20BCCCF3C30A34BEDF27835528BE955A7599D42869339218936E78FF6D46BEEE0097F2DECB2791F7842BB55BA639A44F659F547B5AA1E959370ACBC908248D05893D539F7E4E6BE834CCF0A3101879717585D015992B3C9407410100040201000500100006E377F547D0D20A4A8ACAE0501098BDE40200070100080008405E47D3C301D401080009405E47D3C301D401".HexToBinary();
var key = new KeyCredential(blob, DummyDN);
@ -282,6 +282,28 @@ namespace DSInternals.Common.Test
CollectionAssert.AreEqual(blob, serialized);
}
[TestMethod]
public void KeyCredential_Parse_DeviceKey_TPM()
{
byte[] blob = "000200002000013A86065B23BCC4190BC77C76774425B4C6AFF7EE35958D2C1B128830F17D89FD2000029D737FFB5C056741291CBAD933714FA911446B958E8FA3A802A96414B64849B40403035043504D3800000002000000020000003C010000E00000000000000000000000B00000000000000000000000000000000000000000000000013A0001000B0003047200209DFFCBF36C383AE699FB9868DC6DCB89D7153884BE2803922C124158BFAD22AE00060080004300100800000000000100A88E8812C2C35E42CFFF100024CAAEFD12C04929DF925FD5AB7F26B3DF92CEA60410B9792B789BB122323502CCE394A8CC246D01ACA04E5327C4D79F3339FA54F61F25F126649ECF3A70B7847915222BD54E470550E2449F9FDB43B2EB55377971935C9727DE419E2A9CCBDCE6A97F0F84F56272E65B9920AE16DE3AF350F7CC29C6A492BB1D703CC0AD23253D0E828FFBDBEAC21E0E0C1705A5E4894264EA357A13D36A62B74CB362705CB35244DB61FABF8B584C57F22F571858594D046485A50BF0D84D68EB69C1C8F92F99FE07080E2AC69A77DA12097F70B8102D7DDA19EB6C60DD2828815E4A0008A0E2A0BF363720B49F897B0D3109B2A4BC119A3AF700DE0020F9EDC3869F8ED64C5DC24366AFC3288DAB0E00A1673C2170C43F733B728282860010BA276857DCACF6D1A1C18FF161089380D8736D754A12C81D004B8296A5F077A0649E44540775FC179A03D0B75B81DB194AF3F47ACC4BB228C181065FEDDA86BB2DF704261391217662C49C7A719E08F535467CD217D645C6AF31CAC3D8350735CA358D006448276105C8392978CB1BEC89A515D0AB402DF476947061F8581CE91C5AB75919E5110B027A1809A581F0224FED448E8A1932AFE2954B0224B6512F8223678079EFD2B25255FE2D829D514C12C95A79E31C949C341D0000000600208FCD2169AB92694E0C633F1AB772842B8241BBC20288981FC7AC1EDDC1FDDB0E0020E529F5D6112872954E8ED6605117B757E237C6E19513A949FEE1F204C458023A0020AF2CA569699C436A21006F1CB8A2756C98BC1C765A3559C5FE1C3F5E7228A7E70020C413A847B11112B1CBDDD4ECA4DAAA15A1852C1C3BBA57461D257605F3D5AF5300000020048E9A3ACE08583F79F344FF785BBEA9F07AC7FA3325B3D49A21DD5194C65850010004020100050010000672A8E9CFFF135147A777AEC88C30A76202000701000800086885D2B95D49D5010800096885D2B95D49D501".HexToBinary();
// Parse
var key = new KeyCredential(blob, DummyDN);
Assert.AreEqual(KeyCredentialVersion.Version2, key.Version);
Assert.AreEqual(KeyUsage.STK, key.Usage);
Assert.AreEqual(KeySource.AD, key.Source);
Assert.AreEqual(KeyFlags.None, key.CustomKeyInfo.Flags);
Assert.AreEqual("OoYGWyO8xBkLx3x2d0QltMav9+41lY0sGxKIMPF9if0=", key.Identifier);
Assert.AreEqual(key.LastLogonTime, key.CreationTime);
Assert.AreEqual("2019-08-02T18:11:37.5665512Z", key.CreationTime.ToUniversalTime().ToString("o"));
Assert.AreEqual(0x304, key.RawKeyMaterial.Length);
// Serialize
byte[] serialized = key.ToByteArray();
Assert.AreEqual(blob.Length, serialized.Length);
CollectionAssert.AreEqual(blob, serialized);
}
[TestMethod]
public void KeyCredential_Parse_ComputerKey()
{

View File

@ -108,6 +108,7 @@
return null;
}
// FIDO keys typically use ECC instead of RSA, but we try to extract the RSA key anyway:
var fidoKey = this.FidoKeyMaterial;
if (fidoKey != null && fidoKey.AuthenticatorData.AttestedCredentialData.CredentialPublicKey.Type == COSE.KeyType.RSA)
{
@ -116,12 +117,20 @@
if(this.Usage == KeyUsage.NGC || this.Usage == KeyUsage.STK)
{
// The RSA public key can be stored in at least 3 different formats.
if (this.RawKeyMaterial.IsBCryptRSAPublicKeyBlob())
{
// This public key is in DER format. This is typically true for device/computer keys.
return this.RawKeyMaterial.ImportRSAPublicKeyBCrypt();
}
else
else if(this.RawKeyMaterial.IsTPM20PublicKeyBlob())
{
// This public key is encoded as PCP_KEY_BLOB_WIN8. This is typically true for device keys protected by TPM.
// The PCP_KEY_BLOB_WIN8 structure is not yet supported by DSInternals.
return null;
}
else if(this.RawKeyMaterial.IsDERPublicKeyBlob())
{
// This public key is encoded as BCRYPT_RSAKEY_BLOB. This is typically true for user keys.
return this.RawKeyMaterial.ImportRSAPublicKeyDER();

View File

@ -10,6 +10,10 @@ namespace DSInternals.Common
{
private const int BCryptKeyBlobHeaderSize = 6 * sizeof(uint);
private const uint BCryptRSAPublicKeyMagic = 0x31415352; // "RSA1" in ASCII
private const int TPM20KeyBlobHeaderSize = 4 * sizeof(int) + 9 * sizeof(uint);
private const uint TPM20PublicKeyMagic = 0x4d504350; // "MPCP" in ASCII
private const byte DERSequenceTag = 0x30;
private const int DERPublicKeyMinSize = 260; // At least 2K RSA modulus + 3B public exponent + 1B sequence tag
/// <summary>
/// OID 1.2.840.113549.1.1.1 - Identifier for RSA encryption for use with Public Key Cryptosystem One defined by RSA Inc.
@ -84,7 +88,7 @@ namespace DSInternals.Common
}
/// <summary>
/// CHecks whether the input blob is in the BCRYPT_RSAKEY_BLOB format.
/// Checks whether the input blob is in the BCRYPT_RSAKEY_BLOB format.
/// </summary>
public static bool IsBCryptRSAPublicKeyBlob(this byte[] blob)
{
@ -96,5 +100,33 @@ namespace DSInternals.Common
// Check if the byte sequence starts with the magic
return BitConverter.ToUInt32(blob, 0) == BCryptRSAPublicKeyMagic;
}
/// <summary>
/// Checks whether the input blob is in the PCP_KEY_BLOB_WIN8 format.
/// </summary>
public static bool IsTPM20PublicKeyBlob(this byte[] blob)
{
if (blob == null || blob.Length < TPM20KeyBlobHeaderSize)
{
return false;
}
// Check if the byte sequence starts with the magic
return BitConverter.ToUInt32(blob, 0) == TPM20PublicKeyMagic;
}
/// <summary>
/// Checks whether the input blob is a DER-encoded public key.
/// </summary>
public static bool IsDERPublicKeyBlob(this byte[] blob)
{
if (blob == null || blob.Length < DERPublicKeyMinSize)
{
return false;
}
// Check if the byte sequence starts with a DER sequence tag. This is a very vague test.
return blob[0] == DERSequenceTag;
}
}
}