/// <summary> /// Validate the tester by emulating the actions of the TPM /// </summary> internal static void TestTester() { var random = new SecureRandom(); // Algorithms to test var algInfo = new[] { new { genner = (IAsymmetricCipherKeyPairGenerator) new ECKeyPairGenerator(), strength = 256, signingAlgorithm = "SHA256WITHECDSA" }, new { genner = (IAsymmetricCipherKeyPairGenerator) new RsaKeyPairGenerator(), strength = 2048, signingAlgorithm = "SHA256WITHRSAENCRYPTION" } }; foreach (var keyType in algInfo) { // Make a two keys of the specified algorithm var keyGenerationParameters = new KeyGenerationParameters(random, keyType.strength); keyType.genner.Init(keyGenerationParameters); var signingKey = keyType.genner.GenerateKeyPair(); var toBeCertifiedKeyPair = keyType.genner.GenerateKeyPair(); // Make the partial certificate that is input to the TPM PartialCertificate partialCert = MakeExemplarPartialCert(); // Simulate the actions of the TPM. This returns both the full and partial (AddedTo) certificate // The full certitificate is just for debugging var certTuple /*(CompleteCertificate, AddedTo)*/ = SimulateX509Certify(partialCert, toBeCertifiedKeyPair.Public, signingKey.Private, keyType.signingAlgorithm); X509Certificate CompleteCertificate = certTuple.Item1; AddedToCertificate AddedTo = certTuple.Item2; // Is the full certificate OK (it certainly should be) CompleteCertificate.Verify(signingKey.Public); // Debugging help... DebugPrintHex(CompleteCertificate.GetEncoded(), "ActualCert"); // When using TPM2_CertifyX509() the TPM does not return the whole certificate: it returns the // parts of the certificate that were not originally provided in partialCertificate in a data // structure called AddedTo, as well as the signature. The caller/TSS has to recosntruct // the full certificate. var signature = CompleteCertificate.GetSignature(); var finishedCert = AssembleCertificate(partialCert, AddedTo, signature); DebugPrintHex(finishedCert.GetEncoded(), "AssembledCert"); // sanity check that we can parse a DER encoded AddedTo (this is what the TPM will return.) var addedToBytes = AddedTo.GetDerEncoded(); var reconstructedAddedTo = AddedToCertificate.FromDerEncoding(addedToBytes); AssertByteArraysTheSame(addedToBytes, reconstructedAddedTo.ToAsn1Object().GetDerEncoded()); // Sanity AssertByteArraysTheSame(CompleteCertificate.GetEncoded(), finishedCert.GetEncoded()); // and more sanity finishedCert.Verify(signingKey.Public); } return; }
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
/// <summary> /// To be called after the TPM has returned the addedTo part of the certificate and the signature. Assembles /// partialCert, addedTo, and the signature to form an actual X.509 certificate encapsulated in a Bouncy Castle /// X509Certificate /// </summary> /// <param name="partialCert"></param> /// <param name="addedToCertificate"></param> /// <param name="signature"></param> /// <returns></returns> internal static X509Certificate AssembleCertificate( PartialCertificate partialCert, AddedToCertificate addedToCertificate, byte[] signatureBytes) { Debug.Assert(addedToCertificate.Version.ToString() == "2"); var signature = new DerBitString(signatureBytes); var sigAlgID = partialCert.SigAlgID ?? addedToCertificate.SigAlgID; // Assemble TBS. Start with a vector which we will later convert to a sequence Asn1EncodableVector tbsContents = new Asn1EncodableVector(); tbsContents.Add(new DerTaggedObject(0, new DerInteger(BigInteger.ValueOf(2)))); tbsContents.Add(addedToCertificate.SerialNumber); tbsContents.Add(sigAlgID); tbsContents.Add(partialCert.Issuer); tbsContents.Add(new CertificateValidity(partialCert.NotBefore, partialCert.NotAfter)); tbsContents.Add(partialCert.Subject); tbsContents.Add(addedToCertificate.SubjectPublicKeyInfo); // Add optional components if (partialCert.IssuerUniqueId != null) { tbsContents.Add(new DerTaggedObject(false, 1, new DerBitString(partialCert.IssuerUniqueId))); } if (partialCert.SubjectUniqueId != null) { tbsContents.Add(new DerTaggedObject(false, 2, new DerBitString(partialCert.SubjectUniqueId))); } if (partialCert.Extensions != null) { tbsContents.Add(new DerTaggedObject(3, partialCert.Extensions.ToAsn1Object())); } // Convert the vector to an ASN SEQUENCE var tbsCertificate = new DerSequence(tbsContents); // assemble the certificate. Start with the components as a vector Asn1EncodableVector certContents = new Asn1EncodableVector(); certContents.Add(tbsCertificate); certContents.Add(sigAlgID); certContents.Add(signature); // Convert to a SEQUENCE. certSequence will contain the DER encoded certificate var certSequence = new DerSequence(certContents); // Convert to a first-class BC X509Certificate var certBytes = certSequence.GetEncoded(); var cert = new X509CertificateParser().ReadCertificate(certSequence.GetEncoded()); // and return it return(cert); }
/// <summary> /// Parses the AddedTo data that is returned from TPM2_CertifyX509() /// </summary> /// <param name="data"></param> /// <returns></returns> public static AddedToCertificate FromDerEncoding(byte[] data) { var ret = new AddedToCertificate(); var sequence = (DerSequence)DerSequence.FromByteArray(data); var taggedVersion = (DerTaggedObject)(sequence[0]); Debug.Assert(taggedVersion.TagNo == 0); ret.Version = (DerInteger)taggedVersion.GetObject(); ret.SerialNumber = (DerInteger)sequence[1]; ret.Signature = AlgorithmIdentifier.GetInstance(sequence[2]); ret.SubjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(sequence[3]); return(ret); }
SimulateX509Certify(PartialCertificate partialCert, AsymmetricKeyParameter publicKeyToCertify, AsymmetricKeyParameter signingKey, string signingAlgorithm) { // We can simulate ECDSA/SHA256 and RSA/SHA256 ISignatureFactory signatureFactory; DerObjectIdentifier sigAlgOid; if (signingKey is ECPrivateKeyParameters) { sigAlgOid = X9ObjectIdentifiers.ECDsaWithSha256; } else { sigAlgOid = PkcsObjectIdentifiers.Sha256WithRsaEncryption; } //signatureFactory = new Asn1SignatureFactory(sigAlgOid.ToString(), signingKey); signatureFactory = new Asn1SignatureFactory(sigAlgOid.ToString(), signingKey); // Make the certificate var certGenerator = new X509V3CertificateGenerator(); certGenerator.SetIssuerDN(partialCert.Issuer); certGenerator.SetSubjectDN(partialCert.Subject); certGenerator.SetSerialNumber(BigInteger.ValueOf(1)); certGenerator.SetNotBefore(partialCert.NotBefore); certGenerator.SetNotAfter(partialCert.NotAfter); certGenerator.SetPublicKey(publicKeyToCertify); if (partialCert.SubjectUniqueId != null) { certGenerator.SetSubjectUniqueID(ByteArrayToBoolArray(partialCert.SubjectUniqueId)); } if (partialCert.IssuerUniqueId != null) { certGenerator.SetIssuerUniqueID(ByteArrayToBoolArray(partialCert.IssuerUniqueId)); } // process the extensions. Note that this will not preserve the order var extensions = partialCert.Extensions; if (extensions != null) { foreach (var critExtOid in extensions.GetCriticalExtensionOids()) { certGenerator.AddExtension(critExtOid.ToString(), true, extensions.GetExtension(critExtOid).GetParsedValue()); } foreach (var nonCritExtOid in extensions.GetNonCriticalExtensionOids()) { certGenerator.AddExtension(nonCritExtOid.ToString(), false, extensions.GetExtension(nonCritExtOid).GetParsedValue()); } } // and sign to make the cert var cert = certGenerator.Generate(signatureFactory); // take things apart again for addedToCert var subjectPubKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKeyToCertify); // get the exact bytes for the signature algorithm var tbsSequence = ((DerSequence)DerSequence.FromByteArray(cert.GetTbsCertificate())); var sigAlgBytes = tbsSequence[2]; AddedToCertificate addedTo = new AddedToCertificate() { Version = new DerInteger(BigInteger.ValueOf(cert.Version)), SerialNumber = new DerInteger(cert.SerialNumber), Signature = AlgorithmIdentifier.GetInstance(sigAlgBytes), SubjectPublicKeyInfo = subjectPubKeyInfo }; return(System.ValueTuple.Create(cert, addedTo)); }
void TestCertifyX509Impl(Tpm2 tpm, TestContext testCtx, TpmPublic subjectTemplate, TpmPublic sigKeyTemplate, PolicyTree policy, string testLabel) { var partialCert = X509Helpers.MakePartialCert(subjectTemplate); var partialCertBytes = partialCert.GetDerEncoded(); // If you want to paste in your own hex put it here and s //var partialCertBytes = Globs.ByteArrayFromHex("01020304"); // Certify RSA with RSA TpmPublic certifyingKeyPub, keyToBeCertifiedPub; TpmHandle hSigKey = Substrate.CreatePrimary(tpm, sigKeyTemplate, out certifyingKeyPub); TpmHandle hSubjectKey = Substrate.CreatePrimary(tpm, subjectTemplate, out keyToBeCertifiedPub); AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); sess.RunPolicy(tpm, policy); ISignatureUnion sig; byte[] tbsHash; byte[] addedTo = tpm[sess].CertifyX509(hSubjectKey, hSigKey, null, new NullSigScheme(), partialCertBytes, out tbsHash, out sig); tpm.FlushContext(sess); tpm.FlushContext(hSubjectKey); var addedToCert = AddedToCertificate.FromDerEncoding(addedTo); X509Certificate returnedCert = X509Helpers.AssembleCertificate(partialCert, addedToCert, sig is SignatureRsa ? ((SignatureRsa)sig).GetTpmRepresentation() : ((SignatureEcc)sig).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)); // Is the cert properly signed? if (TpmHelper.GetScheme(sigKeyTemplate).GetUnionSelector() != TpmAlgId.Rsapss) { // Software crypto layer does not support PSS bool sigOk = certifyingKeyPub.VerifySignatureOverHash(tbsHash, sig); if (sigKeyTemplate.type == TpmAlgId.Ecc) { #if !__NETCOREAPP2__ // No ECC in .Net Core testCtx.Assert("Sign" + testLabel, sigOk); #endif } else { testCtx.Assert("Sign" + testLabel, sigOk); } } tpm.VerifySignature(hSigKey, tbsHash, sig); tpm.FlushContext(hSigKey); }