/// <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; }
/// <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); }
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)); }