Ejemplo n.º 1
0
        /// <inheritdoc/>
        public async Task <KeyHandle> ImportKeyAsync(string name, Key key,
                                                     KeyStoreProperties store, CancellationToken ct)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            try {
                // Import key
                var keyBundle = await _keyVaultClient.ImportKeyAsync(_vaultBaseUrl, name,
                                                                     key.ToJsonWebKey(), null, new KeyAttributes {
                    Enabled   = true,
                    NotBefore = DateTime.UtcNow
                }, null, ct);

                if (store?.Exportable ?? false)
                {
                    // Store key as json web key secret so we can export it
                    var secretBundle = await _keyVaultClient.SetSecretAsync(_vaultBaseUrl,
                                                                            name, _serializer.SerializeToString(key.ToJsonWebKey()),
                                                                            null, ContentMimeType.Json,
                                                                            new SecretAttributes {
                        Enabled   = true,
                        NotBefore = DateTime.UtcNow
                    }, ct);

                    return(KeyVaultKeyHandle.Create(keyBundle, secretBundle));
                }
                return(KeyVaultKeyHandle.Create(keyBundle));
            }
            catch (KeyVaultErrorException kex) {
                throw new ExternalDependencyException("Failed to import key", kex);
            }
        }
        /// <inheritdoc/>
        public async Task <Key> ExportKeyAsync(KeyHandle handle, CancellationToken ct)
        {
            var bundle = KeyVaultKeyHandle.GetBundle(handle);

            if (string.IsNullOrEmpty(bundle.SecretIdentifier))
            {
                throw new InvalidOperationException("Non-exportable key.");
            }
            try {
                var secretBundle = await _keyVaultClient.GetSecretAsync(
                    bundle.SecretIdentifier, ct);

                // Check whether this is an imported key
                if (secretBundle.ContentType.EqualsIgnoreCase(ContentEncodings.MimeTypeJson))
                {
                    // Decode json web key and convert to key
                    var key = JsonConvert.DeserializeObject <JsonWebKey>(secretBundle.Value);
                    return(key.ToKey());
                }

                // Check whether this is a certificate backing secret
                if (secretBundle.ContentType.EqualsIgnoreCase(CertificateContentType.Pfx))
                {
                    // Decode pfx from secret and get key
                    var pfx = Convert.FromBase64String(secretBundle.Value);
                    using (var cert = new X509Certificate2(pfx, (string)null,
                                                           X509KeyStorageFlags.Exportable)) {
                        return(cert.PrivateKey.ToKey());
                    }
                }
                throw new ResourceNotFoundException(
                          $"Key handle points to invalid content {secretBundle.ContentType}");
            }
            catch (KeyVaultErrorException kex) {
                throw new ExternalDependencyException("Failed to export key", kex);
            }
        }
Ejemplo n.º 3
0
        /// <inheritdoc/>
        public async Task <KeyHandle> CreateKeyAsync(string name, CreateKeyParams keyParams,
                                                     KeyStoreProperties store, CancellationToken ct)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (keyParams == null)
            {
                throw new ArgumentNullException(nameof(keyParams));
            }
            try {
                if (!(store?.Exportable ?? false))
                {
                    // Create key inside key vault
                    var result = await _keyVaultClient.CreateKeyAsync(_vaultBaseUrl, name,
                                                                      new NewKeyParameters {
                        KeySize    = (int?)keyParams.KeySize,
                        CurveName  = keyParams.Curve?.ToJsonWebKeyCurveName(),
                        Attributes = new KeyAttributes {
                            Enabled   = true,
                            NotBefore = DateTime.UtcNow
                        },
                        Kty = keyParams.Type.ToKty(_keyStoreIsHsm)
                    }, ct);

                    return(KeyVaultKeyHandle.Create(result));
                }
                // Create key outside and import
                return(await ImportKeyAsync(name, keyParams.CreateKey(),
                                            new KeyStoreProperties { Exportable = true }, ct));
            }
            catch (KeyVaultErrorException kex) {
                throw new ExternalDependencyException("Failed to create key", kex);
            }
        }
Ejemplo n.º 4
0
        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()));
                            }
            }
        }
