/// <summary> /// Validates a certificate. /// </summary> /// <remarks> /// Each UA application may have a list of trusted certificates that is different from /// all other UA applications that may be running on the same machine. As a result, the /// certificate validator cannot rely completely on the Windows certificate store and /// user or machine specific CTLs (certificate trust lists). /// /// The validator constructs the trust chain for the certificate and follows the chain /// until it finds a certification that is in the application trust list. Non-fatal trust /// chain errors (i.e. certificate expired) are ignored if the certificate is in the /// application trust list. /// /// If no certificate in the chain is trusted then the validator will still accept the /// certification if there are no trust chain errors. /// /// The validator may be configured to ignore the application trust list and/or trust chain. /// </remarks> public virtual void Validate(X509Certificate2Collection chain) { X509Certificate2 certificate = chain[0]; try { lock (m_lock) { InternalValidate(chain).GetAwaiter().GetResult(); // add to list of validated certificates. m_validatedCertificates[certificate.Thumbprint] = new X509Certificate2(certificate.RawData); } } catch (ServiceResultException se) { // check for errors that may be suppressed. switch (se.StatusCode) { case StatusCodes.BadCertificateHostNameInvalid: case StatusCodes.BadCertificateIssuerRevocationUnknown: case StatusCodes.BadCertificateChainIncomplete: case StatusCodes.BadCertificateIssuerTimeInvalid: case StatusCodes.BadCertificateIssuerUseNotAllowed: case StatusCodes.BadCertificateRevocationUnknown: case StatusCodes.BadCertificateTimeInvalid: case StatusCodes.BadCertificatePolicyCheckFailed: case StatusCodes.BadCertificateUseNotAllowed: case StatusCodes.BadCertificateUntrusted: { Utils.Trace("Certificate Vaildation failed for '{0}'. Reason={1}", certificate.Subject, (StatusCode)se.StatusCode); break; } default: { // write the invalid certificate to rejected store if specified. Utils.Trace((int)Utils.TraceMasks.Error, "Certificate '{0}' rejected. Reason={1}", certificate.Subject, (StatusCode)se.StatusCode); SaveCertificate(certificate); throw new ServiceResultException(se, StatusCodes.BadCertificateInvalid); } } // invoke callback. bool accept = false; lock (m_callbackLock) { if (m_CertificateValidation != null) { CertificateValidationEventArgs args = new CertificateValidationEventArgs(new ServiceResult(se), certificate); m_CertificateValidation(this, args); accept = args.Accept; } } // throw if rejected. if (!accept) { // write the invalid certificate to rejected store if specified. Utils.Trace((int)Utils.TraceMasks.Error, "Certificate '{0}' rejected. Reason={1}", certificate.Subject, (StatusCode)se.StatusCode); SaveCertificate(certificate); throw new ServiceResultException(se, StatusCodes.BadCertificateInvalid); } // add to list of peers. lock (m_lock) { Utils.Trace("Validation error suppressed for '{0}'.", certificate.Subject); m_validatedCertificates[certificate.Thumbprint] = new X509Certificate2(certificate.RawData); } } }
/// <summary> /// Checks if issuer has revoked the certificate. /// </summary> public StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate) { if (issuer == null) { throw new ArgumentNullException("issuer"); } if (certificate == null) { throw new ArgumentNullException("certificate"); } // check for CRL. DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + "\\crl"); if (info.Exists) { bool crlExpired = true; foreach (FileInfo file in info.GetFiles("*.crl")) { X509CRL crl = null; try { crl = new X509CRL(file.FullName); } catch (Exception e) { Utils.Trace(e, "Could not parse CRL file."); continue; } if (!Utils.CompareDistinguishedName(crl.Issuer, issuer.Subject)) { continue; } if (!crl.VerifySignature(issuer, false)) { continue; } if (crl.IsRevoked(certificate)) { return(StatusCodes.BadCertificateRevoked); } if (crl.UpdateTime <= DateTime.UtcNow && (crl.NextUpdateTime == DateTime.MinValue || crl.NextUpdateTime >= DateTime.UtcNow)) { crlExpired = false; } } // certificate is fine. if (!crlExpired) { return(StatusCodes.Good); } } // can't find a valid CRL. return(StatusCodes.BadCertificateRevocationUnknown); }
/// <summary> /// Reads the current contents of the directory from disk. /// </summary> private IDictionary <string, Entry> Load(string thumbprint) { lock (m_lock) { DateTime now = DateTime.UtcNow; // refresh the directories. m_certificateSubdir.Refresh(); if (!NoPrivateKeys) { m_privateKeySubdir.Refresh(); } // check if store exists. if (!m_certificateSubdir.Exists) { m_certificates.Clear(); return(m_certificates); } // check if cache is still good. if (m_certificateSubdir.LastWriteTimeUtc < m_lastDirectoryCheck && (NoPrivateKeys || this.m_privateKeySubdir.LastWriteTimeUtc < m_lastDirectoryCheck)) { return(m_certificates); } m_certificates.Clear(); m_lastDirectoryCheck = now; bool incompleteSearch = false; // check for public keys. foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der")) { try { Entry entry = new Entry(); entry.Certificate = new X509Certificate2(file.FullName); entry.CertificateFile = file; entry.PrivateKeyFile = null; entry.CertificateWithPrivateKey = null; if (!NoPrivateKeys) { string fileRoot = file.Name.Substring(0, entry.CertificateFile.Name.Length - entry.CertificateFile.Extension.Length); StringBuilder filePath = new StringBuilder(); filePath.Append(m_privateKeySubdir.FullName); filePath.Append("\\"); filePath.Append(fileRoot); entry.PrivateKeyFile = new FileInfo(filePath.ToString() + ".pfx"); // check for PFX file. if (entry.PrivateKeyFile.Exists) { try { X509Certificate2 certificate = new X509Certificate2( entry.PrivateKeyFile.FullName, new System.Security.SecureString(), X509KeyStorageFlags.Exportable); if (certificate.HasPrivateKey) { entry.CertificateWithPrivateKey = certificate; } } catch (System.Security.Cryptography.CryptographicException) { // Utils.Trace("{1}: {0}", entry.PrivateKeyFile.Name, e.Message.Trim()); } catch (Exception e) { Utils.Trace(e, "Could not load private key certificate from file: {0}", entry.PrivateKeyFile.Name); } } // check for PEM file. else { entry.PrivateKeyFile = new FileInfo(filePath.ToString() + ".pem"); if (!entry.PrivateKeyFile.Exists) { entry.PrivateKeyFile = null; } } } m_certificates[entry.Certificate.Thumbprint] = entry; if (!String.IsNullOrEmpty(thumbprint) && thumbprint == entry.Certificate.Thumbprint) { incompleteSearch = true; break; } } catch (Exception e) { Utils.Trace(e, "Could not load certificate from file: {0}", file.FullName); } } if (incompleteSearch) { m_lastDirectoryCheck = DateTime.MinValue; } return(m_certificates); } }
/// <summary> /// Validates a certificate. /// </summary> /// <remarks> /// Each UA application may have a list of trusted certificates that is different from /// all other UA applications that may be running on the same machine. As a result, the /// certificate validator cannot rely completely on the Windows certificate store and /// user or machine specific CTLs (certificate trust lists). /// /// The validator constructs the trust chain for the certificate and follows the chain /// until it finds a certification that is in the application trust list. Non-fatal trust /// chain errors (i.e. certificate expired) are ignored if the certificate is in the /// application trust list. /// /// If no certificate in the chain is trusted then the validator will still accept the /// certification if there are no trust chain errors. /// /// The validator may be configured to ignore the application trust list and/or trust chain. /// </remarks> public virtual void Validate(X509Certificate2Collection chain) { X509Certificate2 certificate = chain[0]; try { lock (m_lock) { InternalValidate(chain).Wait(); // add to list of validated certificates. m_validatedCertificates[certificate.Thumbprint] = certificate; } } catch (AggregateException ae) { foreach (ServiceResultException e in ae.InnerExceptions) { // check for errors that may be suppressed. switch (e.StatusCode) { case StatusCodes.BadCertificateHostNameInvalid: case StatusCodes.BadCertificateIssuerRevocationUnknown: case StatusCodes.BadCertificateIssuerTimeInvalid: case StatusCodes.BadCertificateIssuerUseNotAllowed: case StatusCodes.BadCertificateRevocationUnknown: case StatusCodes.BadCertificateTimeInvalid: case StatusCodes.BadCertificateUriInvalid: case StatusCodes.BadCertificateUseNotAllowed: case StatusCodes.BadCertificateUntrusted: { Utils.Trace("Cert Validate failed: {0}", (StatusCode)e.StatusCode); break; } default: { throw new ServiceResultException(e, StatusCodes.BadCertificateInvalid); } } // invoke callback. bool accept = false; lock (m_callbackLock) { if (m_CertificateValidation != null) { CertificateValidationEventArgs args = new CertificateValidationEventArgs(new ServiceResult(e), certificate); m_CertificateValidation(this, args); accept = args.Accept; } } // throw if rejected. if (!accept) { // write the invalid certificate to a directory if specified. lock (m_lock) { Utils.Trace((int)Utils.TraceMasks.Error, "Certificate '{0}' rejected. Reason={1}", certificate.Subject, (StatusCode)e.StatusCode); if (m_rejectedCertificateStore != null) { Utils.Trace((int)Utils.TraceMasks.Error, "Writing rejected certificate to directory: {0}", m_rejectedCertificateStore); SaveCertificate(certificate); } } throw new ServiceResultException(e, StatusCodes.BadCertificateInvalid); } // add to list of peers. lock (m_lock) { m_validatedCertificates[certificate.Thumbprint] = certificate; } break; } } }
/// <summary> /// Loads the private key from a PFX file in the certificate store. /// </summary> public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, System.Security.SecureString password) { if (m_certificateSubdir == null || !m_certificateSubdir.Exists) { return(null); } if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName)) { return(null); } foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der")) { try { X509Certificate2 certificate = new X509Certificate2(file.FullName); if (!String.IsNullOrEmpty(thumbprint)) { if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase)) { continue; } } if (!String.IsNullOrEmpty(subjectName)) { if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject)) { if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName)) { continue; } } } string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length); StringBuilder filePath = new StringBuilder(); filePath.Append(m_privateKeySubdir.FullName); filePath.Append("\\"); filePath.Append(fileRoot); FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx"); certificate = new X509Certificate2( privateKeyFile.FullName, (password == null)?new System.Security.SecureString():password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); System.Security.Cryptography.RSACryptoServiceProvider rsa = certificate.PrivateKey as System.Security.Cryptography.RSACryptoServiceProvider; if (rsa != null && rsa.CspKeyContainerInfo.Exportable) { int inputBlockSize = rsa.KeySize / 8 - 42; byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], true); byte[] bytes2 = rsa.Decrypt(bytes1, true); if (bytes2 != null) { // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint); return(certificate); } } return(certificate); } catch (Exception e) { Utils.Trace(e, "Could not load private key certificate from file: {0}", file.Name); } } return(null); }
/// <summary> /// Loads the private key from a PFX file in the certificate store. /// </summary> public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, string password) { if (m_certificateSubdir == null || !m_certificateSubdir.Exists) { return(null); } if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName)) { return(null); } foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der")) { try { X509Certificate2 certificate = new X509Certificate2(file.FullName); if (!String.IsNullOrEmpty(thumbprint)) { if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase)) { continue; } } if (!String.IsNullOrEmpty(subjectName)) { if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject)) { if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName)) { continue; } } } string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length); StringBuilder filePath = new StringBuilder(); filePath.Append(m_privateKeySubdir.FullName); filePath.Append(Path.DirectorySeparatorChar); filePath.Append(fileRoot); FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx"); RSA rsa = null; try { certificate = new X509Certificate2( privateKeyFile.FullName, (password == null) ? String.Empty : password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet); rsa = certificate.GetRSAPrivateKey(); } catch (Exception) { certificate = new X509Certificate2( privateKeyFile.FullName, (password == null) ? String.Empty : password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); rsa = certificate.GetRSAPrivateKey(); } if (rsa != null) { int inputBlockSize = rsa.KeySize / 8 - 42; byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1); byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1); if (bytes2 != null) { // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint); return(certificate); } } } catch (Exception e) { Utils.Trace(e, "Could not load private key for certificate " + subjectName); } } return(null); }
/// <summary> /// Loads the private key from a PFX file in the certificate store. /// </summary> public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, string password) { if (m_certificateSubdir == null || !m_certificateSubdir.Exists) { return(null); } if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName)) { return(null); } foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der")) { try { X509Certificate2 certificate = new X509Certificate2(file.FullName); if (!String.IsNullOrEmpty(thumbprint)) { if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase)) { continue; } } if (!String.IsNullOrEmpty(subjectName)) { if (!X509Utils.CompareDistinguishedName(subjectName, certificate.Subject)) { if (subjectName.Contains("=")) { continue; } if (!X509Utils.ParseDistinguishedName(certificate.Subject).Any(s => s.Equals("CN=" + subjectName, StringComparison.OrdinalIgnoreCase))) { continue; } } } string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length); StringBuilder filePath = new StringBuilder(); filePath.Append(m_privateKeySubdir.FullName); filePath.Append(Path.DirectorySeparatorChar); filePath.Append(fileRoot); X509KeyStorageFlags[] storageFlags = { X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet }; FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx"); password = password ?? String.Empty; foreach (var flag in storageFlags) { try { certificate = new X509Certificate2( privateKeyFile.FullName, password, flag); if (X509Utils.VerifyRSAKeyPair(certificate, certificate, true)) { return(certificate); } } catch (Exception) { certificate?.Dispose(); certificate = null; } } } catch (Exception e) { Utils.Trace(e, "Could not load private key for certificate " + subjectName); } } return(null); }
/// <summary> /// Gets the application access rules implied by the access rights to the file. /// </summary> public static void SetAccessRules(String filePath, IList <ApplicationAccessRule> accessRules, bool replaceExisting) { // get the current permissions from the file or directory. FileSystemSecurity security = null; FileInfo fileInfo = new FileInfo(filePath); DirectoryInfo directoryInfo = null; if (!fileInfo.Exists) { directoryInfo = new DirectoryInfo(filePath); if (!directoryInfo.Exists) { throw new FileNotFoundException("File or directory does not exist.", filePath); } security = directoryInfo.GetAccessControl(AccessControlSections.Access); } else { security = fileInfo.GetAccessControl(AccessControlSections.Access); } if (replaceExisting) { // can't use inhieritance when setting permissions security.SetAccessRuleProtection(true, false); // remove all existing access rules. AuthorizationRuleCollection authorizationRules = security.GetAccessRules(true, true, typeof(NTAccount)); for (int ii = 0; ii < authorizationRules.Count; ii++) { FileSystemAccessRule accessRule = authorizationRules[ii] as FileSystemAccessRule; // only care about file system rules. if (accessRule == null) { continue; } security.RemoveAccessRule(accessRule); } } // allow children to inherit rules for directories. InheritanceFlags flags = InheritanceFlags.None; if (directoryInfo != null) { flags = InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit; } // add the new rules. for (int ii = 0; ii < accessRules.Count; ii++) { ApplicationAccessRule applicationRule = accessRules[ii]; IdentityReference identityReference = applicationRule.IdentityReference; if (identityReference == null) { if (applicationRule.IdentityName.StartsWith("S-")) { SecurityIdentifier sid = new SecurityIdentifier(applicationRule.IdentityName); if (!sid.IsValidTargetType(typeof(NTAccount))) { continue; } identityReference = sid.Translate(typeof(NTAccount)); } else { identityReference = new NTAccount(applicationRule.IdentityName); } } FileSystemAccessRule fileRule = null; switch (applicationRule.Right) { case ApplicationAccessRight.Run: { fileRule = new FileSystemAccessRule( identityReference, (applicationRule.RuleType == AccessControlType.Allow) ? Read : Configure, flags, PropagationFlags.None, ApplicationAccessRule.Convert(applicationRule.RuleType)); break; } case ApplicationAccessRight.Update: { fileRule = new FileSystemAccessRule( identityReference, (applicationRule.RuleType == AccessControlType.Allow) ? Update : ConfigureOnly | UpdateOnly, flags, PropagationFlags.None, ApplicationAccessRule.Convert(applicationRule.RuleType)); security.SetAccessRule(fileRule); break; } case ApplicationAccessRight.Configure: { fileRule = new FileSystemAccessRule( identityReference, (applicationRule.RuleType == AccessControlType.Allow) ? Configure : ConfigureOnly, flags, PropagationFlags.None, ApplicationAccessRule.Convert(applicationRule.RuleType)); break; } } try { security.SetAccessRule(fileRule); } catch (Exception e) { Utils.Trace( "Could not set access rule for account '{0}' on file '{1}'. Error={2}", applicationRule.IdentityName, filePath, e.Message); } } if (directoryInfo != null) { directoryInfo.SetAccessControl((DirectorySecurity)security); return; } fileInfo.SetAccessControl((FileSecurity)security); }
/// <summary> /// Creates a self signed application instance certificate. /// </summary> /// <param name="storeType">Type of certificate store (Directory) <see cref="CertificateStoreType"/>.</param> /// <param name="storePath">The store path (syntax depends on storeType).</param> /// <param name="password">The password to use to protect the certificate.</param> /// <param name="applicationUri">The application uri (created if not specified).</param> /// <param name="applicationName">Name of the application (optional if subjectName is specified).</param> /// <param name="subjectName">The subject used to create the certificate (optional if applicationName is specified).</param> /// <param name="domainNames">The domain names that can be used to access the server machine (defaults to local computer name if not specified).</param> /// <param name="keySize">Size of the key (1024, 2048 or 4096).</param> /// <param name="startTime">The start time.</param> /// <param name="lifetimeInMonths">The lifetime of the key in months.</param> /// <param name="hashSizeInBits">The hash size in bits.</param> /// <param name="isCA">if set to <c>true</c> then a CA certificate is created.</param> /// <param name="issuerCAKeyCert">The CA cert with the CA private key.</param> /// <returns>The certificate with a private key.</returns> public static X509Certificate2 CreateCertificate( string storeType, string storePath, string password, string applicationUri, string applicationName, string subjectName, IList <String> domainNames, ushort keySize, DateTime startTime, ushort lifetimeInMonths, ushort hashSizeInBits, bool isCA, X509Certificate2 issuerCAKeyCert) { if (issuerCAKeyCert != null) { if (!issuerCAKeyCert.HasPrivateKey) { throw new NotSupportedException("Cannot sign with a CA certificate without a private key."); } throw new NotSupportedException("Signing with an issuer CA certificate is currently unsupported."); } // set default values. SetSuitableDefaults( ref applicationUri, ref applicationName, ref subjectName, ref domainNames, ref keySize, ref lifetimeInMonths, isCA); // cert generators SecureRandom random = new SecureRandom(); X509V3CertificateGenerator cg = new X509V3CertificateGenerator(); // Serial Number BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); cg.SetSerialNumber(serialNumber); // build name attributes var nameOids = new ArrayList(); nameOids.Add(X509Name.DC); nameOids.Add(X509Name.CN); var nameValues = new ArrayList(); nameValues.Add(domainNames[0]); nameValues.Add(subjectName); // self signed X509Name subjectDN = new X509Name(nameOids, nameValues); X509Name issuerDN = subjectDN; cg.SetIssuerDN(issuerDN); cg.SetSubjectDN(subjectDN); // valid for cg.SetNotBefore(startTime); cg.SetNotAfter(startTime.AddMonths(lifetimeInMonths)); // Private/Public Key AsymmetricCipherKeyPair subjectKeyPair; var keyGenerationParameters = new KeyGenerationParameters(random, keySize); var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); subjectKeyPair = keyPairGenerator.GenerateKeyPair(); cg.SetPublicKey(subjectKeyPair.Public); // add extensions // Subject key identifier cg.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, false, new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public))); // Basic constraints cg.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCA)); // Authority Key identifier var issuerKeyPair = subjectKeyPair; var issuerSerialNumber = serialNumber; cg.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false, new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public), new GeneralNames(new GeneralName(issuerDN)), issuerSerialNumber)); if (!isCA) { // Key usage cg.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DataEncipherment | KeyUsage.DigitalSignature | KeyUsage.NonRepudiation | KeyUsage.KeyCertSign | KeyUsage.KeyEncipherment)); // Extended Key usage cg.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(new List <DerObjectIdentifier>() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1"), // server auth new DerObjectIdentifier("1.3.6.1.5.5.7.3.2"), // client auth })); // subject alternate name cg.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName[] { new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri), new GeneralName(GeneralName.DnsName, domainNames[0]) })); } else { // Key usage CA cg.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.CrlSign | KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); } // sign certificate ISignatureFactory signatureFactory = new Asn1SignatureFactory((hashSizeInBits < 256) ? "SHA1WITHRSA" : "SHA256WITHRSA", subjectKeyPair.Private, random); Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory); // create pkcs12 store for cert and private key X509Certificate2 certificate = null; using (MemoryStream pfxData = new MemoryStream()) { Pkcs12Store pkcsStore = new Pkcs12StoreBuilder().Build(); X509CertificateEntry[] chain = new X509CertificateEntry[1]; string passcode = "passcode"; chain[0] = new X509CertificateEntry(x509); pkcsStore.SetKeyEntry(applicationName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain); pkcsStore.Save(pfxData, passcode.ToCharArray(), random); // merge into X509Certificate2 certificate = CreateCertificateFromPKCS12(pfxData.ToArray(), passcode); } Utils.Trace(Utils.TraceMasks.Security, "Created new certificate: {0}", certificate.Thumbprint); // add cert to the store. if (!String.IsNullOrEmpty(storePath)) { ICertificateStore store = null; if (storeType == CertificateStoreType.X509Store) { store = new X509CertificateStore(); } else if (storeType == CertificateStoreType.Directory) { store = new DirectoryCertificateStore(); } else { throw new ArgumentException("Invalid store type"); } store.Open(storePath); store.Add(certificate); store.Close(); store.Dispose(); } // note: this cert has a private key! return(certificate); }
/// <summary> /// Validates a certificate with domain validation check. /// <see cref="Validate(X509Certificate2Collection)"/> /// </summary> public virtual void Validate(X509Certificate2Collection chain, ConfiguredEndpoint endpoint) { X509Certificate2 certificate = chain[0]; try { lock (m_lock) { InternalValidate(chain, endpoint).GetAwaiter().GetResult(); // add to list of validated certificates. m_validatedCertificates[certificate.Thumbprint] = new X509Certificate2(certificate.RawData); } } catch (ServiceResultException se) { // check for errors that may be suppressed. if (ContainsUnsuppressibleSC(se.Result)) { SaveCertificate(certificate); Utils.Trace(Utils.TraceMasks.Error, "Certificate '{0}' rejected. Reason={1}.", certificate.Subject, se.Result.ToString()); TraceInnerServiceResults(se.Result); throw new ServiceResultException(se, StatusCodes.BadCertificateInvalid); } else { Utils.Trace("Certificate Vaildation failed for '{0}'. Reason={1}", certificate.Subject, se.ToLongString()); TraceInnerServiceResults(se.Result); } // invoke callback. bool accept = false; ServiceResult serviceResult = se.Result; lock (m_callbackLock) { if (m_CertificateValidation != null) { do { CertificateValidationEventArgs args = new CertificateValidationEventArgs(serviceResult, certificate); m_CertificateValidation(this, args); if (args.AcceptAll) { accept = true; serviceResult = null; break; } accept = args.Accept; if (accept) { serviceResult = serviceResult.InnerResult; } else { // report the rejected service result se = new ServiceResultException(serviceResult); } } while (accept && serviceResult != null); } } // throw if rejected. if (!accept) { // write the invalid certificate to rejected store if specified. Utils.Trace(Utils.TraceMasks.Error, "Certificate '{0}' rejected. Reason={1}", certificate.Subject, serviceResult != null ? serviceResult.ToString() : "Unknown Error"); SaveCertificate(certificate); throw new ServiceResultException(se, StatusCodes.BadCertificateInvalid); } // add to list of peers. lock (m_lock) { Utils.Trace("Validation error suppressed for '{0}'.", certificate.Subject); m_validatedCertificates[certificate.Thumbprint] = new X509Certificate2(certificate.RawData); } } }