/// <inheritdoc/> public async Task <Certificate> ImportCertificateAsync(string certificateName, Certificate certificate, Key privateKey, CancellationToken ct) { if (string.IsNullOrEmpty(certificateName)) { throw new ArgumentNullException(nameof(certificateName)); } if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } if (privateKey == null) { certificate = certificate.Clone(); certificate.IssuerPolicies = null; await _certificates.AddCertificateAsync(certificateName, certificate, null, ct); return(certificate); } try { var password = Guid.NewGuid().ToString(); var pfxBase64 = certificate.ToPfx(privateKey, password).ToBase64String(); // Import bundle var bundle = await _keyVaultClient.ImportCertificateAsync(_vaultBaseUrl, certificateName, pfxBase64, password, CreateCertificatePolicy(certificate, true, _keyStoreIsHsm), CreateCertificateAttributes(certificate.NotBeforeUtc, certificate.NotAfterUtc - certificate.NotBeforeUtc, certificate.NotAfterUtc), null, ct); try { var result = CertificateEx.Create(bundle.Cer, new KeyVaultKeyHandle(bundle), certificate.IssuerPolicies); await _certificates.AddCertificateAsync( certificateName, result, bundle.CertificateIdentifier.Identifier, ct); return(result); } catch { await Try.Async(() => _keyVaultClient.DeleteCertificateAsync( _vaultBaseUrl, certificateName, ct)); throw; } } catch (KeyVaultErrorException ex) { throw new ExternalDependencyException("Failed to import certificate", ex); } }
/// <summary> /// Convert to certificate model /// </summary> /// <param name="document"></param> /// <returns></returns> private Certificate DocumentToCertificate(CertificateDocument document) { if (document == null) { return(null); } var keyHandle = _keys.DeserializeHandle(document.KeyHandle); return(CertificateEx.Create(document.RawData, keyHandle, document.IsserPolicies, document.DisabledSince == null ? null : new RevocationInfo { Date = document.DisabledSince, // ... })); }
/// <summary> /// Convert to framework model /// </summary> /// <returns></returns> public static Certificate ToStackModel(this X509CertificateModel model) { return(CertificateEx.Create(model.ToRawData())); }
/// <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, new KeyVaultKeyHandle(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); } }
/// <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, new KeyVaultKeyHandle(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, new KeyVaultKeyHandle(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)); } } }