Ejemplo n.º 5
0
        /// <inheritdoc/>
        public async Task <Certificate> CreateCertificateAndPrivateKeyAsync(string rootCertificate,
                                                                            string certificateName, X500DistinguishedName subjectName, DateTime?notBefore,
                                                                            CreateKeyParams keyParams, Func <byte[], IEnumerable <X509Extension> > extensions,
                                                                            CancellationToken ct)
        {
            try {
                // (0) Retrieve issuer certificate
                var caCertBundle = await _keyVaultClient.GetCertificateAsync(
                    _vaultBaseUrl, rootCertificate, ct);

                if (caCertBundle == null)
                {
                    throw new ResourceNotFoundException("Issuer cert not found.");
                }
                var caCert = await _certificates.FindCertificateAsync(
                    caCertBundle.CertificateIdentifier.Identifier);

                if (caCert?.IssuerPolicies == null)
                {
                    throw new ArgumentException("Certificate cannot issue.");
                }

                // (1) Create key in key vault and get CSR.

                // policy unknown issuer, new key, exportable key
                var policyUnknownNewExportable = CreateCertificatePolicy(
                    subjectName.Name, keyParams, false, _keyStoreIsHsm, false, true);

                var attributes = CreateCertificateAttributes(notBefore,
                                                             caCert.IssuerPolicies.IssuedLifetime.Value, caCert.NotAfterUtc);
                var createResult = await CreateCertificateAsync(certificateName,
                                                                policyUnknownNewExportable, attributes, null, ct);

                if (createResult.Csr == null)
                {
                    throw new CryptographicUnexpectedOperationException(
                              "Failed to read CSR from CreateCertificate.");
                }
                // decode the CSR and verify consistency
                var info = createResult.Csr.ToCertificationRequest();

                try {
                    // (2) - Issue X509 Certificate with csr and root certificate.

                    // create signed cert
                    var signedcert = await _factory.CreateCertificateAsync(this,
                                                                           caCert, subjectName, info.PublicKey,
                                                                           attributes.NotBefore.Value, attributes.Expires.Value,
                                                                           caCert.IssuerPolicies.SignatureType.Value, false, extensions, ct);

                    // (3) - Complete certificate creation with merger of X509 Certificate.

                    var mergeResult = await _keyVaultClient.MergeCertificateAsync(
                        _vaultBaseUrl, certificateName,
                        new X509Certificate2Collection(signedcert), null, null, ct);

                    // (4) - Get merged certificate and key identifier

                    var mergedCert = await _keyVaultClient.GetCertificateAsync(
                        mergeResult.CertificateIdentifier.Identifier, ct);

                    var cert = CertificateEx.Create(mergedCert.Cer,
                                                    KeyVaultKeyHandle.Create(mergedCert));
                    System.Diagnostics.Debug.Assert(!cert.IsIssuer());
                    await _certificates.AddCertificateAsync(certificateName,
                                                            cert, mergedCert.CertificateIdentifier.Identifier, ct);

                    return(cert);
                }
                catch {
                    await _keyVaultClient.DeleteCertificateAsync(
                        _vaultBaseUrl, certificateName, ct);

                    await Try.Async(() => _keyVaultClient.PurgeDeletedCertificateAsync(
                                        _vaultBaseUrl, certificateName, ct));

                    throw;
                }
            }
            catch (KeyVaultErrorException ex) {
                throw new ExternalDependencyException(
                          "Failed to create new key pair certificate", ex);
            }
        }
Ejemplo n.º 6
0
        /// <inheritdoc/>
        public async Task <Certificate> NewRootCertificateAsync(string certificateName,
                                                                X500DistinguishedName subjectName, DateTime?notBefore, TimeSpan lifetime,
                                                                CreateKeyParams keyParams, IssuerPolicies policies,
                                                                Func <byte[], IEnumerable <X509Extension> > extensions,
                                                                CancellationToken ct)
        {
            if (string.IsNullOrEmpty(certificateName))
            {
                throw new ArgumentNullException(nameof(certificateName));
            }

            // Validate policies
            policies = policies.Validate(null, keyParams);
            string caTempCertIdentifier = null;

            try {
                // (1) Create key in key vault and get CSR.

                // policy self signed, new key, not exportable key
                var policySelfSignedNewKey = CreateCertificatePolicy(
                    subjectName.Name, keyParams, true, _keyStoreIsHsm, false, false);
                var tempAttributes = CreateCertificateAttributes(
                    DateTime.UtcNow.AddMinutes(-10), TimeSpan.FromMinutes(10),
                    DateTime.MaxValue);

                await CreateCertificateAsync(certificateName, policySelfSignedNewKey,
                                             tempAttributes, null, ct);

                // We have the cert - get it and key identifier to do the signing
                var createdCertificateBundle = await _keyVaultClient.GetCertificateAsync(
                    _vaultBaseUrl, certificateName, ct);

                caTempCertIdentifier =
                    createdCertificateBundle.CertificateIdentifier.Identifier;

                // policy unknown issuer, reuse key - not exportable
                var policyUnknownReuse = CreateCertificatePolicy(
                    subjectName.Name, keyParams, false, _keyStoreIsHsm, true, false);
                var attributes = CreateCertificateAttributes(notBefore, lifetime,
                                                             DateTime.MaxValue);

                // create the CSR
                var createResult = await CreateCertificateAsync(certificateName,
                                                                policyUnknownReuse, attributes, null, ct);

                if (createResult.Csr == null)
                {
                    throw new CryptographicUnexpectedOperationException(
                              "Failed to read CSR from CreateCertificate.");
                }

                // decode the CSR and verify consistency
                var info = createResult.Csr.ToCertificationRequest();

                // (2) - Issue root X509 Certificate with the csr.

                var signedcert = await _factory.CreateCertificateAsync(this,
                                                                       KeyVaultKeyHandle.Create(createdCertificateBundle), subjectName,
                                                                       info.PublicKey,
                                                                       attributes.NotBefore.Value, attributes.Expires.Value,
                                                                       policies.SignatureType.Value, true, extensions, ct);

                // (3) - Complete certificate creation with merger of X509 Certificate.

                var mergeResult = await _keyVaultClient.MergeCertificateAsync(
                    _vaultBaseUrl, certificateName,
                    new X509Certificate2Collection(signedcert), null, null, ct);

                // (4) - Get merged certificate and key identifier

                var mergedCert = await _keyVaultClient.GetCertificateAsync(
                    mergeResult.CertificateIdentifier.Identifier, ct);

                var cert = CertificateEx.Create(mergedCert.Cer,
                                                KeyVaultKeyHandle.Create(mergedCert), policies);
                await _certificates.AddCertificateAsync(certificateName, cert,
                                                        mergedCert.CertificateIdentifier.Identifier, ct);

                return(cert);
            }
            catch (KeyVaultErrorException kex) {
                throw new ExternalDependencyException(
                          "Failed to create new Root CA certificate", kex);
            }
            finally {
                if (caTempCertIdentifier != null)
                {
                    // disable the temp cert for self signing operation
                    var attr = new CertificateAttributes {
                        Enabled = false
                    };
                    await Try.Async(() => _keyVaultClient.UpdateCertificateAsync(
                                        caTempCertIdentifier, null, attr));
                }
            }
        }