public async Task CreateRSARootAndRSAIssuerTestAsync() { using (var mock = Setup((v, q) => { var expected = "SELECT TOP 1 * FROM Certificates c " + "WHERE c.Type = 'Certificate' " + "AND c.CertificateName = 'footca' " + "ORDER BY c.Version DESC"; if (q == expected) { return(v .Where(o => o.Value["Type"] == "Certificate") .Where(o => o.Value["CertificateName"] == "footca") .OrderByDescending(o => o.Value["Version"])); } expected = "SELECT TOP 1 * FROM Certificates c " + "WHERE c.Type = 'Certificate' " + "AND c.CertificateName = 'rootca' " + "ORDER BY c.Version DESC"; if (q == expected) { return(v .Where(o => o.Value["Type"] == "Certificate") .Where(o => o.Value["CertificateName"] == "rootca") .OrderByDescending(o => o.Value["Version"])); } expected = "SELECT TOP 1 * FROM Certificates c " + "WHERE c.Type = 'Certificate' " + "AND c.CertificateId = '" + kTestVaultUri + "/certificates/rootca' " + "ORDER BY c.Version DESC"; if (q == expected) { return(v .Where(o => o.Value["Type"] == "Certificate") .Where(o => o.Value["CertificateName"] == "rootca") .OrderByDescending(o => o.Value["Version"])); } throw new AssertActualExpectedException(expected, q, "Query"); }, out var service, out var client)) { ICertificateStore store = mock.Create <CertificateDatabase>(); ICertificateRepository repo = mock.Create <CertificateDatabase>(); var now = DateTime.UtcNow; using (var rkey = SignatureType.RS256.CreateCsr("CN=thee", true, out var rootcsr)) using (var rootca = rootcsr.CreateSelfSigned(now, now + TimeSpan.FromDays(5))) using (var ikey = SignatureType.RS256.CreateCsr("CN=me", true, out var issuercsr)) using (var issuer = issuercsr.Create(rootca, now, now + TimeSpan.FromHours(3), Guid.NewGuid().ToByteArray())) { await repo.AddCertificateAsync("rootca", rootca.ToCertificate(new IssuerPolicies { SignatureType = SignatureType.RS256, IssuedLifetime = TimeSpan.FromHours(3) }, KeyVaultKeyHandle.Create(kTestVaultUri + "/keys/rkid", null)), kTestVaultUri + "/certificates/rootca"); client.Setup(o => o.GetCertificateWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), It.Is <string>(a => a == "rootca"), It.IsAny <string>(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new CertificateBundle( kTestVaultUri + "/certificates/rootca", kTestVaultUri + "/keys/rkid", null, // not exportable null, null, rootca.ToPfx(rkey.ToKey()), null, null, null); return(Task.FromResult(new AzureOperationResponse <CertificateBundle> { Body = result })); }); client.Setup(o => o.CreateCertificateWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), It.Is <string>(a => a == "footca"), It.IsNotNull <CertificatePolicy>(), It.IsNotNull <CertificateAttributes>(), It.IsAny <IDictionary <string, string> >(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new CertificateOperation { Status = "InProgress" }; return(Task.FromResult(new AzureOperationResponse <CertificateOperation> { Body = result })); }); client.Setup(o => o.GetCertificateOperationWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), It.IsAny <string>(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new CertificateOperation { Csr = issuercsr.CreateSigningRequest(), Status = "Completed" }; return(Task.FromResult(new AzureOperationResponse <CertificateOperation> { Body = result })); }); client.Setup(o => o.GetCertificateWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), It.Is <string>(a => a == "footca"), It.IsAny <string>(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new CertificateBundle( kTestVaultUri + "/certificates/footca", kTestVaultUri + "/keys/fkid", null, // not exportable null, null, issuer.ToPfx(ikey.ToKey()), null, null, null); return(Task.FromResult(new AzureOperationResponse <CertificateBundle> { Body = result })); }); client.Setup(o => o.MergeCertificateWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), It.Is <string>(a => a == "footca"), It.IsAny <IList <byte[]> >(), It.IsAny <CertificateAttributes>(), It.IsAny <IDictionary <string, string> >(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new CertificateBundle( kTestVaultUri + "/certificates/footca", kTestVaultUri + "/keys/fkid", null, // not exportable null, null, issuer.ToPfx(ikey.ToKey()), null, null, null); return(Task.FromResult(new AzureOperationResponse <CertificateBundle> { Body = result })); }); client.Setup(o => o.SignWithHttpMessagesAsync( It.Is <string>(a => a == kTestVaultUri), // It.Is<string>(a => a == kTestVaultUri + "/keys/rkid"), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), // It.Is<string>(a => a == "RS256"), It.IsAny <byte[]>(), It.IsAny <Dictionary <string, List <string> > >(), It.IsAny <CancellationToken>())).Returns(() => { var result = new KeyOperationResult( kTestVaultUri + "/keys/rkid", new byte[32]); return(Task.FromResult(new AzureOperationResponse <KeyOperationResult> { Body = result })); }); // Run var footca = await service.NewIssuerCertificateAsync("rootca", "footca", X500DistinguishedNameEx.Create("CN=me"), DateTime.UtcNow, new CreateKeyParams { KeySize = 2048, Type = KeyType.RSA }, new IssuerPolicies { IssuedLifetime = TimeSpan.FromHours(1) }); var found = await store.FindLatestCertificateAsync("footca"); // Assert Assert.NotNull(footca); Assert.NotNull(found); Assert.NotNull(footca.IssuerPolicies); Assert.NotNull(footca.KeyHandle); Assert.Null(footca.Revoked); Assert.Equal(TimeSpan.FromHours(3), footca.NotAfterUtc - footca.NotBeforeUtc); Assert.Equal(TimeSpan.FromHours(1), footca.IssuerPolicies.IssuedLifetime); Assert.Equal(SignatureType.RS256, footca.IssuerPolicies.SignatureType); Assert.False(footca.IsSelfSigned()); Assert.True(footca.IsIssuer()); Assert.True(footca.SameAs(found)); Assert.Equal(rootca.Subject, footca.GetIssuerSubjectName()); Assert.True(rootca.SubjectName.SameAs(footca.Issuer)); using (var cert = footca.ToX509Certificate2()) { Assert.Equal(cert.GetSerialNumber(), footca.GetSerialNumberAsBytesLE()); Assert.Equal(cert.SerialNumber, footca.GetSerialNumberAsString()); Assert.Equal(cert.Thumbprint, footca.Thumbprint); } Assert.True(footca.IsValidChain(rootca.ToCertificate().YieldReturn())); } } }