diff --git a/SampleApplications/Samples/Client.Net4/Opc.Ua.SampleClient.Config.xml b/SampleApplications/Samples/Client.Net4/Opc.Ua.SampleClient.Config.xml index e773694e93..3f366d10d6 100644 --- a/SampleApplications/Samples/Client.Net4/Opc.Ua.SampleClient.Config.xml +++ b/SampleApplications/Samples/Client.Net4/Opc.Ua.SampleClient.Config.xml @@ -21,18 +21,9 @@ - - - - Directory - - - %CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault - + + X509Store + CurrentUser\UA_MachineDefault - Opc.Ua.SampleClient - - - urn:localhost:OPCFoundation:SampleClient - - - http://opcfoundation.org/UA/SampleClient/ - - - ClientAndServer_2 - - - - - - - - - Directory - - - %LocalFolder%\OPC Foundation\CertificateStores\MachineDefault - - - - Opc.Ua.SampleClient - - - - - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\UA Applications - - - - 32 - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates - - - - - - - - - - - 120000 - - - 1048576 - - - 4194304 - - - 65535 - - - 4194304 - - - 65535 - - - 300000 - - - 3600000 - - - - - - - - - opc.tcp://localhost:61210/UA/SampleClient - - - - - - - - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 - 4 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - 2 - - - None_1 - http://opcfoundation.org/UA/SecurityPolicy#None - 0 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 - 1 - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - 5 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 - 3 - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 - 6 - - - - 5 - 100 - 2000 - - - - - - Anonymous_0 - http://opcfoundation.org/UA/SecurityPolicy#None - - - - - UserName_1 - - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - - - - - Certificate_2 - - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - - - - - - true - - - 100 - - - 10000 - - - 3600000 - - - 10 - - - 10 - - - 100 - - - 600000 - - - 100 - - - 3600000 - - - 100 - - - 3600000 - - - 100 - - - 100 - - - 1000 - - - 1000 - - - - - - - - opc.tcp://localhost:4840 - - opc.tcp://localhost:4840 - DiscoveryServer_3 - - opc.tcp://localhost:4840 - - - SignAndEncrypt_3 - - - 1 - - - - 0 - - - Opc.Ua.Server.nodes.xml - - - 10000 - - - - - - - 600000 - - - - opc.tcp://{0}:4840/UADiscovery - http://{0}:52601/UADiscovery - http://{0}/UADiscovery/Default.svc - - - - - - - Opc.Ua.SampleClient.Endpoints.xml - - - 10000 - - - - - - - - - UInt32 - 100 - UInt32 - - - Double - 100 - Double - - - - - - - - - - %LocalFolder%\Logs\Opc.Ua.SampleClient.log.txt - true - - - - 513 - - - - - - - - - - - - - true - + + + + Opc.Ua.SampleClient + + + urn:localhost:OPCFoundation:SampleClient + + + http://opcfoundation.org/UA/SampleClient/ + + + ClientAndServer_2 + + + + + + + X509Store + CurrentUser\UA_MachineDefault + + + Opc.Ua.SampleClient + + + + + + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities + + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\UA Applications + + + + 32 + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates + + + + + + + + + + + 120000 + + + 1048576 + + + 4194304 + + + 65535 + + + 4194304 + + + 65535 + + + 300000 + + + 3600000 + + + + + + + + + opc.tcp://localhost:61210/UA/SampleClient + + + + + + + + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 + 4 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + 2 + + + None_1 + http://opcfoundation.org/UA/SecurityPolicy#None + 0 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 + 1 + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + 5 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 + 3 + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 + 6 + + + + 5 + 100 + 2000 + + + + + + Anonymous_0 + http://opcfoundation.org/UA/SecurityPolicy#None + + + + + UserName_1 + + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + + + + + Certificate_2 + + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + + + + + + true + + + 100 + + + 10000 + + + 3600000 + + + 10 + + + 10 + + + 100 + + + 600000 + + + 100 + + + 3600000 + + + 100 + + + 3600000 + + + 100 + + + 100 + + + 1000 + + + 1000 + + + + + + + + opc.tcp://localhost:4840 + + opc.tcp://localhost:4840 + DiscoveryServer_3 + + opc.tcp://localhost:4840 + + + SignAndEncrypt_3 + + + 1 + + + + 0 + + + Opc.Ua.Server.nodes.xml + + + 10000 + + + + + + + 600000 + + + + opc.tcp://{0}:4840/UADiscovery + http://{0}:52601/UADiscovery + http://{0}/UADiscovery/Default.svc + + + + + + + Opc.Ua.SampleClient.Endpoints.xml + + + 10000 + + + + + + + + + UInt32 + 100 + UInt32 + + + Double + 100 + Double + + + + + + + + + + %LocalFolder%\Logs\Opc.Ua.SampleClient.log.txt + true + + + + 513 + + + + + + + + + + + + + true + \ No newline at end of file diff --git a/SampleApplications/Samples/NetCoreConsoleClient/Program.cs b/SampleApplications/Samples/NetCoreConsoleClient/Program.cs index 0a0c4924aa..c7158523cf 100644 --- a/SampleApplications/Samples/NetCoreConsoleClient/Program.cs +++ b/SampleApplications/Samples/NetCoreConsoleClient/Program.cs @@ -57,8 +57,8 @@ namespace NetCoreConsoleClient { ApplicationCertificate = new CertificateIdentifier { - StoreType = "Directory", - StorePath = "OPC Foundation/CertificateStores/MachineDefault", + StoreType = "X509Store", + StorePath = "CurrentUser\\UA_MachineDefault", SubjectName = "UA Core Sample Client" }, TrustedPeerCertificates = new CertificateTrustList diff --git a/SampleApplications/Samples/NetCoreConsoleServer/Opc.Ua.SampleServer.Config.xml b/SampleApplications/Samples/NetCoreConsoleServer/Opc.Ua.SampleServer.Config.xml index b9a718fa58..cbd12c059c 100644 --- a/SampleApplications/Samples/NetCoreConsoleServer/Opc.Ua.SampleServer.Config.xml +++ b/SampleApplications/Samples/NetCoreConsoleServer/Opc.Ua.SampleServer.Config.xml @@ -20,20 +20,20 @@ - X509Store - CurrentUser\UA_Certificate_Authorities + Directory + OPC Foundation/CertificateStores//UA Certificate Authorities - X509Store - CurrentUser\UA_Applications + Directory + OPC Foundation/CertificateStores/UA Applications - X509Store - CurrentUser\UA_RejectedCertificates + Directory + OPC Foundation/CertificateStores/RejectedCertificates - Directory - %CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault + X509Store + CurrentUser\UA_MachineDefault UA Sample Server diff --git a/SampleApplications/Samples/Server/Opc.Ua.SampleServer.Config.xml b/SampleApplications/Samples/Server/Opc.Ua.SampleServer.Config.xml index 7a6f7a8256..5a83c82143 100644 --- a/SampleApplications/Samples/Server/Opc.Ua.SampleServer.Config.xml +++ b/SampleApplications/Samples/Server/Opc.Ua.SampleServer.Config.xml @@ -1,208 +1,208 @@ - - - Opc.Ua.SampleServer - urn:localhost:OPCFoundation:SampleServer - http://opcfoundation.org/UA/SampleServer - Server_0 - - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\MachineDefault - Opc.Ua.SampleServer - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\UA Applications - - - - - Directory - %LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates - - - - - - - - - 600000 - 1048576 - 4194304 - 65535 - 4194304 - 65535 - 300000 - 3600000 - - - - - opc.tcp://localhost:51210/UA/SampleServer - - - - - - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 - 4 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - 2 - - - None_1 - http://opcfoundation.org/UA/SecurityPolicy#None - 0 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 - 1 - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - 5 - - - Sign_2 - http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 - 3 - - - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 - 6 - - - - 5 - 100 - 2000 - - - - - - Anonymous_0 - http://opcfoundation.org/UA/SecurityPolicy#None - - - - - UserName_1 - - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - - - - - Certificate_2 - - http://opcfoundation.org/UA/SecurityPolicy#Basic256 - - - - true - 100 - 10000 - 3600000 - 10 - 10 - 100 - 600000 - 100 - 3600000 - 50 - 3600000 - 100 - 100 - 1000 - 1000 - - 0 - Opc.Ua.Server.nodes.xml - - - - - - - - UInt32 - 100 - UInt32 - - - Double - 100 - Double - - - - - - - - %LocalFolder%\Logs\Opc.Ua.SampleServer.log.txt - true - - - - 513 - - - - - - - - - - - - true - + + + Opc.Ua.SampleServer + urn:localhost:OPCFoundation:SampleServer + http://opcfoundation.org/UA/SampleServer + Server_0 + + + + + + X509Store + CurrentUser\UA_MachineDefault + Opc.Ua.SampleServer + + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities + + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\UA Applications + + + + + Directory + %LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates + + + + + + + + + 600000 + 1048576 + 4194304 + 65535 + 4194304 + 65535 + 300000 + 3600000 + + + + + opc.tcp://localhost:51210/UA/SampleServer + + + + + + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 + 4 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + 2 + + + None_1 + http://opcfoundation.org/UA/SecurityPolicy#None + 0 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 + 1 + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + 5 + + + Sign_2 + http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 + 3 + + + SignAndEncrypt_3 + http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 + 6 + + + + 5 + 100 + 2000 + + + + + + Anonymous_0 + http://opcfoundation.org/UA/SecurityPolicy#None + + + + + UserName_1 + + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + + + + + Certificate_2 + + http://opcfoundation.org/UA/SecurityPolicy#Basic256 + + + + true + 100 + 10000 + 3600000 + 10 + 10 + 100 + 600000 + 100 + 3600000 + 50 + 3600000 + 100 + 100 + 1000 + 1000 + + 0 + Opc.Ua.Server.nodes.xml + + + + + + + + UInt32 + 100 + UInt32 + + + Double + 100 + Double + + + + + + + + %LocalFolder%\Logs\Opc.Ua.SampleServer.log.txt + true + + + + 513 + + + + + + + + + + + + true + \ No newline at end of file diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs index 0d2219e168..9958b14a5b 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs @@ -718,6 +718,38 @@ namespace Opc.Ua { return StatusCodes.BadNotSupported; } + + /// + /// Returns the CRLs in the store. + /// + public List EnumerateCRLs() + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } + + /// + /// Returns the CRLs for the issuer. + /// + public List EnumerateCRLs(X509Certificate2 issuer) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } + + /// + /// Adds a CRL to the store. + /// + public void AddCRL(X509CRL crl) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } + + /// + /// Removes a CRL from the store. + /// + public bool DeleteCRL(X509CRL crl) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } #endregion } #endregion diff --git a/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs b/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs index 9f6b6f4dd9..44adee556b 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs @@ -379,9 +379,154 @@ namespace Opc.Ua // can't find a valid CRL. return StatusCodes.BadCertificateRevocationUnknown; } -#endregion -#region Private Methods + /// + /// Returns the CRLs in the store. + /// + public List EnumerateCRLs() + { + List crls = new List(); + + // check for CRL. + DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + Path.DirectorySeparatorChar + "crl"); + + if (info.Exists) + { + foreach (FileInfo file in info.GetFiles("*.crl")) + { + X509CRL crl = new X509CRL(file.FullName); + crls.Add(crl); + } + } + + return crls; + } + + /// + /// Returns the CRLs for the issuer. + /// + public List EnumerateCRLs(X509Certificate2 issuer) + { + if (issuer == null) + { + throw new ArgumentNullException("issuer"); + } + + List crls = new List(); + + // check for CRL. + DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + Path.DirectorySeparatorChar + "crl"); + + if (info.Exists) + { + foreach (FileInfo file in info.GetFiles("*.crl")) + { + X509CRL crl = new X509CRL(file.FullName); + + if (!Utils.CompareDistinguishedName(crl.Issuer, issuer.Subject)) + { + continue; + } + + if (!crl.VerifySignature(issuer, false)) + { + continue; + } + + if (crl.UpdateTime <= DateTime.UtcNow && (crl.NextUpdateTime == DateTime.MinValue || crl.NextUpdateTime >= DateTime.UtcNow)) + { + crls.Add(crl); + } + } + } + + return crls; + } + + /// + /// Adds a CRL to the store. + /// + public void AddCRL(X509CRL crl) + { + if (crl == null) + { + throw new ArgumentNullException("crl"); + } + + X509Certificate2 issuer = null; + X509Certificate2Collection certificates = null; + certificates = Enumerate().Result; + foreach (X509Certificate2 certificate in certificates) + { + if (Utils.CompareDistinguishedName(certificate.Subject, crl.Issuer)) + { + if (crl.VerifySignature(certificate, false)) + { + issuer = certificate; + break; + } + } + } + + if (issuer == null) + { + throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Could not find issuer of the CRL."); + } + + StringBuilder builder = new StringBuilder(); + builder.Append(m_directory.FullName); + + builder.Append(Path.DirectorySeparatorChar + "crl" + Path.DirectorySeparatorChar); + builder.Append(GetFileName(issuer)); + builder.Append(".crl"); + + FileInfo fileInfo = new FileInfo(builder.ToString()); + + if (!fileInfo.Directory.Exists) + { + fileInfo.Directory.Create(); + } + + File.WriteAllBytes(fileInfo.FullName, crl.RawData); + } + + /// + /// Removes a CRL from the store. + /// + public bool DeleteCRL(X509CRL crl) + { + if (crl == null) + { + throw new ArgumentNullException("crl"); + } + + string filePath = m_directory.FullName; + filePath += Path.DirectorySeparatorChar + "crl"; + + DirectoryInfo dirInfo = new DirectoryInfo(filePath); + + if (dirInfo.Exists) + { + foreach (FileInfo fileInfo in dirInfo.GetFiles("*.crl")) + { + if (fileInfo.Length == crl.RawData.Length) + { + byte[] bytes = File.ReadAllBytes(fileInfo.FullName); + + if (Utils.IsEqual(bytes, crl.RawData)) + { + fileInfo.Delete(); + return true; + } + } + } + } + + return false; + } + #endregion + + #region Private Methods /// /// Reads the current contents of the directory from disk. /// diff --git a/Stack/Opc.Ua.Core/Security/Certificates/ICertificateStore.cs b/Stack/Opc.Ua.Core/Security/Certificates/ICertificateStore.cs index 1cc7bf49e8..eaf4261190 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/ICertificateStore.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/ICertificateStore.cs @@ -11,6 +11,7 @@ */ using System; +using System.Collections.Generic; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -64,5 +65,25 @@ namespace Opc.Ua /// Checks if issuer has revoked the certificate. /// StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate); + + /// + /// Returns the CRLs in the store. + /// + List EnumerateCRLs(); + + /// + /// Returns the CRLs for the issuer. + /// + List EnumerateCRLs(X509Certificate2 issuer); + + /// + /// Adds a CRL to the store. + /// + void AddCRL(X509CRL crl); + + /// + /// Removes a CRL from the store. + /// + bool DeleteCRL(X509CRL crl); }; } diff --git a/Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore.cs b/Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore.cs index 72b60024ea..0dedf9820a 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore.cs @@ -31,7 +31,7 @@ namespace Opc.Ua { m_store = null; } - + public void Dispose() { Dispose(true); @@ -39,7 +39,6 @@ namespace Opc.Ua protected virtual void Dispose(bool disposing) { - // clean up managed resources. if (disposing) { Close(); @@ -47,12 +46,12 @@ namespace Opc.Ua } /// - /// - /// Syntax: StoreLocation\StoreName - /// Examples: - /// LocalMachine\My - /// CurrentUser\Trust - /// + /// + /// Syntax: StoreLocation\StoreName + /// Examples: + /// LocalMachine\My + /// CurrentUser\Trust + /// public void Open(string path) { if (path == null) throw new ArgumentNullException("path"); @@ -101,7 +100,6 @@ namespace Opc.Ua m_store.Open(OpenFlags.ReadWrite); } - /// public void Close() { if (m_store != null) @@ -111,7 +109,6 @@ namespace Opc.Ua } } - /// public Task Enumerate() { if (m_store == null) @@ -123,9 +120,9 @@ namespace Opc.Ua certificates.AddRange(m_store.Certificates); - return Task.FromResult(certificates); + return Task.FromResult(certificates); } - + /// public Task Add(X509Certificate2 certificate) { @@ -145,7 +142,6 @@ namespace Opc.Ua return Task.CompletedTask; } - /// public Task Delete(string thumbprint) { if (m_store == null) @@ -160,11 +156,10 @@ namespace Opc.Ua m_store.Certificates.Remove(certificate); } } - - return Task.FromResult(true); + + return Task.FromResult(true); } - - /// + public Task FindByThumbprint(string thumbprint) { if (m_store == null) @@ -181,76 +176,33 @@ namespace Opc.Ua collection.Add(certificate); } } - + return Task.FromResult(collection); } - - /// - /// Checks if issuer has revoked the certificate. - /// + public StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate) { - if (issuer == null) - { - throw new ArgumentNullException("issuer"); - } + throw new ServiceResultException(StatusCodes.BadNotSupported); + } - if (certificate == null) - { - throw new ArgumentNullException("certificate"); - } + public List EnumerateCRLs() + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } - // check for CRL. - DirectoryInfo info = new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "crl"); + public List EnumerateCRLs(X509Certificate2 issuer) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } - if (info.Exists) - { - bool crlExpired = true; + public void AddCRL(X509CRL crl) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); + } - 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; + public bool DeleteCRL(X509CRL crl) + { + throw new ServiceResultException(StatusCodes.BadNotSupported); } private X509Store m_store;