Merge pull request #135 from OPCFoundation/develop_erichb

Added X509 cert store and removed unused code from all stores (not even GDS was using it).
This commit is contained in:
Erich Barnstedt
2017-02-16 19:23:27 +01:00
committed by GitHub
21 changed files with 903 additions and 1485 deletions
@@ -720,9 +720,6 @@ namespace Opc.Ua.Configuration
}
}
// configure access to the executable, the configuration file and the private key.
await ConfigureFileAccess(configuration);
// update configuration file.
ConfigUtils.UpdateConfigurationLocation(InstallConfig.ExecutableFile, InstallConfig.ConfigurationFile);
@@ -1513,124 +1510,6 @@ namespace Opc.Ua.Configuration
Utils.Trace(e, "Could not add certificate to trusted peer store. StorePath={0}", storePath);
}
}
/// <summary>
/// Gets the access rules to use for the application.
/// </summary>
private List<ApplicationAccessRule> GetAccessRules()
{
List<ApplicationAccessRule> rules = new List<ApplicationAccessRule>();
// check for rules specified in the installer configuration.
bool hasAdmin = false;
if (InstallConfig.AccessRules != null)
{
for (int ii = 0; ii < InstallConfig.AccessRules.Count; ii++)
{
ApplicationAccessRule rule = InstallConfig.AccessRules[ii];
if (rule.Right == ApplicationAccessRight.Configure && rule.RuleType == AccessControlType.Allow)
{
hasAdmin = true;
break;
}
}
rules = InstallConfig.AccessRules;
}
// provide some default rules.
if (rules.Count == 0)
{
// give user run access.
ApplicationAccessRule rule = new ApplicationAccessRule();
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Run;
rule.IdentityName = WellKnownSids.Users;
rules.Add(rule);
// ensure service can access.
if (InstallConfig.InstallAsService)
{
rule = new ApplicationAccessRule();
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Run;
rule.IdentityName = WellKnownSids.NetworkService;
rules.Add(rule);
rule = new ApplicationAccessRule();
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Run;
rule.IdentityName = WellKnownSids.LocalService;
rules.Add(rule);
}
}
// ensure someone can change the configuration later.
if (!hasAdmin)
{
ApplicationAccessRule rule = new ApplicationAccessRule();
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Configure;
rule.IdentityName = WellKnownSids.Administrators;
rules.Add(rule);
}
return rules;
}
/// <summary>
/// Configures access to the executable, the configuration file and the private key.
/// </summary>
private async Task ConfigureFileAccess(ApplicationConfiguration configuration)
{
Utils.Trace(Utils.TraceMasks.Information, "Configuring file access.");
List<ApplicationAccessRule> rules = GetAccessRules();
// apply access rules to the excutable file.
try
{
if (InstallConfig.SetExecutableFilePermissions)
{
ApplicationAccessRule.SetAccessRules(InstallConfig.ExecutableFile, rules, true);
}
}
catch (Exception e)
{
Utils.Trace(e, "Could not set executable file permissions.");
}
// apply access rules to the configuration file.
try
{
if (InstallConfig.SetConfigurationFilePermisions)
{
ApplicationAccessRule.SetAccessRules(configuration.SourceFilePath, rules, true);
}
}
catch (Exception e)
{
Utils.Trace(e, "Could not set configuration file permissions.");
}
// apply access rules to the private key file.
try
{
X509Certificate2 certificate = await configuration.SecurityConfiguration.ApplicationCertificate.Find(true);
if (certificate != null)
{
ICertificateStore store = configuration.SecurityConfiguration.ApplicationCertificate.OpenStore();
store.SetAccessRules(certificate.Thumbprint, rules, true);
}
}
catch (Exception e)
{
Utils.Trace(e, "Could not set private key file permissions.");
}
}
#endregion
#region Private Fields
@@ -21,18 +21,9 @@
<SecurityConfiguration>
<!-- The location of the application instance certificate in the Windows certificate store -->
<ApplicationCertificate>
<!-- The type of store. -->
<StoreType>Directory</StoreType>
<!-- The location of the store.
Windows store must start with LocalMachine, CurrentUser or CurrentService
The name of the store is appended.
Note that the names used in code are difference from what appears in the control panel.
e.g. My == "Personal", Root == "Trusted Root Certification Authorities" -->
<StorePath>%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault</StorePath>
<ApplicationCertificate>
<StoreType>X509Store</StoreType>
<StorePath>CurrentUser\UA_MachineDefault</StorePath>
<!-- The subject for the certificate
Note that subject names are complex structures. The text that appears here is the CommonName component.
@@ -1,438 +1,429 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
schemaLocation="./Schema/ApplicationConfiguration.xsd"
>
<!-- A human readable but not necessarily unique name for the application instance -->
<ApplicationName>Opc.Ua.SampleClient</ApplicationName>
<!-- A globally unique identifier for the application instance.
This is overridden with the value contained in the application certificate. -->
<ApplicationUri>urn:localhost:OPCFoundation:SampleClient</ApplicationUri>
<!-- A globally unique URI for the product (usually assigned by the product vendor) -->
<ProductUri>http://opcfoundation.org/UA/SampleClient/</ProductUri>
<!-- Indicates the type of application (Client, Server or ClientServer). -->
<ApplicationType>ClientAndServer_2</ApplicationType>
<!-- Specifies security related configuration information -->
<SecurityConfiguration>
<!-- The location of the application instance certificate in the Windows certificate store -->
<ApplicationCertificate>
<!-- The type of store. -->
<StoreType>Directory</StoreType>
<!-- The location of the store.
Windows store must start with LocalMachine, CurrentUser or CurrentService
The name of the store is appended.
Note that the names used in code are difference from what appears in the control panel.
e.g. My == "Personal", Root == "Trusted Root Certification Authorities" -->
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\MachineDefault</StorePath>
<!-- The subject for the certificate
Note that subject names are complex structures. The text that appears here is the CommonName component.
A complete distinguished would be something like: 'CN=UA Sample Client, DC=MACHINENAME'
The first certificate found is used if multiple certificates with the same CommonName exist.
The Thumbprint should be specified if the CommonName does not uniquely identify a certificate. -->
<SubjectName>Opc.Ua.SampleClient</SubjectName>
<!-- The SHA1 thumbprint for the certificate.
The thumbprint uniquely identifies a certificate.
It should be specified in this file, however, the samples rely on quick and
dirty scripts to create new certificate on each machine. A commerical application
would generate the initial certificate itself and update the thumbprint accordingly -->
<!--<Thumbprint>3a35fb798fc6dee8a7e7e4652b0e28fc14c6ee0f</Thumbprint>-->
</ApplicationCertificate>
<!-- The list of certification authorities.
Typical web browsing applications trust any certificate issued by a CA in the
"Trusted Root Certification Authorities" certificate store. However, this approach is
not appropriate for UA because Adminstrators have no control over the CAs that get
placed in that Root store to facilitate web browsing. This means Adminstrators must
specify a different store that is used only for UA related CAs and/or they must explicitly
specify the certificate for each trusted certification authority. -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities</StorePath>
</TrustedIssuerCertificates>
<!-- The list of trusted certificates.
Some UA applications will use self-signed certificates (certificates without a CA)
which means that every application which communicates with it must be configured to
trust it.
Adminstrators may designate a certificate store that contains trusted UA application
instance certificates (this store should not be the same as the store used for CAs
certificates). Alternately, Administrators may enter the certificates explicitly in
this list.
Note that entries in this list may either reference a certificate in the store or
may contained the entire certificate encoded as base64 data.
-->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Applications</StorePath>
</TrustedPeerCertificates>
<!-- Applications exchange Nonces during the CreateSession. This value specifies the length. Must be >= 32 -->
<NonceLength>32</NonceLength>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates</StorePath>
</RejectedCertificateStore>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<!-- Specifies quotas used to by the transport layer -->
<TransportQuotas>
<!-- The default timeout in milliseconds for operations (used by clients) -->
<OperationTimeout>120000</OperationTimeout>
<!-- The maximum length for a string value in any message -->
<MaxStringLength>1048576</MaxStringLength>
<!-- The maximum length for a byte string value in any message -->
<MaxByteStringLength>4194304</MaxByteStringLength>
<!-- The maximum length for any array in a message.
Note that some protocols do not distinguish between bytes and arrays.
In these cases the binding will choose the larger of
MaxByteStringLength or MaxArrayLength-->
<MaxArrayLength>65535</MaxArrayLength>
<!-- The maximum size of any message -->
<MaxMessageSize>4194304</MaxMessageSize>
<!-- The maximum buffer size
This value controls how big a block of memory the transport layer allocates.
Setting this value to a large value will reduce performance and use a lot of RAM -->
<MaxBufferSize>65535</MaxBufferSize>
<!-- The lifetime of a SecureChannel in milliseconds.
This specifies how long the server will keep a broken channel around while waiting
for a client to reconnect.
Not used by HTTP or .NET TCP bindings -->
<ChannelLifetime>300000</ChannelLifetime>
<!-- The lifetime of a SecurityToken in milliseconds.
This specifies how long a security token can be used without renewal. -->
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<!-- This element only needs to be specified for Server or ClientServer applications -->
<ServerConfiguration>
<!-- The set of addresses. One for each supported protocol.
Note that "localhost" is replace with the hostname when the configuration is loaded.
Additional URLs are created by appending strings to the base address.
For example, a URL used for an endpoint which uses the Basic256 security policy would look like this:
http://localhost:61211/UA/SampleClient/Basic256 -->
<BaseAddresses>
<ua:String>opc.tcp://localhost:61210/UA/SampleClient</ua:String>
</BaseAddresses>
<!--
These list the alternate addresses (via firewalls, multiple NICs etc.) that can be
used to communicate with the server. The URL used by the client when calling
FindServers/GetEndpoints or CreateSession will be used to filter the list of
endpoints returned by checking for alternate base addresses that have a domain
that matches the domain in the url provided by the client.
Note that any additional domains should be listed in the server's certificate. If they
are left out the client make refuse to connect because it has no way to know if the
alternate domain was authorized by the server administrator.
-->
<!--
<AlternateBaseAddresses>
<ua:String>http://mycompany.com:40000/UA/SampleClient</ua:String>
</AlternateBaseAddresses>
-->
<!-- The security policies supported by the server.
The SDK combines these with the base address to create as many EndpointDescriptions as required.
Protocols such as HTTP only allow one SecurityPolicy per endpoint to addition URLs are constructed
using the SecurityPolicy and SecurityMode.
The first policy in the list is assigned to base address. -->
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>4</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>2</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</SecurityPolicyUri>
<SecurityLevel>0</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>1</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>5</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>3</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>6</SecurityLevel>
</ServerSecurityPolicy>
</SecurityPolicies>
<MinRequestThreadCount>5</MinRequestThreadCount>
<MaxRequestThreadCount>100</MaxRequestThreadCount>
<MaxQueuedRequestCount>2000</MaxQueuedRequestCount>
<!-- The SDK expects the server to support the same set of user tokens for every endpoint. -->
<UserTokenPolicies>
<!-- Allows anonymous users -->
<ua:UserTokenPolicy>
<ua:TokenType>Anonymous_0</ua:TokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows username/password -->
<ua:UserTokenPolicy>
<ua:TokenType>UserName_1</ua:TokenType>
<!-- passwords must be encrypted - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows user certificates -->
<ua:UserTokenPolicy>
<ua:TokenType>Certificate_2</ua:TokenType>
<!-- certificate possession must be proven with a digital signature - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!--
Issued tokens are any type of WS-Security compliant token
This is a URN assigned by OASIS to SAML Security Tokens
tokens must be encrypted - this specifies what algorithm to use
<ua:UserTokenPolicy>
<ua:TokenType>IssuedToken_3</ua:TokenType>
<ua:IssuedTokenType>urn:oasis:names:tc:SAML:1.0:assertion:Assertion</ua:IssuedTokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
-->
</UserTokenPolicies>
<!-- Whether the server updates its diagnostic information -->
<DiagnosticsEnabled>true</DiagnosticsEnabled>
<!-- The maximum number of simultaneous sessions -->
<MaxSessionCount>100</MaxSessionCount>
<!-- The minimum session lifetime permitted by the server -->
<MinSessionTimeout>10000</MinSessionTimeout>
<!-- The maximum session lifetime permitted by the server -->
<MaxSessionTimeout>3600000</MaxSessionTimeout>
<!-- The maximum number of browse continuation points per session -->
<MaxBrowseContinuationPoints>10</MaxBrowseContinuationPoints>
<!-- The maximum number of query continuation points per session -->
<MaxQueryContinuationPoints>10</MaxQueryContinuationPoints>
<!-- The maximum number of history continuation points per session -->
<MaxHistoryContinuationPoints>100</MaxHistoryContinuationPoints>
<!-- The maximum age of an incoming request -->
<MaxRequestAge>600000</MaxRequestAge>
<!-- The minimum allowed publishing interval (in milliseconds) -->
<MinPublishingInterval>100</MinPublishingInterval>
<!-- The maximum allowed publishing interval (in milliseconds) -->
<MaxPublishingInterval>3600000</MaxPublishingInterval>
<!-- The publishing resolution. Requested publishing intervals are rounded up to the next multiple of this value.-->
<PublishingResolution>100</PublishingResolution>
<!-- The maximum subscription lifetime.
This controls the maximum keep alive count. Smaller publishing intervals will allow large keep alives
provided the maximum subscription lifetime is not exceeded -->
<MaxSubscriptionLifetime>3600000</MaxSubscriptionLifetime>
<!-- The maximum number of sent messages kept in the queue for each subscription-->
<MaxMessageQueueSize>100</MaxMessageQueueSize>
<!-- The maximum number of notifications kept in the queue for each monitored item-->
<MaxNotificationQueueSize>100</MaxNotificationQueueSize>
<!-- The maximum number of notifications in a single publish response -->
<MaxNotificationsPerPublish>1000</MaxNotificationsPerPublish>
<!-- The minimum sampling rate for rarely changing metadata information (such as the server status) -->
<MinMetadataSamplingInterval>1000</MinMetadataSamplingInterval>
<!-- The set of supported sampling rates -->
<AvailableSamplingRates />
<!-- Servers must create a secure channel with the DiscoveryServer
This element specifies the connection information.
Note that server will use the discovery endpoint to update this information -->
<RegistrationEndpoint>
<ua:EndpointUrl>opc.tcp://localhost:4840</ua:EndpointUrl>
<ua:Server>
<ua:ApplicationUri>opc.tcp://localhost:4840</ua:ApplicationUri>
<ua:ApplicationType>DiscoveryServer_3</ua:ApplicationType>
<ua:DiscoveryUrls>
<ua:String>opc.tcp://localhost:4840</ua:String>
</ua:DiscoveryUrls>
</ua:Server>
<ua:SecurityMode>SignAndEncrypt_3</ua:SecurityMode>
<ua:SecurityPolicyUri />
<ua:UserIdentityTokens />
<ua:SecurityLevel>1</ua:SecurityLevel>
</RegistrationEndpoint>
<!-- The maximum interval between registration. 0 disables periodic registration -->
<MaxRegistrationInterval>0</MaxRegistrationInterval>
<!-- The file used to save nodes added to the CoreNodeManager. If missing the CoreNodeManger will discard nodes when it stops. -->
<NodeManagerSaveFile>Opc.Ua.Server.nodes.xml</NodeManagerSaveFile>
<!-- The minimum subscription lifetime.
This ensures subscriptions are not set to expire too quickly. The revised lifetime count
and keep alive count are calculated with this value. -->
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
</ServerConfiguration>
<!-- This element is only required for Client and ClientServer applications -->
<ClientConfiguration>
<!-- The default timeout for new sessions -->
<DefaultSessionTimeout>600000</DefaultSessionTimeout>
<!-- The well-known URLs for the local discovery servers
URLs are tested in the order they appear in this list. -->
<WellKnownDiscoveryUrls>
<ua:String>opc.tcp://{0}:4840/UADiscovery</ua:String>
<ua:String>http://{0}:52601/UADiscovery</ua:String>
<ua:String>http://{0}/UADiscovery/Default.svc</ua:String>
</WellKnownDiscoveryUrls>
<!-- EndpointDescriptions for system wide discovery servers -->
<DiscoveryServers></DiscoveryServers>
<!-- The file used to save the EndpointDescriptions for servers known to the Client -->
<EndpointCacheFilePath>Opc.Ua.SampleClient.Endpoints.xml</EndpointCacheFilePath>
<!-- The minimum subscription lifetime.
This ensures subscriptions are not set to expire too quickly. The requesed lifetime count
and keep alive count are calculated using this value and the request publishing interval -->
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
</ClientConfiguration>
<Extensions>
<ua:XmlElement>
<MemoryBufferConfiguration xmlns="http://samples.org/UA/memorybuffer">
<Buffers>
<MemoryBufferInstance>
<Name>UInt32</Name>
<TagCount>100</TagCount>
<DataType>UInt32</DataType>
</MemoryBufferInstance>
<MemoryBufferInstance>
<Name>Double</Name>
<TagCount>100</TagCount>
<DataType>Double</DataType>
</MemoryBufferInstance>
</Buffers>
</MemoryBufferConfiguration>
</ua:XmlElement>
</Extensions>
<!--
Masks supported by the trace feature.
Servers will detect changes within 5 seconds.
Do not output any messages.
None = 0x0;
Output error messages.
Error = 0x1;
Output informational messages.
Information = 0x2;
Output stack traces.
StackTrace = 0x4;
Output basic messages for service calls.
Service = 0x8;
Output detailed messages for service calls.
ServiceDetail = 0x10;
Output basic messages for each operation.
Operation = 0x20;
Output detailed messages for each operation.
OperationDetail = 0x40;
Output messages related to application initialization or shutdown
StartStop = 0x80;
Output messages related to a call to an external system.
ExternalSystem = 0x100;
Output messages related to security
Security = 0x200;
-->
<TraceConfiguration>
<OutputFilePath>%LocalFolder%\Logs\Opc.Ua.SampleClient.log.txt</OutputFilePath>
<DeleteOnLoad>true</DeleteOnLoad>
<!-- Show Only Errors -->
<!-- <TraceMasks>1</TraceMasks> -->
<!-- Show Only Security and Errors -->
<TraceMasks>513</TraceMasks>
<!-- Show Only Security, Errors and Trace -->
<!-- <TraceMasks>515</TraceMasks> -->
<!-- Show Only Security, COM Calls, Errors and Trace -->
<!-- <TraceMasks>771</TraceMasks> -->
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
</TraceConfiguration>
<!-- Enables the hi-res clock for the process to allows for shorter (<100ms) publishing and sampling intervals. -->
<!-- QueryPerformanceCounter does not work on all multi-core machines so enabling the hi-res clock by default is not recommended. -->
<DisableHiResClock>true</DisableHiResClock>
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
schemaLocation="./Schema/ApplicationConfiguration.xsd"
>
<!-- A human readable but not necessarily unique name for the application instance -->
<ApplicationName>Opc.Ua.SampleClient</ApplicationName>
<!-- A globally unique identifier for the application instance.
This is overridden with the value contained in the application certificate. -->
<ApplicationUri>urn:localhost:OPCFoundation:SampleClient</ApplicationUri>
<!-- A globally unique URI for the product (usually assigned by the product vendor) -->
<ProductUri>http://opcfoundation.org/UA/SampleClient/</ProductUri>
<!-- Indicates the type of application (Client, Server or ClientServer). -->
<ApplicationType>ClientAndServer_2</ApplicationType>
<!-- Specifies security related configuration information -->
<SecurityConfiguration>
<!-- The location of the application instance certificate in the Windows certificate store -->
<ApplicationCertificate>
<StoreType>X509Store</StoreType>
<StorePath>CurrentUser\UA_MachineDefault</StorePath>
<!-- The subject for the certificate
Note that subject names are complex structures. The text that appears here is the CommonName component.
A complete distinguished would be something like: 'CN=UA Sample Client, DC=MACHINENAME'
The first certificate found is used if multiple certificates with the same CommonName exist.
The Thumbprint should be specified if the CommonName does not uniquely identify a certificate. -->
<SubjectName>Opc.Ua.SampleClient</SubjectName>
<!-- The SHA1 thumbprint for the certificate.
The thumbprint uniquely identifies a certificate.
It should be specified in this file, however, the samples rely on quick and
dirty scripts to create new certificate on each machine. A commerical application
would generate the initial certificate itself and update the thumbprint accordingly -->
<!--<Thumbprint>3a35fb798fc6dee8a7e7e4652b0e28fc14c6ee0f</Thumbprint>-->
</ApplicationCertificate>
<!-- The list of certification authorities.
Typical web browsing applications trust any certificate issued by a CA in the
"Trusted Root Certification Authorities" certificate store. However, this approach is
not appropriate for UA because Adminstrators have no control over the CAs that get
placed in that Root store to facilitate web browsing. This means Adminstrators must
specify a different store that is used only for UA related CAs and/or they must explicitly
specify the certificate for each trusted certification authority. -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities</StorePath>
</TrustedIssuerCertificates>
<!-- The list of trusted certificates.
Some UA applications will use self-signed certificates (certificates without a CA)
which means that every application which communicates with it must be configured to
trust it.
Adminstrators may designate a certificate store that contains trusted UA application
instance certificates (this store should not be the same as the store used for CAs
certificates). Alternately, Administrators may enter the certificates explicitly in
this list.
Note that entries in this list may either reference a certificate in the store or
may contained the entire certificate encoded as base64 data.
-->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Applications</StorePath>
</TrustedPeerCertificates>
<!-- Applications exchange Nonces during the CreateSession. This value specifies the length. Must be >= 32 -->
<NonceLength>32</NonceLength>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates</StorePath>
</RejectedCertificateStore>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<!-- Specifies quotas used to by the transport layer -->
<TransportQuotas>
<!-- The default timeout in milliseconds for operations (used by clients) -->
<OperationTimeout>120000</OperationTimeout>
<!-- The maximum length for a string value in any message -->
<MaxStringLength>1048576</MaxStringLength>
<!-- The maximum length for a byte string value in any message -->
<MaxByteStringLength>4194304</MaxByteStringLength>
<!-- The maximum length for any array in a message.
Note that some protocols do not distinguish between bytes and arrays.
In these cases the binding will choose the larger of
MaxByteStringLength or MaxArrayLength-->
<MaxArrayLength>65535</MaxArrayLength>
<!-- The maximum size of any message -->
<MaxMessageSize>4194304</MaxMessageSize>
<!-- The maximum buffer size
This value controls how big a block of memory the transport layer allocates.
Setting this value to a large value will reduce performance and use a lot of RAM -->
<MaxBufferSize>65535</MaxBufferSize>
<!-- The lifetime of a SecureChannel in milliseconds.
This specifies how long the server will keep a broken channel around while waiting
for a client to reconnect.
Not used by HTTP or .NET TCP bindings -->
<ChannelLifetime>300000</ChannelLifetime>
<!-- The lifetime of a SecurityToken in milliseconds.
This specifies how long a security token can be used without renewal. -->
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<!-- This element only needs to be specified for Server or ClientServer applications -->
<ServerConfiguration>
<!-- The set of addresses. One for each supported protocol.
Note that "localhost" is replace with the hostname when the configuration is loaded.
Additional URLs are created by appending strings to the base address.
For example, a URL used for an endpoint which uses the Basic256 security policy would look like this:
http://localhost:61211/UA/SampleClient/Basic256 -->
<BaseAddresses>
<ua:String>opc.tcp://localhost:61210/UA/SampleClient</ua:String>
</BaseAddresses>
<!--
These list the alternate addresses (via firewalls, multiple NICs etc.) that can be
used to communicate with the server. The URL used by the client when calling
FindServers/GetEndpoints or CreateSession will be used to filter the list of
endpoints returned by checking for alternate base addresses that have a domain
that matches the domain in the url provided by the client.
Note that any additional domains should be listed in the server's certificate. If they
are left out the client make refuse to connect because it has no way to know if the
alternate domain was authorized by the server administrator.
-->
<!--
<AlternateBaseAddresses>
<ua:String>http://mycompany.com:40000/UA/SampleClient</ua:String>
</AlternateBaseAddresses>
-->
<!-- The security policies supported by the server.
The SDK combines these with the base address to create as many EndpointDescriptions as required.
Protocols such as HTTP only allow one SecurityPolicy per endpoint to addition URLs are constructed
using the SecurityPolicy and SecurityMode.
The first policy in the list is assigned to base address. -->
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>4</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>2</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</SecurityPolicyUri>
<SecurityLevel>0</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>1</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>5</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>3</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>6</SecurityLevel>
</ServerSecurityPolicy>
</SecurityPolicies>
<MinRequestThreadCount>5</MinRequestThreadCount>
<MaxRequestThreadCount>100</MaxRequestThreadCount>
<MaxQueuedRequestCount>2000</MaxQueuedRequestCount>
<!-- The SDK expects the server to support the same set of user tokens for every endpoint. -->
<UserTokenPolicies>
<!-- Allows anonymous users -->
<ua:UserTokenPolicy>
<ua:TokenType>Anonymous_0</ua:TokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows username/password -->
<ua:UserTokenPolicy>
<ua:TokenType>UserName_1</ua:TokenType>
<!-- passwords must be encrypted - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows user certificates -->
<ua:UserTokenPolicy>
<ua:TokenType>Certificate_2</ua:TokenType>
<!-- certificate possession must be proven with a digital signature - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!--
Issued tokens are any type of WS-Security compliant token
This is a URN assigned by OASIS to SAML Security Tokens
tokens must be encrypted - this specifies what algorithm to use
<ua:UserTokenPolicy>
<ua:TokenType>IssuedToken_3</ua:TokenType>
<ua:IssuedTokenType>urn:oasis:names:tc:SAML:1.0:assertion:Assertion</ua:IssuedTokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
-->
</UserTokenPolicies>
<!-- Whether the server updates its diagnostic information -->
<DiagnosticsEnabled>true</DiagnosticsEnabled>
<!-- The maximum number of simultaneous sessions -->
<MaxSessionCount>100</MaxSessionCount>
<!-- The minimum session lifetime permitted by the server -->
<MinSessionTimeout>10000</MinSessionTimeout>
<!-- The maximum session lifetime permitted by the server -->
<MaxSessionTimeout>3600000</MaxSessionTimeout>
<!-- The maximum number of browse continuation points per session -->
<MaxBrowseContinuationPoints>10</MaxBrowseContinuationPoints>
<!-- The maximum number of query continuation points per session -->
<MaxQueryContinuationPoints>10</MaxQueryContinuationPoints>
<!-- The maximum number of history continuation points per session -->
<MaxHistoryContinuationPoints>100</MaxHistoryContinuationPoints>
<!-- The maximum age of an incoming request -->
<MaxRequestAge>600000</MaxRequestAge>
<!-- The minimum allowed publishing interval (in milliseconds) -->
<MinPublishingInterval>100</MinPublishingInterval>
<!-- The maximum allowed publishing interval (in milliseconds) -->
<MaxPublishingInterval>3600000</MaxPublishingInterval>
<!-- The publishing resolution. Requested publishing intervals are rounded up to the next multiple of this value.-->
<PublishingResolution>100</PublishingResolution>
<!-- The maximum subscription lifetime.
This controls the maximum keep alive count. Smaller publishing intervals will allow large keep alives
provided the maximum subscription lifetime is not exceeded -->
<MaxSubscriptionLifetime>3600000</MaxSubscriptionLifetime>
<!-- The maximum number of sent messages kept in the queue for each subscription-->
<MaxMessageQueueSize>100</MaxMessageQueueSize>
<!-- The maximum number of notifications kept in the queue for each monitored item-->
<MaxNotificationQueueSize>100</MaxNotificationQueueSize>
<!-- The maximum number of notifications in a single publish response -->
<MaxNotificationsPerPublish>1000</MaxNotificationsPerPublish>
<!-- The minimum sampling rate for rarely changing metadata information (such as the server status) -->
<MinMetadataSamplingInterval>1000</MinMetadataSamplingInterval>
<!-- The set of supported sampling rates -->
<AvailableSamplingRates />
<!-- Servers must create a secure channel with the DiscoveryServer
This element specifies the connection information.
Note that server will use the discovery endpoint to update this information -->
<RegistrationEndpoint>
<ua:EndpointUrl>opc.tcp://localhost:4840</ua:EndpointUrl>
<ua:Server>
<ua:ApplicationUri>opc.tcp://localhost:4840</ua:ApplicationUri>
<ua:ApplicationType>DiscoveryServer_3</ua:ApplicationType>
<ua:DiscoveryUrls>
<ua:String>opc.tcp://localhost:4840</ua:String>
</ua:DiscoveryUrls>
</ua:Server>
<ua:SecurityMode>SignAndEncrypt_3</ua:SecurityMode>
<ua:SecurityPolicyUri />
<ua:UserIdentityTokens />
<ua:SecurityLevel>1</ua:SecurityLevel>
</RegistrationEndpoint>
<!-- The maximum interval between registration. 0 disables periodic registration -->
<MaxRegistrationInterval>0</MaxRegistrationInterval>
<!-- The file used to save nodes added to the CoreNodeManager. If missing the CoreNodeManger will discard nodes when it stops. -->
<NodeManagerSaveFile>Opc.Ua.Server.nodes.xml</NodeManagerSaveFile>
<!-- The minimum subscription lifetime.
This ensures subscriptions are not set to expire too quickly. The revised lifetime count
and keep alive count are calculated with this value. -->
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
</ServerConfiguration>
<!-- This element is only required for Client and ClientServer applications -->
<ClientConfiguration>
<!-- The default timeout for new sessions -->
<DefaultSessionTimeout>600000</DefaultSessionTimeout>
<!-- The well-known URLs for the local discovery servers
URLs are tested in the order they appear in this list. -->
<WellKnownDiscoveryUrls>
<ua:String>opc.tcp://{0}:4840/UADiscovery</ua:String>
<ua:String>http://{0}:52601/UADiscovery</ua:String>
<ua:String>http://{0}/UADiscovery/Default.svc</ua:String>
</WellKnownDiscoveryUrls>
<!-- EndpointDescriptions for system wide discovery servers -->
<DiscoveryServers></DiscoveryServers>
<!-- The file used to save the EndpointDescriptions for servers known to the Client -->
<EndpointCacheFilePath>Opc.Ua.SampleClient.Endpoints.xml</EndpointCacheFilePath>
<!-- The minimum subscription lifetime.
This ensures subscriptions are not set to expire too quickly. The requesed lifetime count
and keep alive count are calculated using this value and the request publishing interval -->
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
</ClientConfiguration>
<Extensions>
<ua:XmlElement>
<MemoryBufferConfiguration xmlns="http://samples.org/UA/memorybuffer">
<Buffers>
<MemoryBufferInstance>
<Name>UInt32</Name>
<TagCount>100</TagCount>
<DataType>UInt32</DataType>
</MemoryBufferInstance>
<MemoryBufferInstance>
<Name>Double</Name>
<TagCount>100</TagCount>
<DataType>Double</DataType>
</MemoryBufferInstance>
</Buffers>
</MemoryBufferConfiguration>
</ua:XmlElement>
</Extensions>
<!--
Masks supported by the trace feature.
Servers will detect changes within 5 seconds.
Do not output any messages.
None = 0x0;
Output error messages.
Error = 0x1;
Output informational messages.
Information = 0x2;
Output stack traces.
StackTrace = 0x4;
Output basic messages for service calls.
Service = 0x8;
Output detailed messages for service calls.
ServiceDetail = 0x10;
Output basic messages for each operation.
Operation = 0x20;
Output detailed messages for each operation.
OperationDetail = 0x40;
Output messages related to application initialization or shutdown
StartStop = 0x80;
Output messages related to a call to an external system.
ExternalSystem = 0x100;
Output messages related to security
Security = 0x200;
-->
<TraceConfiguration>
<OutputFilePath>%LocalFolder%\Logs\Opc.Ua.SampleClient.log.txt</OutputFilePath>
<DeleteOnLoad>true</DeleteOnLoad>
<!-- Show Only Errors -->
<!-- <TraceMasks>1</TraceMasks> -->
<!-- Show Only Security and Errors -->
<TraceMasks>513</TraceMasks>
<!-- Show Only Security, Errors and Trace -->
<!-- <TraceMasks>515</TraceMasks> -->
<!-- Show Only Security, COM Calls, Errors and Trace -->
<!-- <TraceMasks>771</TraceMasks> -->
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
</TraceConfiguration>
<!-- Enables the hi-res clock for the process to allows for shorter (<100ms) publishing and sampling intervals. -->
<!-- QueryPerformanceCounter does not work on all multi-core machines so enabling the hi-res clock by default is not recommended. -->
<DisableHiResClock>true</DisableHiResClock>
</ApplicationConfiguration>
@@ -350,27 +350,6 @@ namespace Opc.Ua.Client.Controls
else
{
listItem.SubItems[2].Text = "No";
if (m_storeId != null)
{
ICertificateStore store = m_storeId.OpenStore();
try
{
if (store.GetPrivateKeyFilePath(certificate.Thumbprint) != null)
{
listItem.SubItems[2].Text = "Yes (No Access)";
}
}
catch (Exception e)
{
listItem.SubItems[2].Text = e.Message;
}
finally
{
store.Close();
}
}
}
// look up domains.
@@ -56,7 +56,7 @@ namespace Opc.Ua.Client.Controls
InitializeComponent();
StoreTypeCB.Items.Add(CertificateStoreType.Directory);
StoreTypeCB.Items.Add(CertificateStoreType.Windows);
StoreTypeCB.Items.Add(CertificateStoreType.X509Store);
StoreTypeCB.SelectedIndex = 0;
}
#endregion
@@ -170,7 +170,7 @@ namespace Opc.Ua.Client.Controls
stores.Add(Path.DirectorySeparatorChar + "OPC Foundation" + Path.DirectorySeparatorChar + "CertificateStores" + Path.DirectorySeparatorChar + "RejectedCertificates");
}
if (CertificateStoreType.Windows == storeType)
if (CertificateStoreType.X509Store == storeType)
{
stores.Add("LocalMachine\\My");
stores.Add("LocalMachine\\UA Applications");
@@ -244,7 +244,7 @@ namespace Opc.Ua.Client.Controls
storePath = dialog.SelectedPath;
}
if (storeType == CertificateStoreType.Windows)
if (storeType == CertificateStoreType.X509Store)
{
CertificateStoreIdentifier store = new CertificateStoreTreeDlg().ShowDialog(null);
@@ -28,8 +28,6 @@
* ======================================================================*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
@@ -38,12 +36,6 @@ using System.Xml;
using System.Runtime.Serialization;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.ServiceProcess;
using System.Management;
using System.Management.Instrumentation;
using System.Runtime.InteropServices;
using Opc.Ua.Configuration;
using System.Threading.Tasks;
namespace Opc.Ua.Client.Controls
{
@@ -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
@@ -13,8 +13,8 @@
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>OPC Foundation/CertificateStores/MachineDefault</StorePath>
<StoreType>X509Store</StoreType>
<StorePath>CurrentUser\UA_MachineDefault</StorePath>
<SubjectName>UA Core Sample Server</SubjectName>
</ApplicationCertificate>
@@ -42,8 +42,7 @@
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<TransportConfigurations/>
<TransportQuotas>
<OperationTimeout>600000</OperationTimeout>
@@ -193,7 +192,7 @@
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
<TraceMasks>519</TraceMasks>
</TraceConfiguration>
<!-- Disables the hi-res clock if the QueryPerformanceCounter does work on a particular machine. -->
@@ -13,8 +13,8 @@
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault</StorePath>
<StoreType>X509Store</StoreType>
<StorePath>CurrentUser\UA_MachineDefault</StorePath>
<SubjectName>UA Sample Server</SubjectName>
</ApplicationCertificate>
@@ -1,208 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
schemaLocation="./Schema/ApplicationConfiguration.xsd"
>
<ApplicationName>Opc.Ua.SampleServer</ApplicationName>
<ApplicationUri>urn:localhost:OPCFoundation:SampleServer</ApplicationUri>
<ProductUri>http://opcfoundation.org/UA/SampleServer</ProductUri>
<ApplicationType>Server_0</ApplicationType>
<SecurityConfiguration>
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\MachineDefault</StorePath>
<SubjectName>Opc.Ua.SampleServer</SubjectName>
</ApplicationCertificate>
<!-- Where the issuer certificate are stored (certificate authorities) -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities</StorePath>
</TrustedIssuerCertificates>
<!-- Where the trust list is stored (UA Applications) -->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Applications</StorePath>
</TrustedPeerCertificates>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates</StorePath>
</RejectedCertificateStore>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<TransportQuotas>
<OperationTimeout>600000</OperationTimeout>
<MaxStringLength>1048576</MaxStringLength>
<MaxByteStringLength>4194304</MaxByteStringLength>
<MaxArrayLength>65535</MaxArrayLength>
<MaxMessageSize>4194304</MaxMessageSize>
<MaxBufferSize>65535</MaxBufferSize>
<ChannelLifetime>300000</ChannelLifetime>
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<ServerConfiguration>
<BaseAddresses>
<ua:String>opc.tcp://localhost:51210/UA/SampleServer</ua:String>
</BaseAddresses>
<!--
These list the alternate addresses (via firewalls, multiple NICs etc.) that can be
used to communicate with the server. The URL used by the client when calling
FindServers/GetEndpoints or CreateSession will be used to filter the list of
endpoints returned by checking for alternate base addresses that have a domain
that matches the domain in the url provided by the client.
Note that any additional domains should be listed in the server's certificate. If they
are left out the client make refuse to connect because it has no way to know if the
alternate domain was authorized by the server administrator.
-->
<!--
<AlternateBaseAddresses>
<ua:String>http://mycompany.com:40000/UA/SampleServer</ua:String>
</AlternateBaseAddresses>
-->
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>4</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>2</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</SecurityPolicyUri>
<SecurityLevel>0</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>1</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>5</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>3</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>6</SecurityLevel>
</ServerSecurityPolicy>
</SecurityPolicies>
<MinRequestThreadCount>5</MinRequestThreadCount>
<MaxRequestThreadCount>100</MaxRequestThreadCount>
<MaxQueuedRequestCount>2000</MaxQueuedRequestCount>
<!-- The SDK expects the server to support the same set of user tokens for every endpoint. -->
<UserTokenPolicies>
<!-- Allows anonymous users -->
<ua:UserTokenPolicy>
<ua:TokenType>Anonymous_0</ua:TokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows username/password -->
<ua:UserTokenPolicy>
<ua:TokenType>UserName_1</ua:TokenType>
<!-- passwords must be encrypted - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows user certificates -->
<ua:UserTokenPolicy>
<ua:TokenType>Certificate_2</ua:TokenType>
<!-- certificate possession must be proven with a digital signature - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!--
<ua:UserTokenPolicy>
<ua:TokenType>IssuedToken_3</ua:TokenType>
<ua:IssuedTokenType>urn:oasis:names:tc:SAML:1.0:assertion:Assertion</ua:IssuedTokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
-->
</UserTokenPolicies>
<DiagnosticsEnabled>true</DiagnosticsEnabled>
<MaxSessionCount>100</MaxSessionCount>
<MinSessionTimeout>10000</MinSessionTimeout>
<MaxSessionTimeout>3600000</MaxSessionTimeout>
<MaxBrowseContinuationPoints>10</MaxBrowseContinuationPoints>
<MaxQueryContinuationPoints>10</MaxQueryContinuationPoints>
<MaxHistoryContinuationPoints>100</MaxHistoryContinuationPoints>
<MaxRequestAge>600000</MaxRequestAge>
<MinPublishingInterval>100</MinPublishingInterval>
<MaxPublishingInterval>3600000</MaxPublishingInterval>
<PublishingResolution>50</PublishingResolution>
<MaxSubscriptionLifetime>3600000</MaxSubscriptionLifetime>
<MaxMessageQueueSize>100</MaxMessageQueueSize>
<MaxNotificationQueueSize>100</MaxNotificationQueueSize>
<MaxNotificationsPerPublish>1000</MaxNotificationsPerPublish>
<MinMetadataSamplingInterval>1000</MinMetadataSamplingInterval>
<AvailableSamplingRates />
<MaxRegistrationInterval>0</MaxRegistrationInterval>
<NodeManagerSaveFile>Opc.Ua.Server.nodes.xml</NodeManagerSaveFile>
</ServerConfiguration>
<Extensions>
<ua:XmlElement>
<MemoryBufferConfiguration xmlns="http://samples.org/UA/memorybuffer">
<Buffers>
<MemoryBufferInstance>
<Name>UInt32</Name>
<TagCount>100</TagCount>
<DataType>UInt32</DataType>
</MemoryBufferInstance>
<MemoryBufferInstance>
<Name>Double</Name>
<TagCount>100</TagCount>
<DataType>Double</DataType>
</MemoryBufferInstance>
</Buffers>
</MemoryBufferConfiguration>
</ua:XmlElement>
</Extensions>
<TraceConfiguration>
<OutputFilePath>%LocalFolder%\Logs\Opc.Ua.SampleServer.log.txt</OutputFilePath>
<DeleteOnLoad>true</DeleteOnLoad>
<!-- Show Only Errors -->
<!-- <TraceMasks>1</TraceMasks> -->
<!-- Show Only Security and Errors -->
<TraceMasks>513</TraceMasks>
<!-- Show Only Security, Errors and Trace -->
<!-- <TraceMasks>515</TraceMasks> -->
<!-- Show Only Security, COM Calls, Errors and Trace -->
<!-- <TraceMasks>771</TraceMasks> -->
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
</TraceConfiguration>
<!-- Disables the hi-res clock if the QueryPerformanceCounter does work on a particular machine. -->
<DisableHiResClock>true</DisableHiResClock>
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
schemaLocation="./Schema/ApplicationConfiguration.xsd"
>
<ApplicationName>Opc.Ua.SampleServer</ApplicationName>
<ApplicationUri>urn:localhost:OPCFoundation:SampleServer</ApplicationUri>
<ProductUri>http://opcfoundation.org/UA/SampleServer</ProductUri>
<ApplicationType>Server_0</ApplicationType>
<SecurityConfiguration>
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>X509Store</StoreType>
<StorePath>CurrentUser\UA_MachineDefault</StorePath>
<SubjectName>Opc.Ua.SampleServer</SubjectName>
</ApplicationCertificate>
<!-- Where the issuer certificate are stored (certificate authorities) -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Certificate Authorities</StorePath>
</TrustedIssuerCertificates>
<!-- Where the trust list is stored (UA Applications) -->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\UA Applications</StorePath>
</TrustedPeerCertificates>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%\OPC Foundation\CertificateStores\RejectedCertificates</StorePath>
</RejectedCertificateStore>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<TransportQuotas>
<OperationTimeout>600000</OperationTimeout>
<MaxStringLength>1048576</MaxStringLength>
<MaxByteStringLength>4194304</MaxByteStringLength>
<MaxArrayLength>65535</MaxArrayLength>
<MaxMessageSize>4194304</MaxMessageSize>
<MaxBufferSize>65535</MaxBufferSize>
<ChannelLifetime>300000</ChannelLifetime>
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<ServerConfiguration>
<BaseAddresses>
<ua:String>opc.tcp://localhost:51210/UA/SampleServer</ua:String>
</BaseAddresses>
<!--
These list the alternate addresses (via firewalls, multiple NICs etc.) that can be
used to communicate with the server. The URL used by the client when calling
FindServers/GetEndpoints or CreateSession will be used to filter the list of
endpoints returned by checking for alternate base addresses that have a domain
that matches the domain in the url provided by the client.
Note that any additional domains should be listed in the server's certificate. If they
are left out the client make refuse to connect because it has no way to know if the
alternate domain was authorized by the server administrator.
-->
<!--
<AlternateBaseAddresses>
<ua:String>http://mycompany.com:40000/UA/SampleServer</ua:String>
</AlternateBaseAddresses>
-->
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>4</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>2</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</SecurityPolicyUri>
<SecurityLevel>0</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15</SecurityPolicyUri>
<SecurityLevel>1</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
<SecurityLevel>5</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>Sign_2</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>3</SecurityLevel>
</ServerSecurityPolicy>
<ServerSecurityPolicy>
<SecurityMode>SignAndEncrypt_3</SecurityMode>
<SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256</SecurityPolicyUri>
<SecurityLevel>6</SecurityLevel>
</ServerSecurityPolicy>
</SecurityPolicies>
<MinRequestThreadCount>5</MinRequestThreadCount>
<MaxRequestThreadCount>100</MaxRequestThreadCount>
<MaxQueuedRequestCount>2000</MaxQueuedRequestCount>
<!-- The SDK expects the server to support the same set of user tokens for every endpoint. -->
<UserTokenPolicies>
<!-- Allows anonymous users -->
<ua:UserTokenPolicy>
<ua:TokenType>Anonymous_0</ua:TokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#None</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows username/password -->
<ua:UserTokenPolicy>
<ua:TokenType>UserName_1</ua:TokenType>
<!-- passwords must be encrypted - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!-- Allows user certificates -->
<ua:UserTokenPolicy>
<ua:TokenType>Certificate_2</ua:TokenType>
<!-- certificate possession must be proven with a digital signature - this specifies what algorithm to use -->
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
<!--
<ua:UserTokenPolicy>
<ua:TokenType>IssuedToken_3</ua:TokenType>
<ua:IssuedTokenType>urn:oasis:names:tc:SAML:1.0:assertion:Assertion</ua:IssuedTokenType>
<ua:SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</ua:SecurityPolicyUri>
</ua:UserTokenPolicy>
-->
</UserTokenPolicies>
<DiagnosticsEnabled>true</DiagnosticsEnabled>
<MaxSessionCount>100</MaxSessionCount>
<MinSessionTimeout>10000</MinSessionTimeout>
<MaxSessionTimeout>3600000</MaxSessionTimeout>
<MaxBrowseContinuationPoints>10</MaxBrowseContinuationPoints>
<MaxQueryContinuationPoints>10</MaxQueryContinuationPoints>
<MaxHistoryContinuationPoints>100</MaxHistoryContinuationPoints>
<MaxRequestAge>600000</MaxRequestAge>
<MinPublishingInterval>100</MinPublishingInterval>
<MaxPublishingInterval>3600000</MaxPublishingInterval>
<PublishingResolution>50</PublishingResolution>
<MaxSubscriptionLifetime>3600000</MaxSubscriptionLifetime>
<MaxMessageQueueSize>100</MaxMessageQueueSize>
<MaxNotificationQueueSize>100</MaxNotificationQueueSize>
<MaxNotificationsPerPublish>1000</MaxNotificationsPerPublish>
<MinMetadataSamplingInterval>1000</MinMetadataSamplingInterval>
<AvailableSamplingRates />
<MaxRegistrationInterval>0</MaxRegistrationInterval>
<NodeManagerSaveFile>Opc.Ua.Server.nodes.xml</NodeManagerSaveFile>
</ServerConfiguration>
<Extensions>
<ua:XmlElement>
<MemoryBufferConfiguration xmlns="http://samples.org/UA/memorybuffer">
<Buffers>
<MemoryBufferInstance>
<Name>UInt32</Name>
<TagCount>100</TagCount>
<DataType>UInt32</DataType>
</MemoryBufferInstance>
<MemoryBufferInstance>
<Name>Double</Name>
<TagCount>100</TagCount>
<DataType>Double</DataType>
</MemoryBufferInstance>
</Buffers>
</MemoryBufferConfiguration>
</ua:XmlElement>
</Extensions>
<TraceConfiguration>
<OutputFilePath>%LocalFolder%\Logs\Opc.Ua.SampleServer.log.txt</OutputFilePath>
<DeleteOnLoad>true</DeleteOnLoad>
<!-- Show Only Errors -->
<!-- <TraceMasks>1</TraceMasks> -->
<!-- Show Only Security and Errors -->
<TraceMasks>513</TraceMasks>
<!-- Show Only Security, Errors and Trace -->
<!-- <TraceMasks>515</TraceMasks> -->
<!-- Show Only Security, COM Calls, Errors and Trace -->
<!-- <TraceMasks>771</TraceMasks> -->
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
</TraceConfiguration>
<!-- Disables the hi-res clock if the QueryPerformanceCounter does work on a particular machine. -->
<DisableHiResClock>true</DisableHiResClock>
</ApplicationConfiguration>
@@ -1921,7 +1921,7 @@ namespace Opc.Ua
/// The type of certificate store.
/// </summary>
/// <value>
/// If the StoreName is not empty, the CertificateStoreType.Windows is returned, otherwise the StoreType is returned.
/// If the StoreName is not empty, the CertificateStoreType.X509Store is returned, otherwise the StoreType is returned.
/// </value>
[DataMember(IsRequired = false, EmitDefaultValue = false, Order = 0)]
public string StoreType
@@ -1930,7 +1930,7 @@ namespace Opc.Ua
{
if (!String.IsNullOrEmpty(m_storeName))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
return m_storeType;
@@ -1978,7 +1978,7 @@ namespace Opc.Ua
{
if (m_storePath.StartsWith("LocalMachine", StringComparison.CurrentCultureIgnoreCase) || m_storePath.StartsWith("CurrentUser", StringComparison.CurrentCultureIgnoreCase))
{
m_storeType = CertificateStoreType.Windows;
m_storeType = CertificateStoreType.X509Store;
}
else
{
@@ -2190,7 +2190,7 @@ namespace Opc.Ua
{
if (!String.IsNullOrEmpty(m_storeName))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
return m_storeType;
@@ -2234,7 +2234,7 @@ namespace Opc.Ua
{
if (m_storePath.StartsWith("LocalMachine", StringComparison.CurrentCultureIgnoreCase) || m_storePath.StartsWith("CurrentUser", StringComparison.CurrentCultureIgnoreCase))
{
m_storeType = CertificateStoreType.Windows;
m_storeType = CertificateStoreType.X509Store;
}
else
{
@@ -461,18 +461,8 @@ namespace Opc.Ua.Security
Opc.Ua.CertificateIdentifier output = SecuredApplication.FromCertificateIdentifier(this);
return output.OpenStore();
}
/// <summary>
/// Gets the private key file path.
/// </summary>
public async Task<string> GetPrivateKeyFilePath()
{
Opc.Ua.CertificateIdentifier output = SecuredApplication.FromCertificateIdentifier(this);
return await output.GetPrivateKeyFilePath();
}
}
/// <summary>
/// An identifier for a certificate store.
/// </summary>
@@ -1,41 +0,0 @@
/* Copyright (c) 1996-2016, OPC Foundation. All rights reserved.
The source code in this file is covered under a dual-license scenario:
- RCL: for OPC Foundation members in good-standing
- GPL V2: everybody else
RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
GNU General Public License as published by the Free Software Foundation;
version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace Opc.Ua
{
/// <summary>
/// An access rule for an application.
/// </summary>
public partial class ApplicationAccessRule
{
/// Gets the application access rules implied by the access rights to the file.
/// </summary>
public static IList<ApplicationAccessRule> GetAccessRules(String filePath)
{
// combine the access rules into a set of abstract application rules.
List<ApplicationAccessRule> accessRules = new List<ApplicationAccessRule>();
return accessRules;
}
/// <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)
{
}
}
}
@@ -1,216 +0,0 @@
/* Copyright (c) 1996-2016, OPC Foundation. All rights reserved.
The source code in this file is covered under a dual-license scenario:
- RCL: for OPC Foundation members in good-standing
- GPL V2: everybody else
RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
GNU General Public License as published by the Free Software Foundation;
version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace Opc.Ua.Configuration
{
/// <summary>
/// An access rule for an HTTP URL used by a WCF service.
/// </summary>
[DataContract(Namespace=Namespaces.OpcUaConfig)]
public class HttpAccessRule
{
const Int16 AF_INET = 2;
const Int16 AF_INET6 = 23;
}
#region AccessControlEntity Class
/// <summary>
/// A class that stores the components of ACE within a DACL.
/// </summary>
public class AccessControlEntity
{
/// <summary>
/// The access type granted by the ACE.
/// </summary>
public string AccessType
{
get { return m_accessType; }
set { m_accessType = value; }
}
/// <summary>
/// Any flags associated with the ACE.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags")]
public string Flags
{
get { return m_flags; }
set { m_flags = value; }
}
/// <summary>
/// The rights allowed/restricted by the ACE.
/// </summary>
public string Rights
{
get { return m_rights; }
set { m_rights = value; }
}
/// <summary>
/// The object associated with the ACE.
/// </summary>
public string ObjectGuid
{
get { return m_objectGuid; }
set { m_objectGuid = value; }
}
/// <summary>
/// The inherited object associated with the ACE.
/// </summary>
public string InheritObjectGuid
{
get { return m_inheritObjectGuid; }
set { m_inheritObjectGuid = value; }
}
/// <summary>
/// The SID for the account which is affected by the ACE.
/// </summary>
public string AccountSid
{
get { return m_accountSid; }
set { m_accountSid = value; }
}
/// <summary>
/// Extracts a list of ACEs from a SDDL string.
/// </summary>
public static IList<AccessControlEntity> Parse(string sddl)
{
List<AccessControlEntity> entities = new List<AccessControlEntity>();
if (!sddl.StartsWith("D:", StringComparison.Ordinal))
{
throw new ArgumentException(Utils.Format("Could not parse SDDL string: {0}", sddl));
}
sddl = sddl.Substring(2, sddl.Length-2);
string[] aces = sddl.Split('(', ')');
for (int ii = 0; ii < aces.Length; ii++)
{
if (String.IsNullOrEmpty(aces[ii]))
{
continue;
}
AccessControlEntity entity = new AccessControlEntity();
entity.Initialize(aces[ii]);
entities.Add(entity);
}
return entities;
}
/// <summary>
/// Extracts a single ACE from a SDDL string fragment.
/// </summary>
public void Initialize(string sddl)
{
string[] fields = sddl.Split(';');
if (fields.Length != 6)
{
throw new ArgumentException(Utils.Format("Could not parse SDDL ACE string: {0}", sddl));
}
m_accessType = fields[0];
m_flags = fields[1];
m_rights = fields[2];
m_objectGuid = fields[3];
m_inheritObjectGuid = fields[4];
m_accountSid = fields[5];
}
private string m_accessType;
private string m_flags;
private string m_rights;
private string m_objectGuid;
private string m_inheritObjectGuid;
private string m_accountSid;
}
#endregion
#region SslCertificateBinding Class
/// <summary>
/// Stores the details of an SSL certification configuration binding.
/// </summary>
public class SslCertificateBinding
{
/// <summary>
/// The IP Address.
/// </summary>
public IPAddress IPAddress { get; set; }
/// <summary>
/// The port number.
/// </summary>
public ushort Port { get; set; }
/// <summary>
/// The certificate thumbprint.
/// </summary>
public string Thumbprint { get; set; }
/// <summary>
/// The application id.
/// </summary>
public Guid ApplicationId { get; set; }
/// <summary>
/// The names of the store to use.
/// </summary>
public string StoreName { get; set; }
/// <summary>
/// The default revocation check mode.
/// </summary>
public uint DefaultCertCheckMode { get; set; }
/// <summary>
/// The default revocation freshness time.
/// </summary>
public int DefaultRevocationFreshnessTime { get; set; }
/// <summary>
/// The default revocation URL timeout.
/// </summary>
public int DefaultRevocationUrlRetrievalTimeout { get; set; }
/// <summary>
/// The default certificate trust list identifier.
/// </summary>
public string DefaultSslCtlIdentifier { get; set; }
/// <summary>
/// The default certificate trust list store.
/// </summary>
public string DefaultSslCtlStoreName { get; set; }
/// <summary>
/// The default flags.
/// </summary>
public uint DefaultFlags { get; set; }
}
#endregion
}
@@ -183,12 +183,6 @@ namespace Opc.Ua
bool isCA,
X509Certificate2 issuerCAKeyCert)
{
if (!String.IsNullOrEmpty(storeType) &&
storeType != CertificateStoreType.Directory)
{
throw new NotSupportedException("Cannot create a certificate for a non directory store.");
}
if (issuerCAKeyCert != null)
{
if (!issuerCAKeyCert.HasPrivateKey)
@@ -312,15 +306,23 @@ namespace Opc.Ua
if (!String.IsNullOrEmpty(storePath))
{
ICertificateStore store = null;
if (storeType == CertificateStoreType.Directory)
if (storeType == CertificateStoreType.X509Store)
{
using (store = new DirectoryCertificateStore())
{
store.Open(storePath);
store.Add(certificate);
store.Close();
}
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!
@@ -12,7 +12,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -471,31 +470,6 @@ namespace Opc.Ua
store.Open(this.StorePath);
return store;
}
/// <summary>
/// Gets the private key file path.
/// </summary>
public async Task<string> GetPrivateKeyFilePath()
{
X509Certificate2 certificate = await Find(false);
if (certificate == null)
{
return null;
}
ICertificateStore store = CertificateStoreIdentifier.CreateStore(this.StoreType);
try
{
store.Open(this.StorePath);
return store.GetPrivateKeyFilePath(certificate.Thumbprint);
}
finally
{
store.Close();
}
}
#endregion
#region Private Methods
@@ -737,83 +711,6 @@ namespace Opc.Ua
return null;
}
/// <summary>
/// Whether the store supports access control.
/// </summary>
public bool SupportsAccessControl
{
get { return false; }
}
/// <summary>
/// Returns the access rules that are currently applied to the store.
/// </summary>
/// <returns>The list of access rules.</returns>
public IList<ApplicationAccessRule> GetAccessRules()
{
throw new NotImplementedException();
}
/// <summary>
/// Sets the access rules that are currently applied to the store.
/// </summary>
/// <param name="rules">The rules.</param>
/// <param name="replaceExisting">if set to <c>true</c> the existing access rules are replaced.</param>
public void SetAccessRules(IList<ApplicationAccessRule> rules, bool replaceExisting)
{
throw new NotImplementedException();
}
/// <summary>
/// Whether the store supports access control on certificates.
/// </summary>
public bool SupportsCertificateAccessControl
{
get { return false; }
}
/// <summary>
/// Whether the store supports private keys.
/// </summary>
/// <value></value>
public bool SupportsPrivateKeys
{
get { return false; }
}
/// <summary>
/// Returns the file containing the private key for the specified certificate.
/// </summary>
public string GetPrivateKeyFilePath(string thumbprint)
{
return null;
}
/// <summary>
/// Returns the access rules that are currently applied to the certficate's private key.
/// </summary>
/// <param name="thumbprint">The thumbprint.</param>
/// <returns>The access rules.</returns>
public IList<ApplicationAccessRule> GetAccessRules(string thumbprint)
{
throw new NotImplementedException();
}
/// <summary>
/// Sets the access rules that are currently applied to the certficate's private key.
/// </summary>
/// <param name="thumbprint">The thumbprint.</param>
/// <param name="rules">The rules.</param>
/// <param name="replaceExisting">if set to <c>true</c> the existing access rules are replaced.</param>
public void SetAccessRules(string thumbprint, IList<ApplicationAccessRule> rules, bool replaceExisting)
{
throw new NotImplementedException();
}
/// <summary>
/// Whether the store support CRLs.
/// </summary>
public bool SupportsCRLs { get { return false; } }
/// <summary>
/// Checks if issuer has revoked the certificate.
/// </summary>
@@ -821,13 +718,13 @@ namespace Opc.Ua
{
return StatusCodes.BadNotSupported;
}
/// <summary>
/// Returns the CRLs in the store.
/// </summary>
public List<X509CRL> EnumerateCRLs()
{
return new List<X509CRL>();
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
/// <summary>
@@ -835,9 +732,9 @@ namespace Opc.Ua
/// </summary>
public List<X509CRL> EnumerateCRLs(X509Certificate2 issuer)
{
return new List<X509CRL>();
}
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
/// <summary>
/// Adds a CRL to the store.
/// </summary>
@@ -98,22 +98,22 @@ namespace Opc.Ua
if (storePath.StartsWith("LocalMachine\\", StringComparison.OrdinalIgnoreCase))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
if (storePath.StartsWith("CurrentUser\\", StringComparison.OrdinalIgnoreCase))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
if (storePath.StartsWith("User\\", StringComparison.OrdinalIgnoreCase))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
if (storePath.StartsWith("Service\\", StringComparison.OrdinalIgnoreCase))
{
return CertificateStoreType.Windows;
return CertificateStoreType.X509Store;
}
return CertificateStoreType.Directory;
@@ -133,6 +133,11 @@ namespace Opc.Ua
switch (storeType)
{
case CertificateStoreType.X509Store:
{
store = new X509CertificateStore();
break;
}
case CertificateStoreType.Directory:
{
store = new DirectoryCertificateStore();
@@ -175,7 +180,7 @@ namespace Opc.Ua
/// <summary>
/// A windows certificate store.
/// </summary>
public const string Windows = "Windows";
public const string X509Store = "X509Store";
/// <summary>
/// A directory certificate store.
@@ -72,7 +72,7 @@ namespace Opc.Ua
/// <value>
/// <c>true</c> if [no private keys]; otherwise, <c>false</c>.
/// </value>
public bool NoPrivateKeys { get; set; }
private bool NoPrivateKeys { get; set; }
#endregion
#region ICertificateStore Members
@@ -164,6 +164,7 @@ namespace Opc.Ua
m_lastDirectoryCheck = DateTime.MinValue;
}
return Task.CompletedTask;
}
@@ -224,167 +225,6 @@ namespace Opc.Ua
}
}
/// <summary cref="ICertificateStore.SupportsAccessControl" />
public bool SupportsAccessControl
{
get { return true; }
}
/// <summary cref="ICertificateStore.GetAccessRules()" />
public IList<ApplicationAccessRule> GetAccessRules()
{
lock (m_lock)
{
return ApplicationAccessRule.GetAccessRules(m_certificateSubdir.FullName);
}
}
/// <summary cref="ICertificateStore.SetAccessRules(IList{ApplicationAccessRule},bool)" />
public void SetAccessRules(IList<ApplicationAccessRule> rules, bool replaceExisting)
{
lock (m_lock)
{
ApplicationAccessRule.SetAccessRules(m_certificateSubdir.FullName, rules, replaceExisting);
if (String.Compare(m_certificateSubdir.FullName, m_privateKeySubdir.FullName, StringComparison.OrdinalIgnoreCase) != 0)
{
ApplicationAccessRule.SetAccessRules(m_privateKeySubdir.FullName, rules, replaceExisting);
}
}
}
/// <summary cref="ICertificateStore.SupportsCertificateAccessControl" />
public bool SupportsCertificateAccessControl
{
get
{
return true;
}
}
/// <summary cref="ICertificateStore.SupportsPrivateKeys" />
public bool SupportsPrivateKeys
{
get
{
return true;
}
}
/// <summary cref="ICertificateStore.GetPrivateKeyFilePath" />
public string GetPublicKeyFilePath(string thumbprint)
{
Entry entry = Find(thumbprint);
if (entry == null)
{
return null;
}
if (entry.CertificateFile == null || !entry.CertificateFile.Exists)
{
return null;
}
return entry.CertificateFile.FullName;
}
/// <summary cref="ICertificateStore.GetPrivateKeyFilePath" />
public string GetPrivateKeyFilePath(string thumbprint)
{
Entry entry = Find(thumbprint);
if (entry == null)
{
return null;
}
if (entry.PrivateKeyFile == null || !entry.PrivateKeyFile.Exists)
{
return null;
}
return entry.PrivateKeyFile.FullName;
}
/// <summary>
/// Gets the CRL file paths.
/// </summary>
/// <param name="thumbprint">The certificate thumbprint.</param>
/// <returns></returns>
public string[] GetCrlFilePaths(string thumbprint)
{
List<string> filePaths = new List<string>();
Entry entry = Find(thumbprint);
DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + Path.DirectorySeparatorChar + "crl");
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, entry.Certificate.Subject))
{
continue;
}
filePaths.Add(file.FullName);
}
return filePaths.ToArray();
}
/// <summary cref="ICertificateStore.GetAccessRules(string)" />
public IList<ApplicationAccessRule> GetAccessRules(string thumbprint)
{
lock (m_lock)
{
Entry entry = Find(thumbprint);
if (entry == null)
{
throw new ArgumentException("Certificate does not exist in store.");
}
if (entry.PrivateKeyFile == null || !entry.PrivateKeyFile.Exists)
{
throw new ArgumentException("Certificate does not have a private key in the store.");
}
return ApplicationAccessRule.GetAccessRules(entry.PrivateKeyFile.FullName);
}
}
/// <summary cref="ICertificateStore.SetAccessRules(string, IList{ApplicationAccessRule},bool)" />
public void SetAccessRules(string thumbprint, IList<ApplicationAccessRule> rules, bool replaceExisting)
{
lock (m_lock)
{
Entry entry = Find(thumbprint);
if (entry == null)
{
throw new ArgumentException("Certificate does not exist in store.");
}
if (entry.PrivateKeyFile != null && entry.PrivateKeyFile.Exists)
{
ApplicationAccessRule.SetAccessRules(entry.PrivateKeyFile.FullName, rules, replaceExisting);
}
}
}
/// <summary>
/// Loads the private key from a PFX file in the certificate store.
/// </summary>
@@ -472,11 +312,6 @@ namespace Opc.Ua
return null;
}
/// <summary>
/// Whether the store support CRLs.
/// </summary>
public bool SupportsCRLs { get { return true; } }
/// <summary>
/// Checks if issuer has revoked the certificate.
/// </summary>
@@ -640,7 +475,7 @@ namespace Opc.Ua
StringBuilder builder = new StringBuilder();
builder.Append(m_directory.FullName);
builder.Append(Path.DirectorySeparatorChar + "crl" + Path.DirectorySeparatorChar);
builder.Append(GetFileName(issuer));
builder.Append(".crl");
@@ -689,9 +524,9 @@ namespace Opc.Ua
return false;
}
#endregion
#endregion
#region Private Methods
#region Private Methods
/// <summary>
/// Reads the current contents of the directory from disk.
/// </summary>
@@ -17,10 +17,10 @@ using System.Threading.Tasks;
namespace Opc.Ua
{
/// <summary>
/// <summary>
/// An abstract interface to certficate stores.
/// </summary>
public interface ICertificateStore : IDisposable
public interface ICertificateStore : IDisposable
{
/// <summary>
/// Opens the store at the specified location.
@@ -61,64 +61,11 @@ namespace Opc.Ua
/// <returns>The matching certificate</returns>
Task<X509Certificate2Collection> FindByThumbprint(string thumbprint);
/// <summary>
/// Whether the store supports access control.
/// </summary>
bool SupportsAccessControl { get; }
/// <summary>
/// Returns the access rules that are currently applied to the store.
/// </summary>
/// <returns>The list of access rules.</returns>
IList<ApplicationAccessRule> GetAccessRules();
/// <summary>
/// Sets the access rules that are currently applied to the store.
/// </summary>
/// <param name="rules">The rules.</param>
/// <param name="replaceExisting">if set to <c>true</c> the existing access rules are replaced.</param>
void SetAccessRules(IList<ApplicationAccessRule> rules, bool replaceExisting);
/// <summary>
/// Whether the store supports access control on certificates.
/// </summary>
bool SupportsCertificateAccessControl { get; }
/// Whether the store supports private keys.
/// </summary>
bool SupportsPrivateKeys { get; }
/// <summary>
/// Returns the file containing the private key for the specified certificate.
/// </summary>
/// <param name="thumbprint">The thumbprint.</param>
/// <returns>The full file path. Null if the certificate does not exist or the private key does not exist.</returns>
string GetPrivateKeyFilePath(string thumbprint);
/// <summary>
/// Returns the access rules that are currently applied to the certficate's private key.
/// </summary>
/// <param name="thumbprint">The thumbprint.</param>
/// <returns>The access rules.</returns>
IList<ApplicationAccessRule> GetAccessRules(string thumbprint);
/// <summary>
/// Sets the access rules that are currently applied to the certficate's private key.
/// </summary>
/// <param name="thumbprint">The thumbprint.</param>
/// <param name="rules">The rules.</param>
/// <param name="replaceExisting">if set to <c>true</c> the existing access rules are replaced.</param>
void SetAccessRules(string thumbprint, IList<ApplicationAccessRule> rules, bool replaceExisting);
/// <summary>
/// Whether the store supports CRLs.
/// </summary>
bool SupportsCRLs { get; }
/// <summary>
/// Checks if issuer has revoked the certificate.
/// </summary>
StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate);
/// <summary>
/// Returns the CRLs in the store.
/// </summary>
@@ -0,0 +1,210 @@
/* Copyright (c) 1996-2016, OPC Foundation. All rights reserved.
The source code in this file is covered under a dual-license scenario:
- RCL: for OPC Foundation members in good-standing
- GPL V2: everybody else
RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
GNU General Public License as published by the Free Software Foundation;
version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace Opc.Ua
{
/// <summary>
/// Provides access to a simple file based certificate store.
/// </summary>
public class X509CertificateStore : ICertificateStore
{
public X509CertificateStore()
{
m_store = null;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Close();
}
}
/// <summary cref="ICertificateStore.Open(string)" />
/// <remarks>
/// Syntax: StoreLocation\StoreName
/// Examples:
/// LocalMachine\My
/// CurrentUser\Trust
/// </remarks>
public void Open(string path)
{
if (path == null) throw new ArgumentNullException("path");
path = path.Trim();
if (string.IsNullOrEmpty(path))
{
throw ServiceResultException.Create(
StatusCodes.BadUnexpectedError,
"Store Location cannot be empty.");
}
// extract store name.
int index = path.IndexOf('\\');
if (index == -1)
{
throw ServiceResultException.Create(
StatusCodes.BadUnexpectedError,
"Path does not specify a store name. Path={0}",
path);
}
// extract store location.
string storeLocation = path.Substring(0, index);
StoreLocation selectedLocation = StoreLocation.CurrentUser;
bool found = false;
foreach (StoreLocation availableLocation in (StoreLocation[])Enum.GetValues(typeof(StoreLocation)))
{
if (availableLocation.ToString() == storeLocation)
{
selectedLocation = availableLocation;
found = true;
}
}
if (found == false)
{
throw ServiceResultException.Create(
StatusCodes.BadUnexpectedError,
"Store location specified not available.\r\nStore location={0}",
storeLocation);
}
string storeName = path.Substring(index + 1);
m_store = new X509Store(storeName, selectedLocation);
m_store.Open(OpenFlags.ReadWrite);
}
public void Close()
{
if (m_store != null)
{
m_store.Dispose();
m_store = null;
}
}
public Task<X509Certificate2Collection> Enumerate()
{
if (m_store == null)
{
throw new NullReferenceException("Store null. Call Open() on the store first!");
}
X509Certificate2Collection certificates = new X509Certificate2Collection();
certificates.AddRange(m_store.Certificates);
return Task.FromResult(certificates);
}
/// <summary cref="ICertificateStore.Add(X509Certificate2)" />
public Task Add(X509Certificate2 certificate)
{
if (m_store == null)
{
throw new NullReferenceException("Store null. Call Open() on the store first!");
}
if (certificate == null) throw new ArgumentNullException("certificate");
if (!m_store.Certificates.Contains(certificate))
{
m_store.Add(certificate);
Utils.Trace(Utils.TraceMasks.Information, "Added cert {0} to X509Store {1}.", certificate.ToString(), m_store.Name);
}
return Task.CompletedTask;
}
public Task<bool> Delete(string thumbprint)
{
if (m_store == null)
{
throw new NullReferenceException("Store null. Call Open() on the store first!");
}
foreach (X509Certificate2 certificate in m_store.Certificates)
{
if (certificate.Thumbprint == thumbprint)
{
m_store.Certificates.Remove(certificate);
}
}
return Task.FromResult(true);
}
public Task<X509Certificate2Collection> FindByThumbprint(string thumbprint)
{
if (m_store == null)
{
throw new NullReferenceException("Store null. Call Open() on the store first!");
}
X509Certificate2Collection collection = new X509Certificate2Collection();
foreach (X509Certificate2 certificate in m_store.Certificates)
{
if (certificate.Thumbprint == thumbprint)
{
collection.Add(certificate);
}
}
return Task.FromResult(collection);
}
public StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate)
{
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
public List<X509CRL> EnumerateCRLs()
{
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
public List<X509CRL> EnumerateCRLs(X509Certificate2 issuer)
{
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
public void AddCRL(X509CRL crl)
{
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
public bool DeleteCRL(X509CRL crl)
{
throw new ServiceResultException(StatusCodes.BadNotSupported);
}
private X509Store m_store;
}
}
@@ -12,48 +12,6 @@
namespace Opc.Ua
{
/// <summary>
/// Constants that identify certificate store locations.
/// </summary>
public static class StoreLocations
{
/// <summary>
/// The store assigned to the current user.
/// </summary>
public const string CurrentUser = "CurrentUser";
/// <summary>
/// The store assigned to the local machine.
/// </summary>
public const string LocalMachine = "LocalMachine";
}
/// <summary>
/// Constants that identify certificate store names.
/// </summary>
public static class StoreNames
{
/// <summary>
/// The store used for personal certificates.
/// </summary>
public const string Personal = "My";
/// <summary>
/// The store used for UA application certificates.
/// </summary>
public const string Applications = "UA Applications";
/// <summary>
/// The store used for UA certificate authorities certificates.
/// </summary>
public const string CertificateAuthorities = "UA Certificate Authorities";
/// <summary>
/// The store used for trusted root certificate authorities.
/// </summary>
public const string Root = "Root";
}
/// <summary>
/// Defines constants for key security policies.
/// </summary>