/// <summary> /// Updates the certificate authority certificate and CRL in the trusted list. /// </summary> protected async Task UpdateAuthorityCertInTrustedList() { string trustedListStorePath = Configuration.TrustedListPath; if (!String.IsNullOrEmpty(Configuration.TrustedListPath)) { using (ICertificateStore authorityStore = CertificateStoreIdentifier.OpenStore(m_authoritiesStorePath)) using (ICertificateStore trustedStore = CertificateStoreIdentifier.OpenStore(trustedListStorePath)) { X509Certificate2Collection certificates = await authorityStore.Enumerate(); foreach (var certificate in certificates) { if (X509Utils.CompareDistinguishedName(certificate.Subject, m_subjectName)) { X509Certificate2Collection certs = await trustedStore.FindByThumbprint(certificate.Thumbprint); if (certs.Count == 0) { await trustedStore.Add(new X509Certificate2(certificate.RawData)); } // delete existing CRL in trusted list foreach (var crl in trustedStore.EnumerateCRLs(certificate, false)) { if (crl.VerifySignature(certificate, false)) { trustedStore.DeleteCRL(crl); } } // copy latest CRL to trusted list foreach (var crl in authorityStore.EnumerateCRLs(certificate, true)) { trustedStore.AddCRL(crl); } } } } } }
// Encrypts the given element with the certificate specified. The certificate is added as // an X509Data KeyInfo to an EncryptedKey (AES session key) generated randomly. public EncryptedData Encrypt(XmlElement inputElement, X509Certificate2 certificate) { if (inputElement == null) { throw new ArgumentNullException("inputElement"); } if (certificate == null) { throw new ArgumentNullException("certificate"); } if (X509Utils.OidToAlgId(certificate.PublicKey.Oid.Value) != CAPI.CALG_RSA_KEYX) { throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_KeyAlgorithm")); } // Create the EncryptedData object, using an AES-256 session key by default. EncryptedData ed = new EncryptedData(); ed.Type = EncryptedXml.XmlEncElementUrl; ed.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url); // Include the certificate in the EncryptedKey KeyInfo. EncryptedKey ek = new EncryptedKey(); ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url); ek.KeyInfo.AddClause(new KeyInfoX509Data(certificate)); // Create a random AES session key and encrypt it with the public key associated with the certificate. RijndaelManaged rijn = new RijndaelManaged(); ek.CipherData.CipherValue = EncryptedXml.EncryptKey(rijn.Key, certificate.PublicKey.Key as RSA, false); // Encrypt the input element with the random session key that we've created above. KeyInfoEncryptedKey kek = new KeyInfoEncryptedKey(ek); ed.KeyInfo.AddClause(kek); ed.CipherData.CipherValue = EncryptData(inputElement, rijn, false); return(ed); }
public void UpdateCertificateSelfSignedNoPrivateKey() { ConnectPushClient(true); using (X509Certificate2 invalidCert = CertificateFactory.CreateCertificate(null, null, null, "uri:x:y:z", "TestApp", "CN=Push Server Test", null, 2048, DateTime.UtcNow, 1, 256)) using (X509Certificate2 serverCert = new X509Certificate2(_pushClient.PushClient.Session.ConfiguredEndpoint.Description.ServerCertificate)) { if (!X509Utils.CompareDistinguishedName(serverCert.Subject, serverCert.Issuer)) { Assert.Ignore("Server has no self signed cert in use."); } byte[] invalidRawCert = { 0xba, 0xd0, 0xbe, 0xef, 3 }; // negative test all parameter combinations NodeId invalidCertGroup = new NodeId(333); NodeId invalidCertType = new NodeId(Guid.NewGuid()); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, null, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(invalidCertGroup, null, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, invalidCertType, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(invalidCertGroup, invalidCertType, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, invalidRawCert, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, invalidCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, "XYZ", null, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, "XYZ", invalidCert.RawData, null); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, invalidCert.RawData, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, null, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, invalidRawCert, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, null, null, new byte[][] { serverCert.RawData, invalidRawCert }); }, Throws.Exception); Assert.That(() => { _pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, null, null, null); }, Throws.Exception); var success = _pushClient.PushClient.UpdateCertificate( null, _pushClient.PushClient.ApplicationCertificateType, serverCert.RawData, null, null, null); if (success) { _pushClient.PushClient.ApplyChanges(); } VerifyNewPushServerCert(serverCert.RawData); } }
public void CreateSelfSignedForRSACustomHashDefaultKey( KeyHashPair keyHashPair ) { // default cert with custom HashAlgorithm var cert = CertificateBuilder.Create(Subject) .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .CreateForRSA(); Assert.NotNull(cert); WriteCertificate(cert, $"Default RSA {keyHashPair.HashAlgorithmName} cert"); Assert.AreEqual(Subject, cert.Subject); Assert.AreEqual(X509Defaults.RSAKeySize, cert.GetRSAPublicKey().KeySize); Assert.AreEqual(keyHashPair.HashAlgorithmName, Oids.GetHashAlgorithmName(cert.SignatureAlgorithm.Value)); var basicConstraintsExtension = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert.Extensions); Assert.NotNull(basicConstraintsExtension); Assert.True(basicConstraintsExtension.CertificateAuthority); X509Utils.VerifyRSAKeyPair(cert, cert, true); Assert.True(X509Utils.VerifySelfSigned(cert)); }
public void CreateSelfSignedForRSAAllFields( KeyHashPair keyHashPair ) { // set dates and extension var applicationUri = "urn:opcfoundation.org:mypc"; var domains = new string[] { "mypc", "mypc.opcfoundation.org", "192.168.1.100" }; var cert = CertificateBuilder.Create(Subject) .SetNotBefore(DateTime.Today.AddYears(-1)) .SetNotAfter(DateTime.Today.AddYears(25)) .AddExtension(new X509SubjectAltNameExtension(applicationUri, domains)) .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .SetRSAKeySize(keyHashPair.KeySize) .CreateForRSA(); Assert.NotNull(cert); WriteCertificate(cert, $"Default cert RSA {keyHashPair.KeySize} with modified lifetime and alt name extension"); Assert.AreEqual(Subject, cert.Subject); using (var privateKey = cert.GetRSAPrivateKey()) { Assert.NotNull(privateKey); privateKey.ExportParameters(false); privateKey.ExportParameters(true); } using (var publicKey = cert.GetRSAPublicKey()) { Assert.NotNull(publicKey); publicKey.ExportParameters(false); } Assert.AreEqual(keyHashPair.KeySize, cert.GetRSAPublicKey().KeySize); Assert.AreEqual(keyHashPair.HashAlgorithmName, Oids.GetHashAlgorithmName(cert.SignatureAlgorithm.Value)); var basicConstraintsExtension = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert.Extensions); Assert.NotNull(basicConstraintsExtension); Assert.True(basicConstraintsExtension.CertificateAuthority); X509Utils.VerifyRSAKeyPair(cert, cert, true); Assert.True(X509Utils.VerifySelfSigned(cert)); CheckPEMWriter(cert); }
public void CreateSelfSignedForRSADefaultTest() { // default cert X509Certificate2 cert = CertificateBuilder.Create(Subject).CreateForRSA(); Assert.NotNull(cert); WriteCertificate(cert, "Default RSA cert"); Assert.NotNull(cert.GetRSAPrivateKey()); var publicKey = cert.GetRSAPublicKey(); Assert.NotNull(publicKey); Assert.AreEqual(X509Defaults.RSAKeySize, publicKey.KeySize); Assert.AreEqual(X509Defaults.HashAlgorithmName, Oids.GetHashAlgorithmName(cert.SignatureAlgorithm.Value)); Assert.AreEqual(DateTime.UtcNow.AddDays(-1).Date, cert.NotBefore.ToUniversalTime()); Assert.AreEqual(cert.NotBefore.ToUniversalTime().AddMonths(X509Defaults.LifeTime), cert.NotAfter.ToUniversalTime()); var basicConstraintsExtension = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert.Extensions); Assert.NotNull(basicConstraintsExtension); Assert.True(basicConstraintsExtension.CertificateAuthority); X509Utils.VerifyRSAKeyPair(cert, cert); X509Utils.VerifySelfSigned(cert); }
private static unsafe int VerifyCertificate(X509Certificate2 certificate, X509Certificate2Collection extraStore) { int dwErrorStatus; int hr = X509Utils.VerifyCertificate(X509Utils.GetCertContext(certificate), null, null, X509RevocationMode.Online, X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), extraStore, new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), new IntPtr(&dwErrorStatus)); if (hr != CAPI.S_OK) { return(dwErrorStatus); } // Check key usages to make sure it is good for signing. foreach (X509Extension extension in certificate.Extensions) { if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); keyUsage.CopyFrom(extension); if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { hr = CAPI.CERT_E_WRONG_USAGE; break; } } } return(hr); }
public void CreateCACertForECDsa( ECCurveHashPair ecCurveHashPair ) { // create a CA cert var cert = CertificateBuilder.Create(Subject) .SetCAConstraint() .SetHashAlgorithm(ecCurveHashPair.HashAlgorithmName) .AddExtension(X509Extensions.BuildX509CRLDistributionPoints("http://myca/mycert.crl")) .SetECCurve(ecCurveHashPair.Curve) .CreateForECDsa(); Assert.NotNull(cert); WriteCertificate(cert, "Default cert with RSA {keyHashPair.KeySize} {keyHashPair.HashAlgorithmName} and CRL distribution points"); Assert.AreEqual(ecCurveHashPair.HashAlgorithmName, Oids.GetHashAlgorithmName(cert.SignatureAlgorithm.Value)); var basicConstraintsExtension = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert.Extensions); Assert.NotNull(basicConstraintsExtension); Assert.True(basicConstraintsExtension.CertificateAuthority); Assert.False(basicConstraintsExtension.HasPathLengthConstraint); X509PfxUtils.VerifyECDsaKeyPair(cert, cert, true); Assert.True(X509Utils.VerifySelfSigned(cert)); }
public void VerifyOneSelfSignedAppCertForAll() { var builder = CertificateBuilder.Create(Subject) .SetNotBefore(DateTime.Today.AddYears(-1)) .SetNotAfter(DateTime.Today.AddYears(25)) .AddExtension(new X509SubjectAltNameExtension("urn:opcfoundation.org:mypc", new string[] { "mypc", "mypc.opcfoundation.org", "192.168.1.100" })); byte[] previousSerialNumber = null; foreach (var keyHash in KeyHashPairs) { var cert = builder .SetHashAlgorithm(keyHash.HashAlgorithmName) .SetRSAKeySize(keyHash.KeySize) .CreateForRSA(); Assert.NotNull(cert); WriteCertificate(cert, $"Default cert with RSA {keyHash.KeySize} {keyHash.HashAlgorithmName} signature."); Assert.AreEqual(keyHash.HashAlgorithmName, Oids.GetHashAlgorithmName(cert.SignatureAlgorithm.Value)); // ensure serial numbers are different Assert.AreNotEqual(previousSerialNumber, cert.GetSerialNumber()); X509PfxUtils.VerifyRSAKeyPair(cert, cert, true); Assert.True(X509Utils.VerifySelfSigned(cert)); } }
public void UpdateCertificateSelfSignedNoPrivateKey() { ConnectPushClient(true); using (X509Certificate2 serverCert = new X509Certificate2(m_pushClient.PushClient.Session.ConfiguredEndpoint.Description.ServerCertificate)) { if (!X509Utils.CompareDistinguishedName(serverCert.Subject, serverCert.Issuer)) { Assert.Ignore("Server has no self signed cert in use."); } var success = m_pushClient.PushClient.UpdateCertificate( null, m_pushClient.PushClient.ApplicationCertificateType, serverCert.RawData, null, null, null); if (success) { m_pushClient.PushClient.ApplyChanges(); } VerifyNewPushServerCert(serverCert.RawData); } }
/// <summary> /// Verifies that a certificate user token is trusted. /// </summary> private bool VerifyCertificate(X509Certificate2 certificate) { try { if (_certificateValidator != null) { _certificateValidator.Validate(certificate); } else { CertificateValidator.Validate(certificate); } // determine if self-signed. var isSelfSigned = X509Utils.CompareDistinguishedName( certificate.Subject, certificate.Issuer); // do not allow self signed application certs as user token if (isSelfSigned && X509Utils.HasApplicationURN(certificate)) { throw new ServiceResultException(StatusCodes.BadCertificateUseNotAllowed); } return(false); } catch (Exception e) { TranslationInfo info; StatusCode result = StatusCodes.BadIdentityTokenRejected; if (e is ServiceResultException se && se.StatusCode == StatusCodes.BadCertificateUseNotAllowed) { info = new TranslationInfo( "InvalidCertificate", "en-US", "'{0}' is an invalid user certificate.", certificate.Subject); result = StatusCodes.BadIdentityTokenInvalid; }
/// <summary> /// Create OPC UA client configuration /// </summary> /// <returns></returns> /// <param name="clientName"></param> /// <param name="configPath"></param> /// <exception cref="ArgumentNullException"></exception> public async Task <ApplicationConfiguration> CreateOpcUaConfiguration(string clientName, string configPath) { if (string.IsNullOrWhiteSpace(clientName)) { throw new ArgumentNullException(nameof(clientName)); } if (string.IsNullOrWhiteSpace(configPath)) { throw new ArgumentNullException(nameof(configPath)); } var application = new ApplicationInstance { ApplicationName = clientName, ApplicationType = ApplicationType.Client, ConfigSectionName = clientName, }; var clientApplicationConfig = await application.LoadApplicationConfiguration(filePath : configPath, silent : false); var haveAppCertificate = await application.CheckApplicationInstanceCertificate(silent : false, minimumKeySize : 0); if (!haveAppCertificate) { throw new Exception(Text.InvalidCertificate); } clientApplicationConfig.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(certificate: clientApplicationConfig.SecurityConfiguration.ApplicationCertificate.Certificate); clientApplicationConfig.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(this.SessionAutoAcceptCertificate_Event); return(clientApplicationConfig); }
public void VerifyCACerts( KeyHashPair keyHashPair ) { var subject = "CN=CA Test Cert"; int pathLengthConstraint = (keyHashPair.KeySize / 512) - 3; var cert = CertificateFactory.CreateCertificate(subject) .SetLifeTime(25 * 12) .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .SetCAConstraint(pathLengthConstraint) .SetRSAKeySize(keyHashPair.KeySize) .CreateForRSA(); Assert.NotNull(cert); Assert.NotNull(cert.RawData); Assert.True(cert.HasPrivateKey); var plainCert = new X509Certificate2(cert.RawData); Assert.NotNull(plainCert); VerifyCACert(plainCert, subject, pathLengthConstraint); X509Utils.VerifyRSAKeyPair(cert, cert, true); Assert.True(X509Utils.VerifySelfSigned(cert)); m_rootCACertificate[keyHashPair.KeySize] = cert; }
void NewKeyStore(object o) { var passwordBoxes = (object[])o; var errors = ValidateInputs(passwordBoxes); if (!errors.ToString().IsNullOrEmpty()) { MessageBoxContent = new MessageBoxViewModel(CloseMessageBox, MessageBoxModel.Error("Errors generating Certificate - " + Environment.NewLine + errors.ToString())); IsMessageBoxVisible = true; return; } var password = ((PasswordBox)passwordBoxes[0]).Password.ToCharArray(); var keygen = KeyPairUtils.CreateGenerator(Repository.Srand, Model.KeyPairGenerator, Model.KeyStrength); var keypair = keygen.GenerateKeyPair(); var repo = Repository.Instance; repo.NewCertificateAuthority(Model.CARepositoryPath, password); repo.KeyPairType = Model.KeyPairType; var cert = X509Utils.GenerateCACertificate(Model.X509Name, Model.Validity, keypair.Public, keypair.Private, Model.SignatureAlgorithm, KeyUsageUtils.GetKeyUsage(Model.KeyUsages), Model.ExtendedKeyUsages == null ? null : new ExtendedKeyUsage(KeyUsageUtils.GetExtendedKeyUsages(Model.ExtendedKeyUsages)), Model.PathLenContraint); X509Utils.ExportPKCS12(Repository.Instance.CAKeyStore, /*Model.CommonName*/ "ca", keypair.Private, password, cert); File.WriteAllText(Repository.CaPfxFilename, PemUtilities.Encode(cert)); _newCaCompletedAction.Invoke(new KeyStoreViewModel(password, Model.CARepositoryPath)); //KeyStoreViewModelEx.Instance.Load(password); }
/// <summary> /// Revoke the CA signed certificate. /// The issuer CA public key, the private key and the crl reside in the storepath. /// The CRL number is increased by one and existing CRL for the issuer are deleted from the store. /// </summary> public static async Task <X509CRL> RevokeCertificateAsync( string storePath, X509Certificate2 certificate, string issuerKeyFilePassword = null ) { X509CRL updatedCRL = null; string subjectName = certificate.IssuerName.Name; string keyId = null; string serialNumber = null; // caller may want to create empty CRL using the CA cert itself bool isCACert = X509Utils.IsCertificateAuthority(certificate); // find the authority key identifier. X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(certificate); if (authority != null) { keyId = authority.KeyIdentifier; serialNumber = authority.SerialNumber; } else { throw new ArgumentException("Certificate does not contain an Authority Key"); } if (!isCACert) { if (serialNumber == certificate.SerialNumber || X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer)) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot revoke self signed certificates"); } } X509Certificate2 certCA = null; using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(storePath)) { if (store == null) { throw new ArgumentException("Invalid store path/type"); } certCA = await X509Utils.FindIssuerCABySerialNumberAsync(store, certificate.Issuer, serialNumber).ConfigureAwait(false); if (certCA == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot find issuer certificate in store."); } if (!certCA.HasPrivateKey) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate."); } CertificateIdentifier certCAIdentifier = new CertificateIdentifier(certCA) { StorePath = storePath, StoreType = CertificateStoreIdentifier.DetermineStoreType(storePath) }; X509Certificate2 certCAWithPrivateKey = await certCAIdentifier.LoadPrivateKey(issuerKeyFilePassword).ConfigureAwait(false); if (certCAWithPrivateKey == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Failed to load issuer private key. Is the password correct?"); } List <X509CRL> certCACrl = store.EnumerateCRLs(certCA, false); var certificateCollection = new X509Certificate2Collection() { }; if (!isCACert) { certificateCollection.Add(certificate); } updatedCRL = CertificateFactory.RevokeCertificate(certCAWithPrivateKey, certCACrl, certificateCollection); store.AddCRL(updatedCRL); // delete outdated CRLs from store foreach (X509CRL caCrl in certCACrl) { store.DeleteCRL(caCrl); } store.Close(); } return(updatedCRL); }
internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyInfoX509Data, CertUsageType certUsageType) { X509Certificate2Collection collection = new X509Certificate2Collection(); ArrayList decryptionIssuerSerials = (certUsageType == CertUsageType.Decryption ? new ArrayList() : null); if (keyInfoX509Data.Certificates != null) { foreach (X509Certificate2 certificate in keyInfoX509Data.Certificates) { switch (certUsageType) { case CertUsageType.Verification: collection.Add(certificate); break; case CertUsageType.Decryption: decryptionIssuerSerials.Add(new X509IssuerSerial(certificate.IssuerName.Name, certificate.SerialNumber)); break; } } } if (keyInfoX509Data.SubjectNames == null && keyInfoX509Data.IssuerSerials == null && keyInfoX509Data.SubjectKeyIds == null && decryptionIssuerSerials == null) { return(collection); } // Open LocalMachine and CurrentUser "Other People"/"My" stores. // Assert OpenStore since we are not giving back any certificates to the user. StorePermission sp = new StorePermission(StorePermissionFlags.OpenStore); sp.Assert(); X509Store[] stores = new X509Store[2]; string storeName = (certUsageType == CertUsageType.Verification ? "AddressBook" : "My"); stores[0] = new X509Store(storeName, StoreLocation.CurrentUser); stores[1] = new X509Store(storeName, StoreLocation.LocalMachine); for (int index = 0; index < stores.Length; index++) { if (stores[index] != null) { X509Certificate2Collection filters = null; // We don't care if we can't open the store. try { stores[index].Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); filters = stores[index].Certificates; stores[index].Close(); if (keyInfoX509Data.SubjectNames != null) { foreach (string subjectName in keyInfoX509Data.SubjectNames) { filters = filters.Find(X509FindType.FindBySubjectDistinguishedName, subjectName, false); } } if (keyInfoX509Data.IssuerSerials != null) { foreach (X509IssuerSerial issuerSerial in keyInfoX509Data.IssuerSerials) { filters = filters.Find(X509FindType.FindByIssuerDistinguishedName, issuerSerial.IssuerName, false); filters = filters.Find(X509FindType.FindBySerialNumber, issuerSerial.SerialNumber, false); } } if (keyInfoX509Data.SubjectKeyIds != null) { foreach (byte[] ski in keyInfoX509Data.SubjectKeyIds) { string hex = X509Utils.EncodeHexString(ski); filters = filters.Find(X509FindType.FindBySubjectKeyIdentifier, hex, false); } } if (decryptionIssuerSerials != null) { foreach (X509IssuerSerial issuerSerial in decryptionIssuerSerials) { filters = filters.Find(X509FindType.FindByIssuerDistinguishedName, issuerSerial.IssuerName, false); filters = filters.Find(X509FindType.FindBySerialNumber, issuerSerial.SerialNumber, false); } } } catch (CryptographicException) {} if (filters != null) { collection.AddRange(filters); } } } return(collection); }
/// <summary> /// Adds the certificate to the Trusted Certificate Store /// </summary> /// <param name="configuration">The application's configuration which specifies the location of the TrustedStore.</param> /// <param name="certificate">The certificate to register.</param> private static async Task AddToTrustedStore(ApplicationConfiguration configuration, X509Certificate2 certificate) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } string storePath = null; if (configuration != null && configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null) { storePath = configuration.SecurityConfiguration.TrustedPeerCertificates.StorePath; } if (String.IsNullOrEmpty(storePath)) { Utils.Trace(Utils.TraceMasks.Information, "WARNING: Trusted peer store not specified."); return; } try { ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore(); if (store == null) { Utils.Trace("Could not open trusted peer store. StorePath={0}", storePath); return; } try { // check if it already exists. X509Certificate2Collection existingCertificates = await store.FindByThumbprint(certificate.Thumbprint); if (existingCertificates.Count > 0) { return; } Utils.Trace(Utils.TraceMasks.Information, "Adding certificate to trusted peer store. StorePath={0}", storePath); List <string> subjectName = X509Utils.ParseDistinguishedName(certificate.Subject); // check for old certificate. X509Certificate2Collection certificates = await store.Enumerate(); for (int ii = 0; ii < certificates.Count; ii++) { if (X509Utils.CompareDistinguishedName(certificates[ii], subjectName)) { if (certificates[ii].Thumbprint == certificate.Thumbprint) { return; } await store.Delete(certificates[ii].Thumbprint); break; } } // add new certificate. X509Certificate2 publicKey = new X509Certificate2(certificate.RawData); await store.Add(publicKey); } finally { store.Close(); } } catch (Exception e) { Utils.Trace(e, "Could not add certificate to trusted peer store. StorePath={0}", storePath); } }
/// <summary> /// Checks that the domains in the server addresses match the domains in the certificates. /// </summary> private static async Task <bool> CheckDomainsInCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent) { Utils.Trace(Utils.TraceMasks.Information, "Checking domains in certificate. {0}", certificate.Subject); bool valid = true; IList <string> serverDomainNames = configuration.GetServerDomainNames(); IList <string> certificateDomainNames = X509Utils.GetDomainsFromCertficate(certificate); // get computer name. string computerName = Utils.GetHostName(); // get IP addresses. IPAddress[] addresses = null; for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } // check for aliases. bool found = false; // get IP addresses only if necessary. if (addresses == null) { addresses = await Utils.GetHostAddressesAsync(computerName); } // check for ip addresses. for (int jj = 0; jj < addresses.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, addresses[jj].ToString())) { found = true; break; } } if (found) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Use certificate?", serverDomainNames[ii]); valid = false; if (await ApproveMessage(message, silent)) { valid = true; continue; } break; } return(valid); }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> private static async Task <bool> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent, ushort minimumKeySize) { if (certificate == null) { return(false); } Utils.Trace(Utils.TraceMasks.Information, "Checking application instance certificate. {0}", certificate.Subject); try { // validate certificate. configuration.CertificateValidator.Validate(certificate); } catch (Exception ex) { string message = Utils.Format( "Error validating certificate. Exception: {0}. Use certificate anyway?", ex.Message); if (!await ApproveMessage(message, silent)) { return(false); } } // check key size. int keySize = X509Utils.GetRSAPublicKeySize(certificate); if (minimumKeySize > keySize) { string message = Utils.Format( "The key size ({0}) in the certificate is less than the minimum provided ({1}). Use certificate anyway?", keySize, minimumKeySize); if (!await ApproveMessage(message, silent)) { return(false); } } // check domains. if (configuration.ApplicationType != ApplicationType.Client) { if (!await CheckDomainsInCertificate(configuration, certificate, silent)) { return(false); } } // check uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(certificate); if (String.IsNullOrEmpty(applicationUri)) { string message = "The Application URI could not be read from the certificate. Use certificate anyway?"; if (!await ApproveMessage(message, silent)) { return(false); } } else { configuration.ApplicationUri = applicationUri; } // update configuration. configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; return(true); }
private async Task ConsoleClient() { Log(conn_name + " - " + "Create an Application Configuration..."); exitCode = ExitCode.ErrorCreateApplication; ApplicationInstance application = new ApplicationInstance { ApplicationName = "JSON-SCADA OPC-UA Client", ApplicationType = ApplicationType.Client, ConfigSectionName = "", }; bool haveAppCertificate = false; ApplicationConfiguration config = null; try { // load the application configuration. Log(conn_name + " - " + "Load config from " + OPCUA_conn.configFileName); config = await application.LoadApplicationConfiguration(OPCUA_conn.configFileName, false); // config.SecurityConfiguration.AutoAcceptUntrustedCertificates = true; // check the application certificate. haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); if (!haveAppCertificate) { Log(conn_name + " - " + "FATAL: Application instance certificate invalid!", LogLevelNoLog); Environment.Exit(1); } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { autoAccept = true; } config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation); } else { Log(conn_name + " - " + "WARN: missing application certificate, using unsecure connection."); } } catch (Exception e) { Log(conn_name + " - WARN: " + e.Message); } if (config == null) { Log(conn_name + " - " + "FATAL: error in XML config file!", LogLevelNoLog); Environment.Exit(1); } try { Log(conn_name + " - " + "Discover endpoints of " + OPCUA_conn.endpointURLs[0]); exitCode = ExitCode.ErrorDiscoverEndpoints; var selectedEndpoint = CoreClientUtils.SelectEndpoint(OPCUA_conn.endpointURLs[0], haveAppCertificate && OPCUA_conn.useSecurity, 15000); Log(conn_name + " - " + "Selected endpoint uses: " + selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1)); Log(conn_name + " - " + "Create a session with OPC UA server."); exitCode = ExitCode.ErrorCreateSession; var endpointConfiguration = EndpointConfiguration.Create(config); var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration); await Task.Delay(50); session = await Session.Create(config, endpoint, false, "OPC UA Console Client", 60000, new UserIdentity(new AnonymousIdentityToken()), null); // Log("" + session.KeepAliveInterval); // default is 5000 session.KeepAliveInterval = System.Convert.ToInt32(OPCUA_conn.timeoutMs); // register keep alive handler session.KeepAlive += Client_KeepAlive; } catch (Exception e) { Log(conn_name + " - WARN: " + e.Message); } if (session == null) { Log(conn_name + " - " + "FATAL: error creating session!", LogLevelNoLog); Environment.Exit(1); } Log(conn_name + " - " + "Browsing the OPC UA server namespace."); exitCode = ExitCode.ErrorBrowseNamespace; await FindObjects(session, ObjectIds.ObjectsFolder); await Task.Delay(50); Log(conn_name + " - " + "Add a list of items (server current time and status) to the subscription."); exitCode = ExitCode.ErrorMonitoredItem; ListMon.ForEach(i => i.Notification += OnNotification); //ListMon.ForEach(i => i.SamplingInterval = System.Convert.ToInt32(System.Convert.ToDouble(OPCUA_conn.autoCreateTagSamplingInterval) * 1000); // ListMon.ForEach(i => Log(conn_name + " - " + i.DisplayName)); Log(conn_name + " - " + ListMon.Count + " Objects found"); Log(conn_name + " - " + "Create a subscription with publishing interval of " + System.Convert.ToDouble(OPCUA_conn.autoCreateTagPublishingInterval) + "seconds"); exitCode = ExitCode.ErrorCreateSubscription; var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = System.Convert.ToInt32(System.Convert.ToDouble(OPCUA_conn.autoCreateTagPublishingInterval) * 1000), PublishingEnabled = true }; await Task.Delay(50); subscription.AddItems(ListMon); await Task.Delay(50); Log(conn_name + " - " + "Add the subscription to the session."); Log(conn_name + " - " + subscription.MonitoredItemCount + " Monitored items"); exitCode = ExitCode.ErrorAddSubscription; session.AddSubscription(subscription); subscription.Create(); subscription.ApplyChanges(); Log(conn_name + " - " + "Running..."); exitCode = ExitCode.ErrorRunning; }
private ServiceResult CreateSigningRequest( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, string subjectName, bool regeneratePrivateKey, byte[] nonce, ref byte[] certificateRequest) { HasApplicationSecureAdminAccess(context); ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); if (!String.IsNullOrEmpty(subjectName)) { throw new ArgumentNullException(nameof(subjectName)); } // TODO: implement regeneratePrivateKey // TODO: use nonce for generating the private key var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; Utils.LogCertificate(Utils.TraceMasks.Security, "Create signing request: ", certWithPrivateKey); certificateRequest = CertificateFactory.CreateSigningRequest(certWithPrivateKey, X509Utils.GetDomainsFromCertficate(certWithPrivateKey)); return(ServiceResult.Good); }
/// <summary> /// Create the RSA certificate as Pfx byte array with a private key. /// </summary> /// <returns> /// Returns the Pfx with certificate and private key. /// </returns> private byte[] CreatePfxForRSA(string passcode, ISignatureFactory signatureFactory = null) { // Cases locked out by API flow Debug.Assert(m_rsaPublicKey == null, "A public key is not supported for the certificate."); if (signatureFactory != null && IssuerCAKeyCert == null) { throw new NotSupportedException("Need an issuer certificate for a signature generator."); } if (IssuerCAKeyCert != null && (!IssuerCAKeyCert.HasPrivateKey && signatureFactory == null)) { throw new NotSupportedException("Need an issuer certificate with a private key or a signature generator."); } using (var cfrg = new CertificateFactoryRandomGenerator()) { // cert generators SecureRandom random = new SecureRandom(cfrg); CreateDefaults(cfrg); X509V3CertificateGenerator cg = new X509V3CertificateGenerator(); CreateMandatoryFields(cg); // create Private/Public Keypair AsymmetricKeyParameter subjectPublicKey = null; AsymmetricKeyParameter subjectPrivateKey = null; using (var rsa = new RSACryptoServiceProvider(m_keySize == 0 ? X509Defaults.RSAKeySize : m_keySize)) { subjectPublicKey = X509Utils.GetPublicKeyParameter(rsa); subjectPrivateKey = X509Utils.GetPrivateKeyParameter(rsa); } cg.SetPublicKey(subjectPublicKey); CreateExtensions(cg, subjectPublicKey); // sign certificate if (signatureFactory == null) { AsymmetricKeyParameter signingKey; if (IssuerCAKeyCert != null) { // signed by issuer signingKey = X509Utils.GetPrivateKeyParameter(IssuerCAKeyCert); } else { // self signed signingKey = subjectPrivateKey; } signatureFactory = new Asn1SignatureFactory( X509Utils.GetRSAHashAlgorithm(HashAlgorithmName), signingKey, random); } Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory); // note: this Pfx has a private key! return(X509Utils.CreatePfxWithPrivateKey(x509, null, subjectPrivateKey, passcode, random)); } }
/// <summary> /// Creates a certificate signing request from an /// existing certificate with a private key. /// </summary> public static byte[] CreateSigningRequest( X509Certificate2 certificate, IList <String> domainNames = null ) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } using (var cfrg = new CertificateFactoryRandomGenerator()) { SecureRandom random = new SecureRandom(cfrg); // try to get signing/private key from certificate passed in AsymmetricKeyParameter signingKey = X509Utils.GetPrivateKeyParameter(certificate); RsaKeyParameters publicKey = X509Utils.GetPublicKeyParameter(certificate); ISignatureFactory signatureFactory = new Asn1SignatureFactory(X509Utils.GetRSAHashAlgorithm(X509Defaults.HashAlgorithmName), signingKey, random); Asn1Set attributes = null; var san = X509Extensions.FindExtension <X509SubjectAltNameExtension>(certificate); X509SubjectAltNameExtension alternateName = new X509SubjectAltNameExtension(san, san.Critical); string applicationUri = null; domainNames = domainNames ?? new List <String>(); if (alternateName != null) { if (alternateName.Uris.Count > 0) { applicationUri = alternateName.Uris[0]; } foreach (var name in alternateName.DomainNames) { if (!domainNames.Any(s => s.Equals(name, StringComparison.OrdinalIgnoreCase))) { domainNames.Add(name); } } foreach (var ipAddress in alternateName.IPAddresses) { if (!domainNames.Any(s => s.Equals(ipAddress, StringComparison.OrdinalIgnoreCase))) { domainNames.Add(ipAddress); } } } // build CSR extensions var generalNames = new List <GeneralName>(); if (applicationUri != null) { generalNames.Add(new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri)); } if (domainNames.Count > 0) { generalNames.AddRange(BouncyCastle.X509Extensions.CreateSubjectAlternateNameDomains(domainNames)); } if (generalNames.Count > 0) { IList oids = new ArrayList(); IList values = new ArrayList(); oids.Add(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName); values.Add(new Org.BouncyCastle.Asn1.X509.X509Extension(false, new DerOctetString(new GeneralNames(generalNames.ToArray()).GetDerEncoded()))); var attribute = new Org.BouncyCastle.Asn1.Pkcs.AttributePkcs(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtExtensionRequest, new DerSet(new Org.BouncyCastle.Asn1.X509.X509Extensions(oids, values))); attributes = new DerSet(attribute); } var pkcs10CertificationRequest = new Pkcs10CertificationRequest( signatureFactory, new CertificateFactoryX509Name(false, certificate.Subject), publicKey, attributes); return(pkcs10CertificationRequest.GetEncoded()); } }
public virtual async Task <X509Certificate2> SigningRequestAsync( ApplicationRecordDataType application, string[] domainNames, byte[] certificateRequest) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null) { if (altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(application.ApplicationUri)) { throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, "CSR AltNameExtension does not match " + application.ApplicationUri); } } if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0) { var domainNameList = new List <string>(); domainNameList.AddRange(altNameExtension.DomainNames); domainNameList.AddRange(altNameExtension.IPAddresses); domainNames = domainNameList.ToArray(); } } DateTime yesterday = DateTime.Today.AddDays(-1); using (var signingKey = await LoadSigningKeyAsync(Certificate, string.Empty).ConfigureAwait(false)) { return(CertificateFactory.CreateCertificate( application.ApplicationUri, null, info.Subject.ToString(), domainNames) .SetNotBefore(yesterday) .SetLifeTime(Configuration.DefaultCertificateLifetime) .SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(Configuration.DefaultCertificateHashSize)) .SetIssuer(signingKey) .SetRSAPublicKey(info.SubjectPublicKeyInfo.GetEncoded()) .CreateForRSA()); } } catch (Exception ex) { if (ex is ServiceResultException) { throw ex as ServiceResultException; } throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); } }
/// <summary> /// Create the extensions. /// </summary> /// <param name="cg">The cert generator.</param> /// <param name="subjectPublicKey">The public key to use for the extensions.</param> private void CreateExtensions(X509V3CertificateGenerator cg, AsymmetricKeyParameter subjectPublicKey) { // Subject key identifier cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectKeyIdentifier.Id, false, new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectPublicKey))); // Basic constraints BasicConstraints basicConstraints = new BasicConstraints(m_isCA); if (m_isCA && m_pathLengthConstraint >= 0) { basicConstraints = new BasicConstraints(m_pathLengthConstraint); } else if (!m_isCA && IssuerCAKeyCert == null) { // self-signed basicConstraints = new BasicConstraints(0); } cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.BasicConstraints.Id, true, basicConstraints); // Authority Key identifier references the issuer cert or itself when self signed AsymmetricKeyParameter issuerPublicKey; BigInteger issuerSerialNumber; if (IssuerCAKeyCert != null) { issuerPublicKey = X509Utils.GetPublicKeyParameter(IssuerCAKeyCert); issuerSerialNumber = X509Utils.GetSerialNumber(IssuerCAKeyCert); } else { issuerPublicKey = subjectPublicKey; issuerSerialNumber = new BigInteger(1, m_serialNumber.Reverse().ToArray()); } cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityKeyIdentifier.Id, false, new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerPublicKey), new GeneralNames(new GeneralName(m_issuerDN)), issuerSerialNumber)); if (!m_isCA) { // Key usage var keyUsage = KeyUsage.DataEncipherment | KeyUsage.DigitalSignature | KeyUsage.NonRepudiation | KeyUsage.KeyEncipherment; if (IssuerCAKeyCert == null) { // only self signed certs need KeyCertSign flag. keyUsage |= KeyUsage.KeyCertSign; } cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.KeyUsage, true, new KeyUsage(keyUsage)); // Extended Key usage cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(new List <DerObjectIdentifier>() { new DerObjectIdentifier(Oids.ServerAuthentication), // server auth new DerObjectIdentifier(Oids.ClientAuthentication), // client auth })); } else { // Key usage CA cg.AddExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.CrlSign | KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); } foreach (var extension in m_extensions) { cg.AddExtension(extension.Oid.Value, extension.Critical, Asn1Object.FromByteArray(extension.RawData)); } }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> private async Task <bool> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent, ushort minimumKeySize) { if (certificate == null) { return(false); } // set suppressible errors var certValidator = new CertValidationSuppressibleStatusCodes( new StatusCode[] { StatusCodes.BadCertificateUntrusted, StatusCodes.BadCertificateTimeInvalid, StatusCodes.BadCertificateHostNameInvalid, StatusCodes.BadCertificateRevocationUnknown, StatusCodes.BadCertificateIssuerRevocationUnknown, }); Utils.LogCertificate("Check application instance certificate.", certificate); try { // validate certificate. configuration.CertificateValidator.CertificateValidation += certValidator.OnCertificateValidation; configuration.CertificateValidator.Validate(certificate.HasPrivateKey ? new X509Certificate2(certificate.RawData) : certificate); } catch (Exception ex) { string message = Utils.Format( "Error validating certificate. Exception: {0}. Use certificate anyway?", ex.Message); if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } finally { configuration.CertificateValidator.CertificateValidation -= certValidator.OnCertificateValidation; } // check key size. int keySize = X509Utils.GetRSAPublicKeySize(certificate); if (minimumKeySize > keySize) { string message = Utils.Format( "The key size ({0}) in the certificate is less than the minimum allowed ({1}). Use certificate anyway?", keySize, minimumKeySize); if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } // check domains. if (configuration.ApplicationType != ApplicationType.Client) { if (!await CheckDomainsInCertificate(configuration, certificate, silent).ConfigureAwait(false)) { return(false); } } // check uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(certificate); if (String.IsNullOrEmpty(applicationUri)) { string message = "The Application URI could not be read from the certificate. Use certificate anyway?"; if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } else if (!configuration.ApplicationUri.Equals(applicationUri, StringComparison.InvariantCulture)) { Utils.LogInfo("Updated the ApplicationUri: {0} --> {1}", configuration.ApplicationUri, applicationUri); configuration.ApplicationUri = applicationUri; } Utils.LogInfo("Using the ApplicationUri: {0}", applicationUri); // update configuration. configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; return(true); }
private ServiceResult UpdateCertificate( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, byte[] certificate, byte[][] issuerCertificates, string privateKeyFormat, byte[] privateKey, ref bool applyChangesRequired) { HasApplicationSecureAdminAccess(context); if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } privateKeyFormat = privateKeyFormat?.ToUpper(); if (!(String.IsNullOrEmpty(privateKeyFormat) || privateKeyFormat == "PEM" || privateKeyFormat == "PFX")) { throw new ServiceResultException(StatusCodes.BadNotSupported, "The private key format is not supported."); } ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); certificateGroup.UpdateCertificate = null; X509Certificate2Collection newIssuerCollection = new X509Certificate2Collection(); X509Certificate2 newCert; try { // build issuer chain if (issuerCertificates != null) { foreach (byte[] issuerRawCert in issuerCertificates) { var newIssuerCert = new X509Certificate2(issuerRawCert); newIssuerCollection.Add(newIssuerCert); } } newCert = new X509Certificate2(certificate); } catch { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate data is invalid."); } // validate new subject matches the previous subject if (!X509Utils.CompareDistinguishedName(certificateGroup.ApplicationCertificate.SubjectName, newCert.SubjectName.Name)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application."); } // self signed bool selfSigned = X509Utils.CompareDistinguishedName(newCert.Subject, newCert.Issuer); if (selfSigned && newIssuerCollection.Count != 0) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer list not empty for self signed certificate."); } if (!selfSigned) { try { // verify cert with issuer chain CertificateValidator certValidator = new CertificateValidator(); CertificateTrustList issuerStore = new CertificateTrustList(); CertificateIdentifierCollection issuerCollection = new CertificateIdentifierCollection(); foreach (var issuerCert in newIssuerCollection) { issuerCollection.Add(new CertificateIdentifier(issuerCert)); } issuerStore.TrustedCertificates = issuerCollection; certValidator.Update(issuerStore, issuerStore, null); certValidator.Validate(newCert); } catch { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list."); } } var updateCertificate = new UpdateCertificateData(); try { var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; switch (privateKeyFormat) { case null: case "": { X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PFX": { X509Certificate2 certWithPrivateKey = X509Utils.CreateCertificateFromPKCS12(privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PEM": { updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPEMPrivateKey(newCert, privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); break; } } updateCertificate.IssuerCollection = newIssuerCollection; updateCertificate.SessionId = context.SessionId; } catch { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the private key."); } certificateGroup.UpdateCertificate = updateCertificate; applyChangesRequired = true; if (updateCertificate != null) { try { using (ICertificateStore appStore = certificateGroup.ApplicationCertificate.OpenStore()) { Utils.LogCertificate(Utils.TraceMasks.Security, "Delete application certificate: ", certificateGroup.ApplicationCertificate.Certificate); appStore.Delete(certificateGroup.ApplicationCertificate.Thumbprint).Wait(); Utils.LogCertificate(Utils.TraceMasks.Security, "Add new application certificate: ", updateCertificate.CertificateWithPrivateKey); var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; appStore.Add(updateCertificate.CertificateWithPrivateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)).Wait(); // keep only track of cert without private key var certOnly = new X509Certificate2(updateCertificate.CertificateWithPrivateKey.RawData); updateCertificate.CertificateWithPrivateKey.Dispose(); updateCertificate.CertificateWithPrivateKey = certOnly; } using (ICertificateStore issuerStore = CertificateStoreIdentifier.OpenStore(certificateGroup.IssuerStorePath)) { foreach (var issuer in updateCertificate.IssuerCollection) { try { Utils.LogCertificate(Utils.TraceMasks.Security, "Add new issuer certificate: ", issuer); issuerStore.Add(issuer).Wait(); } catch (ArgumentException) { // ignore error if issuer cert already exists } } } } catch (Exception ex) { Utils.LogError(Utils.TraceMasks.Security, ServiceResult.BuildExceptionTrace(ex)); throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to update certificate.", ex); } } return(ServiceResult.Good); }
public static void VerifySignedApplicationCert(ApplicationTestData testApp, byte[] rawSignedCert, byte[][] rawIssuerCerts) { X509Certificate2 signedCert = new X509Certificate2(rawSignedCert); X509Certificate2 issuerCert = new X509Certificate2(rawIssuerCerts[0]); TestContext.Out.WriteLine($"Signed cert: {signedCert}"); TestContext.Out.WriteLine($"Issuer cert: {issuerCert}"); Assert.NotNull(signedCert); Assert.False(signedCert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(testApp.Subject, signedCert.Subject)); Assert.False(X509Utils.CompareDistinguishedName(signedCert.Issuer, signedCert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(signedCert.Issuer, issuerCert.Subject)); TestContext.Out.WriteLine($"Signed Subject: {signedCert.Subject}"); TestContext.Out.WriteLine($"Issuer Subject: {issuerCert.Subject}"); // test basic constraints X509BasicConstraintsExtension constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(signedCert); Assert.NotNull(constraints); TestContext.Out.WriteLine($"Constraints: {constraints.Format(true)}"); Assert.True(constraints.Critical); Assert.False(constraints.CertificateAuthority); Assert.False(constraints.HasPathLengthConstraint); // key usage X509KeyUsageExtension keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(signedCert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine($"KeyUsage: {keyUsage.Format(true)}"); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == X509KeyUsageFlags.DataEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DecipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == X509KeyUsageFlags.DigitalSignature); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.EncipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == X509KeyUsageFlags.NonRepudiation); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(signedCert); Assert.NotNull(enhancedKeyUsage); TestContext.Out.WriteLine($"Enhanced Key Usage: {enhancedKeyUsage.Format(true)}"); Assert.True(enhancedKeyUsage.Critical); // test for authority key X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(signedCert); Assert.NotNull(authority); TestContext.Out.WriteLine($"Authority Key Identifier: {authority.Format(true)}"); Assert.NotNull(authority.SerialNumber); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(issuerCert); TestContext.Out.WriteLine($"Issuer Subject Key Identifier: {subjectKeyId}"); Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); Assert.AreEqual(issuerCert.SerialNumber, authority.SerialNumber); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(signedCert); Assert.NotNull(subjectAlternateName); TestContext.Out.WriteLine($"Issuer Subject Alternate Name: {subjectAlternateName}"); Assert.False(subjectAlternateName.Critical); var domainNames = X509Utils.GetDomainsFromCertficate(signedCert); foreach (var domainName in testApp.DomainNames) { Assert.True(domainNames.Contains(domainName, StringComparer.OrdinalIgnoreCase)); } Assert.True(subjectAlternateName.Uris.Count == 1); var applicationUri = X509Utils.GetApplicationUriFromCertificate(signedCert); Assert.True(testApp.ApplicationRecord.ApplicationUri == applicationUri); }
private ServiceResult RemoveCertificate( ISystemContext context, MethodState method, NodeId objectId, string thumbprint, bool isTrustedCertificate) { HasSecureWriteAccess(context); lock (m_lock) { if (m_sessionId != null) { return(StatusCodes.BadInvalidState); } if (String.IsNullOrEmpty(thumbprint)) { return(StatusCodes.BadInvalidArgument); } using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(isTrustedCertificate ? m_trustedStorePath : m_issuerStorePath)) { var certCollection = store.FindByThumbprint(thumbprint).Result; if (certCollection.Count == 0) { return(StatusCodes.BadInvalidArgument); } // delete all CRLs signed by cert var crlsToDelete = new List <X509CRL>(); foreach (var crl in store.EnumerateCRLs()) { foreach (var cert in certCollection) { if (X509Utils.CompareDistinguishedName(cert.Subject, crl.Issuer) && crl.VerifySignature(cert, false)) { crlsToDelete.Add(crl); break; } } } if (!store.Delete(thumbprint).Result) { return(StatusCodes.BadInvalidArgument); } foreach (var crl in crlsToDelete) { if (!store.DeleteCRL(crl)) { // intentionally ignore errors, try best effort Utils.Trace("RemoveCertificate: Failed to delete CRL {0}.", crl.ToString()); } } } m_node.LastUpdateTime.Value = DateTime.UtcNow; } return(ServiceResult.Good); }
public async Task VerifyAppCertDirectoryStore() { var appCertificate = GetTestCert(); Assert.NotNull(appCertificate); Assert.True(appCertificate.HasPrivateKey); string password = Guid.NewGuid().ToString(); // pki directory root for app cert var pkiRoot = Path.GetTempPath() + Path.GetRandomFileName() + Path.DirectorySeparatorChar; var storePath = pkiRoot + "own"; var storeType = CertificateStoreType.Directory; appCertificate.AddToStore( storeType, storePath, password ); using (var publicKey = new X509Certificate2(appCertificate.RawData)) { Assert.NotNull(publicKey); Assert.False(publicKey.HasPrivateKey); var id = new CertificateIdentifier() { Thumbprint = publicKey.Thumbprint, StorePath = storePath, StoreType = storeType }; { // check no password fails to load var nullKey = await id.LoadPrivateKey(null).ConfigureAwait(false); Assert.IsNull(nullKey); } { // check invalid password fails to load var nullKey = await id.LoadPrivateKey("123").ConfigureAwait(false); Assert.IsNull(nullKey); } { // check invalid password fails to load var nullKey = await id.LoadPrivateKeyEx(new CertificatePasswordProvider("123")).ConfigureAwait(false); Assert.IsNull(nullKey); } var privateKey = await id.LoadPrivateKeyEx(new CertificatePasswordProvider(password)).ConfigureAwait(false); Assert.NotNull(privateKey); Assert.True(privateKey.HasPrivateKey); X509Utils.VerifyRSAKeyPair(publicKey, privateKey, true); using (ICertificateStore store = Opc.Ua.CertificateStoreIdentifier.CreateStore(storeType)) { store.Open(storePath); await store.Delete(publicKey.Thumbprint).ConfigureAwait(false); } } }