예제 #1
0
 /// <summary>
 /// Parse buffer into cert
 /// </summary>
 /// <param name="buffer"></param>
 /// <param name="key"></param>
 /// <param name="policies"></param>
 /// <param name="revoked"></param>
 /// <returns></returns>
 public static Certificate Create(byte[] buffer,
                                  KeyHandle key          = null, IssuerPolicies policies = null,
                                  RevocationInfo revoked = null)
 {
     using (var cert = new X509Certificate2(buffer)) {
         return(ToCertificate(cert, policies, key, revoked));
     }
 }
 /// <summary>
 /// Clone issuer policies
 /// </summary>
 /// <param name="policies"></param>
 /// <returns></returns>
 public static IssuerPolicies Clone(this IssuerPolicies policies)
 {
     if (policies == null)
     {
         return(null);
     }
     return(new IssuerPolicies {
         IssuedLifetime = policies.IssuedLifetime,
         SignatureType = policies.SignatureType
     });
 }
        /// <summary>
        /// Compare
        /// </summary>
        /// <param name="policies"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static bool SameAs(this IssuerPolicies policies, IssuerPolicies other)
        {
            if (policies == null)
            {
                return(other == null);
            }
            if (other == null)
            {
                return(false);
            }

            if (policies.IssuedLifetime != other.IssuedLifetime)
            {
                return(false);
            }
            if (policies.SignatureType != other.SignatureType)
            {
                return(false);
            }
            return(true);
        }
예제 #4
0
 /// <summary>
 /// Validate issuer policies
 /// </summary>
 /// <param name="policies"></param>
 /// <param name="parent"></param>
 /// <param name="keyParams"></param>
 /// <returns></returns>
 public static IssuerPolicies Validate(this IssuerPolicies policies,
                                       IssuerPolicies parent = null, CreateKeyParams keyParams = null)
 {
     if (policies == null)
     {
         policies = new IssuerPolicies();
     }
     if (policies.IssuedLifetime == null)
     {
         policies.IssuedLifetime = parent?.IssuedLifetime != null ?
                                   parent.IssuedLifetime.Value / 2 : TimeSpan.FromDays(1);
     }
     if (policies.SignatureType == null)
     {
         policies.SignatureType = keyParams.Type == KeyType.RSA ?
                                  SignatureType.RS256 : SignatureType.ES256;
     }
     if (parent != null)
     {
         if (policies.IssuedLifetime > parent.IssuedLifetime)
         {
             throw new ArgumentException(
                       "Issued lifetime cannot be greater than parent issuer policy");
         }
     }
     if (keyParams != null)
     {
         if (policies.SignatureType.Value.IsRSA() && keyParams.Type != KeyType.RSA)
         {
             throw new ArgumentException(
                       "Cannot create rsa signature with mismatch key");
         }
         if (policies.SignatureType.Value.IsECC() && keyParams.Type != KeyType.ECC)
         {
             throw new ArgumentException(
                       "Cannot create ecc signature with mismatch key");
         }
     }
     return(policies);
 }
예제 #5
0
        /// <summary>
        /// Parse buffer into cert
        /// </summary>
        /// <param name="cert"></param>
        /// <param name="policies"></param>
        /// <param name="key"></param>
        /// <param name="revoked"></param>
        /// <returns></returns>
        public static Certificate ToCertificate(this X509Certificate2 cert,
                                                IssuerPolicies policies = null, KeyHandle key = null,
                                                RevocationInfo revoked  = null)
        {
            if (cert == null)
            {
                return(null);
            }

            // We store big-endian but GetSerialNumber returns little-endian
            var serialNumber = cert.GetSerialNumber(); // .net creates clone

            Array.Reverse(serialNumber);

            var certificate = new Certificate {
                RawData        = cert.RawData,
                KeyHandle      = key,
                IssuerPolicies = cert.IsCa() ? policies : null,
                Revoked        = revoked,
                NotAfterUtc    = cert.NotAfter.ToUniversalTime(),
                NotBeforeUtc   = cert.NotBefore.ToUniversalTime(),
                Subject        = cert.SubjectName,
                Thumbprint     = cert.Thumbprint,
                Issuer         = cert.IssuerName,
                SerialNumber   = serialNumber,
                Extensions     = new List <X509Extension>(cert.Extensions.OfType <X509Extension>())
            };

            // Set issuer serial number
            certificate.IssuerSerialNumber =
                certificate.GetAuthorityKeyIdentifierExtension()?.SerialNumber.Value;
            if (certificate.IssuerSerialNumber == null && certificate.IsSelfSigned())
            {
                certificate.IssuerSerialNumber = certificate.SerialNumber.ToArray();
            }
            return(certificate);
        }
예제 #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);

            // Create new signing key
            var keyHandle = await _keys.CreateKeyAsync(Guid.NewGuid().ToString(), keyParams,
                                                       new KeyStoreProperties {
                Exportable = false
            }, ct);

            try {
                // Get public key
                var publicKey = await _keys.GetPublicKeyAsync(keyHandle, ct);

                // Create certificate
                var certificate = await _factory.CreateCertificateAsync(_keys, keyHandle,
                                                                        subjectName, publicKey,
                                                                        GetNotAfter(notBefore, lifetime, DateTime.MaxValue, out var notAfter),
                                                                        notAfter, policies.SignatureType.Value, true, extensions, ct);

                using (certificate) {
                    // Import certificate
                    var result = certificate.ToCertificate(policies, keyHandle);
                    await _repo.AddCertificateAsync(certificateName, result, null, ct);

                    return(result);
                }
            }
            catch (Exception ex) {
                _logger.Verbose(ex, "Failed to add certificate, delete key");
                await Try.Async(() => _keys.DeleteKeyAsync(keyHandle, ct));

                throw;
            }
        }
        /// <inheritdoc/>
        public async Task <Certificate> NewIssuerCertificateAsync(string rootCertificate,
                                                                  string certificateName, X500DistinguishedName subjectName,
                                                                  DateTime?notBefore, CreateKeyParams keyParams, IssuerPolicies policies,
                                                                  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.");
                }

                // Validate policies
                policies = policies.Validate(caCert.IssuerPolicies, keyParams);

                // (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.

                    var signedcert = await _factory.CreateCertificateAsync(this,
                                                                           caCert, subjectName, info.PublicKey,
                                                                           attributes.NotBefore.Value, attributes.Expires.Value,
                                                                           caCert.IssuerPolicies.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);
                    if (!cert.IsIssuer())
                    {
                        throw new ArgumentException("Certifcate created is not issuer.");
                    }
                    await _certificates.AddCertificateAsync(certificateName, cert,
                                                            mergedCert.CertificateIdentifier.Identifier, ct);

                    return(cert);
                }
                catch {
                    await Try.Async(() => _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));
                }
            }
        }