void DuplicateImportRsaSample(Tpm2 tpm, TestContext testCtx) { TpmAlgId nameAlg = Substrate.Random(TpmCfg.HashAlgs); var policy = new PolicyTree(nameAlg); policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.Duplicate)); var inPub = new TpmPublic(nameAlg, ObjectAttr.Sign | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin, policy.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsassa(Substrate.Random(TpmCfg.HashAlgs)), Substrate.Random(TpmCfg.RsaKeySizes), 0), new Tpm2bPublicKeyRsa()); TpmHandle hKey = Substrate.CreateAndLoad(tpm, inPub, out TpmPublic pub); // Duplicate TpmPrivate priv = TpmHelper.GetPlaintextPrivate(tpm, hKey, policy); tpm.FlushContext(hKey); // Import TpmPrivate privImp = tpm.Import(Substrate.LoadRsaPrimary(tpm), null, pub, priv, null, new SymDefObject()); } // SimpleDuplicateImportRsaSample
void TestCertifyX509_1(Tpm2 tpm, TestContext testCtx) { testCtx.ReportParams("Test phase: TestCertifyX509_1"); var policy = new PolicyTree(TpmAlgId.Sha256); policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.CertifyX509)); var keyTemplate = new TpmPublic( TpmAlgId.Sha256, ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.UserWithAuth | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin, policy.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa() ); // Make two keys TpmPublic certifyingKeyPub, keyToBeCertifiedPub; TpmHandle hCertifyingKey = Substrate.CreatePrimary(tpm, keyTemplate, out certifyingKeyPub); TpmHandle hKeyToBeCertified = Substrate.CreatePrimary(tpm, keyTemplate, out keyToBeCertifiedPub); var partialCert = CertifyX509Support.MakeExemplarPartialCert(); var partialCertBytes = partialCert.GetDerEncoded(); // If you want to paste in your own hex put it here and s //var partialCertBytes = Globs.ByteArrayFromHex("01020304"); AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); sess.RunPolicy(tpm, policy); // I used this to test that the auth is OK. Of course you need to change the PolicyCommandCode above //var attestInfo = tpm[sess].Certify(hKeyToBeCertified, hCertifyingKey, new byte[0], new NullSigScheme(), out var legacySignature); byte[] tbsHash; ISignatureUnion signature; byte[] addedTo = tpm[sess].CertifyX509(hKeyToBeCertified, hCertifyingKey, new byte[0], new NullSigScheme(), partialCertBytes, out tbsHash, out signature); var addedToCert = AddedToCertificate.FromDerEncoding(addedTo); var returnedCert = CertifyX509Support.AssembleCertificate(partialCert, addedToCert, ((SignatureRsa)signature).GetTpmRepresentation()); // Does the expected hash match the returned hash? var tbsBytes = returnedCert.GetTbsCertificate(); var expectedTbsHash = TpmHash.FromData(TpmAlgId.Sha256, tbsBytes); Debug.Assert(Globs.ArraysAreEqual(expectedTbsHash.HashData, tbsHash)); // If you get this far we can check the cert is properly signed but we'll need to do a // bit of TPM<->Bouncy Castle data type conversion. tpm.FlushContext(hCertifyingKey); tpm.FlushContext(hKeyToBeCertified); } // TestCertifyX509_1
void TestCertifyX509(Tpm2 tpm, TestContext testCtx) { if (!TpmCfg.IsImplemented(TpmCc.CertifyX509)) { Substrate.WriteToLog("TestCertifyX509 skipped", ConsoleColor.DarkCyan); return; } ObjectAttr attr = ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.UserWithAuth | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin; var policy = new PolicyTree(TpmAlgId.Sha256); policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.CertifyX509)); var keyTemplateRsa = new TpmPublic(TpmAlgId.Sha256, attr, policy.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa() ); var keyTemplateEcc = new TpmPublic(TpmAlgId.Sha256, attr, policy.GetPolicyDigest(), new EccParms(new SymDefObject(), new SchemeEcdsa(TpmAlgId.Sha256), EccCurve.NistP256, new NullKdfScheme()), new EccPoint() ); var keyTemplatePss = new TpmPublic(TpmAlgId.Sha256, attr, policy.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsapss(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa() ); TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplateRsa, policy, "RsaWithRsa.1"); TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplateEcc, policy, "RsaWithEcc.1"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplateEcc, policy, "EccWithEcc.1"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplateRsa, policy, "EccWithRsa.1"); TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplatePss, policy, "RsaWithPss.1"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplatePss, policy, "EccWithPss.1"); attr &= ~(ObjectAttr.Restricted | ObjectAttr.FixedParent | ObjectAttr.FixedTPM); keyTemplateRsa.objectAttributes = attr; keyTemplateEcc.objectAttributes = attr; keyTemplatePss.objectAttributes = attr; TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplateRsa, policy, "RsaWithRsa.2"); TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplateEcc, policy, "RsaWithEcc.2"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplateEcc, policy, "EccWithEcc.2"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplateRsa, policy, "EccWithRsa.2"); TestCertifyX509Impl(tpm, testCtx, keyTemplateRsa, keyTemplatePss, policy, "RsaWithPss.2"); TestCertifyX509Impl(tpm, testCtx, keyTemplateEcc, keyTemplatePss, policy, "EccWithPss.2"); } // TestCertifyX509
void ActivateAikSample(Tpm2 tpm, TestContext testCtx) { // Use an RSA primary key in the Endorsement hierarchy (EK) to 'activate' // another primary in the Endorsement hierarchy (AIK). // Note: this procedure can be used to activate a key in the Storage hierarchy, too. // "Activation" means secure passing sensitive data generated by a CA (e.g. // a symmetric key protecting a freshly generated certificate), so that only // a device with the TPM owning the target AIK and EK can access these data. // Create a primary key that we will certify. ////////////////////////////////////////////////////////////////////////////// // Device side code ////////////////////////////////////////////////////////////////////////////// // Name algorithm of the new AIK TpmAlgId nameAlg = TpmAlgId.Sha256; // The key to be certified needs a policy. It can be ANY policy, but here // it is configured to allow AIK usage only with the following commands var policyAIK = new PolicyTree(nameAlg); var policyOR = new TpmPolicyOr(); policyAIK.SetPolicyRoot(policyOR); policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.ActivateCredential, "Activate")); policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Certify, "Certify")); policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.CertifyCreation, "CertifyCreation")); policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Quote, "Quote")); var inAIKPub = new TpmPublic(nameAlg, ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin, policyAIK.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa()); TpmPublic AIKpub; var inSens = new SensitiveCreate(Substrate.RandomAuth(nameAlg), null); CreationData creationData; byte[] creationHash; TkCreation creationTk; TpmHandle hAIK = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inAIKPub, null, null, out AIKpub, out creationData, out creationHash, out creationTk); // An alternative using test substrate helper //TpmHandle hAIK = Substrate.CreatePrimary(tpm, inAIKPub, TpmRh.Endorsement); // Normally a device would have a pre-provisioned persistent EK with the above handle TpmHandle hEK = new TpmHandle(0x81010001); // Get its public part TpmPublic EKpub = null; // In a test environment the real EK may be absent. In this case use // a primary key temporarily created in the Endorsement hierarchy. byte[] name, qname; tpm._AllowErrors() .ReadPublic(hEK, out name, out qname); if (!tpm._LastCommandSucceeded()) { var inEKpub = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin, new byte[] { 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8, 0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24, 0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64, 0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa }, new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), null, 2048, 0), new Tpm2bPublicKeyRsa()); inSens = new SensitiveCreate(null, null); hEK = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inEKpub, null, null, out EKpub, out creationData, out creationHash, out creationTk); } // Marshal public parts of AIK and EK byte[] AIKpubBytes = AIKpub.GetTpmRepresentation(); byte[] EKpubBytes = EKpub.GetTpmRepresentation(); // Here the device uses network to pass AIKpubBytes and EKpubBytes (as well as // the EK certificate) to CA service. ////////////////////////////////////////////////////////////////////////////// // Service (CA) side code ////////////////////////////////////////////////////////////////////////////// // Unmarshal AIKpub and EKpub (and EK certificate) var m = new Marshaller(AIKpubBytes); AIKpub = m.Get <TpmPublic>(); m = new Marshaller(EKpubBytes); EKpub = m.Get <TpmPublic>(); // Symmetric key to be used by CA to encrypt the new certificate it creates for AIK byte[] secretKey = Substrate.RandomBytes(32); // Here CA does the following (the sample does not show this code): // - Validates EK certificate // - Generates a new certificate for AIK (AIKcert) // - Encrypts AIKcert with secretKey // Create an activation blob // Internal wrapper key encrypted with EKpub to be used by TPM2_ActivateCredential() command. byte[] encSecret; // An encrypted and HMACed object tied to the destination TPM. It contains // 'secret' to be extracted by the successful TPM2_ActivateCredential() command // (that can only succeeed on the TPM that originated both EK and AIK). IdObject certInfo; // Run TSS.Net equivalent of TPM2_MakeCredential() command (convenient for the server side, // as it will likely be faster than the TPM transaction and allows concurrent execution). certInfo = EKpub.CreateActivationCredentials(secretKey, AIKpub.GetName(), out encSecret); // Marshal certInfo // IdObject data type requires customized marshaling m = new Marshaller(); m.Put(certInfo.integrityHMAC.Length, "integrityHMAC.Length"); m.Put(certInfo.integrityHMAC, "integrityHMAC"); m.Put(certInfo.encIdentity.Length, "encIdentity"); m.Put(certInfo.encIdentity, "encIdentity.Length"); byte[] certInfoBytes = m.GetBytes(); // Here the CA passes certInfoBytes and encSecret (as well as the encrypted // AIK certificate) back to the device via network. ////////////////////////////////////////////////////////////////////////////// // Device side code again ////////////////////////////////////////////////////////////////////////////// // Unmarshal certInfo and encSecret (and encrypted AIK certificate) m = new Marshaller(certInfoBytes); int len = m.Get <int>(); certInfo.integrityHMAC = m.GetArray <byte>(len); len = m.Get <int>(); certInfo.encIdentity = m.GetArray <byte>(len); // encSecret is a byte array, so, normally, no special unmarshalling is required // Create policy session to authorize AIK usage AuthSession sessAIK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg); sessAIK.RunPolicy(tpm, policyAIK, "Activate"); // Create policy description and corresponding policy session to authorize EK usage var policyEK = new PolicyTree(EKpub.nameAlg); policyEK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Endorsement, false, 0, null, null)); AuthSession sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, EKpub.nameAlg); sessEK.RunPolicy(tpm, policyEK); byte[] recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo, encSecret); testCtx.AssertEqual("Secret.1", recoveredSecretKey, secretKey); // Here the device can use recoveredSecretKey to decrypt the AIK certificate ////////////////////////////////////////////////////////////////////////////// // End of activation sequence ////////////////////////////////////////////////////////////////////////////// // // Now prepare activation using the TPM built-in command // byte[] encSecret2 = null; IdObject certInfo2 = tpm.MakeCredential(hEK, secretKey, AIKpub.GetName(), out encSecret2); // Reinitialize policy sessions tpm.PolicyRestart(sessAIK); sessAIK.RunPolicy(tpm, policyAIK, "Activate"); tpm.PolicyRestart(sessEK); sessEK.RunPolicy(tpm, policyEK); recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo2, encSecret2); testCtx.AssertEqual("Secret.2", recoveredSecretKey, secretKey); // Cleanup tpm.FlushContext(sessAIK); tpm.FlushContext(sessEK); tpm.FlushContext(hAIK); if (hEK.handle != 0x81010001) { tpm.FlushContext(hEK); } } // ActivateAikSample
/// <summary> /// Activates an identity key within the TPM device. /// </summary> /// <param name="encryptedKey">The encrypted identity key.</param> public override void ActivateIdentityKey(byte[] encryptedKey) { if (Logging.IsEnabled) { Logging.Enter(this, $"{encryptedKey}", nameof(ActivateIdentityKey)); } Destroy(); // Take the pieces out of the container var m = new Marshaller(encryptedKey, DataRepresentation.Tpm); Tpm2bIdObject cred2b = m.Get <Tpm2bIdObject>(); byte[] encryptedSecret = new byte[m.Get <ushort>()]; encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret"); TpmPrivate dupBlob = m.Get <TpmPrivate>(); byte[] encWrapKey = new byte[m.Get <ushort>()]; encWrapKey = m.GetArray <byte>(encWrapKey.Length, "encWrapKey"); UInt16 pubSize = m.Get <UInt16>(); _idKeyPub = m.Get <TpmPublic>(); byte[] cipherText = new byte[m.Get <ushort>()]; cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo"); // Setup the authorization session for the EK var policyNode = new TpmPolicySecret(TpmHandle.RhEndorsement, false, 0, Array.Empty <byte>(), Array.Empty <byte>()); var policy = new PolicyTree(_ekPub.nameAlg); policy.SetPolicyRoot(policyNode); AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg); ekSession.RunPolicy(_tpm2, policy); // Perform the activation ekSession.Attrs &= ~SessionAttr.ContinueSession; _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential( new TpmHandle(TPM_20_SRK_HANDLE), new TpmHandle(TPM_20_EK_HANDLE), cred2b.credential, encryptedSecret); TpmPrivate importedKeyBlob = _tpm2.Import( new TpmHandle(TPM_20_SRK_HANDLE), _activationSecret, _idKeyPub, dupBlob, encWrapKey, new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb)); _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub); // Persist the key in NV TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE); _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle); // Unload the transient copy from the TPM _tpm2.FlushContext(_idKeyHandle); _idKeyHandle = hmacKeyHandle; if (Logging.IsEnabled) { Logging.Exit(this, $"{encryptedKey}", nameof(ActivateIdentityKey)); } }
/// <summary> /// Activates a symmetric identity within the Hardware Security Module. /// </summary> /// <param name="activation">The authentication challenge key supplied by the service.</param> public override void ActivateSymmetricIdentity(byte[] activation) { Destroy(); // Take the pieces out of the container var m = new Marshaller(activation, DataRepresentation.Tpm); byte[] credentialBlob = new byte[m.Get <ushort>()]; credentialBlob = m.GetArray <byte>(credentialBlob.Length, "credentialBlob"); byte[] encryptedSecret = new byte[m.Get <ushort>()]; encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret"); TpmPrivate dupBlob = m.Get <TpmPrivate>(); byte[] encWrapKey = new byte[m.Get <ushort>()]; encWrapKey = m.GetArray <byte>(encryptedSecret.Length, "encWrapKey"); UInt16 pubSize = m.Get <UInt16>(); _idKeyPub = m.Get <TpmPublic>(); byte[] cipherText = new byte[m.Get <ushort>()]; cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo"); // Setup the authorization session for the EK var policyNode = new TpmPolicySecret( TpmHandle.RhEndorsement, _ekAuth ?? Array.Empty <byte>(), new AuthValue(), false, 0, Array.Empty <byte>(), Array.Empty <byte>()); var policy = new PolicyTree(_ekPub.nameAlg); policy.SetPolicyRoot(policyNode); AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg); ekSession.RunPolicy(_tpm2, policy); // Perform the activation ekSession.Attrs &= ~SessionAttr.ContinueSession; _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential( new TpmHandle(TPM_20_SRK_HANDLE), new TpmHandle(TPM_20_EK_HANDLE), credentialBlob, encryptedSecret); TpmPrivate importedKeyBlob = _tpm2.Import( new TpmHandle(TPM_20_SRK_HANDLE), _activationSecret, _idKeyPub, dupBlob, encWrapKey, new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb)); _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub); // Persist the key in NV TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE); _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle); // Unload the transient copy from the TPM _tpm2.FlushContext(_idKeyHandle); _idKeyHandle = hmacKeyHandle; // Unwrap the URI byte[] clearText = SymmCipher.Decrypt( new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), _activationSecret, new byte[16], cipherText); UnicodeEncoding unicode = new UnicodeEncoding(); string uriData = unicode.GetString(clearText); int idx = uriData.IndexOf('/'); if (idx > 0) { string hostName = uriData.Substring(0, idx); string deviceId = uriData.Substring(idx + 1); // Persist the URI ProvisionUri(hostName, deviceId); } }