Repository navigation
Expand file tree
/
Copy pathUAApplication.cs
More file actions
142 lines (118 loc) · 6.88 KB
/
Copy pathUAApplication.cs
File metadata and controls
142 lines (118 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
namespace Opc.Ua.Cloud.Publisher
{
using Microsoft.Extensions.Logging;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Cloud.Publisher.Interfaces;
using Opc.Ua.Configuration;
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
public class UAApplication : IUAApplication
{
private readonly ILogger _logger;
public ConsoleTelemetry Telemetry { get; } = new();
public X509Certificate2 IssuerCert { get; set; }
public ApplicationInstance UAApplicationInstance { get; set; }
public ReverseConnectManager ReverseConnectManager { get; set; }
public UAApplication(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("UAApplication");
}
public async Task CreateAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation($"Creating OPC UA app named {Settings.Instance.PublisherName}");
ApplicationInstance.MessageDlg = new ApplicationMessageDlg();
// create UA app
UAApplicationInstance = new ApplicationInstance(Telemetry)
{
ApplicationName = Settings.Instance.PublisherName,
ApplicationType = ApplicationType.Client,
ConfigSectionName = "UACloudPublisher"
};
ReverseConnectManager = new(Telemetry);
// overwrite app name in UA config file, while removing spaces from the app name
string fileContent = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "UACloudPublisher.Config.xml"));
fileContent = fileContent.Replace("UACloudPublisher", UAApplicationInstance.ApplicationName.Replace(" ", string.Empty));
File.WriteAllText(Path.Combine(Directory.GetCurrentDirectory(), "UACloudPublisher.Config.xml"), fileContent);
// now load UA config file
await UAApplicationInstance.LoadApplicationConfigurationAsync(false).ConfigureAwait(false);
// check the application certificate
bool certOK = await UAApplicationInstance.CheckApplicationInstanceCertificatesAsync(false, 0).ConfigureAwait(false);
if (!certOK)
{
throw new Exception("Application instance certificate invalid!");
}
else
{
// store UA cert thumbprint
Settings.Instance.UAClientCertThumbprint = UAApplicationInstance.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.Certificate.Thumbprint;
Settings.Instance.UAClientCertExpiry = UAApplicationInstance.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.Certificate.NotAfter;
}
_logger.LogInformation($"Application Certificate subject name is: {UAApplicationInstance.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.SubjectName}");
// create OPC UA cert validator
UAApplicationInstance.ApplicationConfiguration.CertificateValidator = new CertificateValidator(Telemetry);
UAApplicationInstance.ApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(OPCUAServerCertificateValidationCallback);
await UAApplicationInstance.ApplicationConfiguration.CertificateValidator.UpdateAsync(UAApplicationInstance.ApplicationConfiguration).ConfigureAwait(false);
await CreateIssuerCertAsync(cancellationToken).ConfigureAwait(false);
_logger.LogInformation("Creating reverse connection endpoint on local port 50000.");
ReverseConnectManager.AddEndpoint(new Uri("opc.tcp://localhost:50000"));
ReverseConnectManager.StartService(UAApplicationInstance.ApplicationConfiguration);
}
private void OPCUAServerCertificateValidationCallback(CertificateValidator validator, CertificateValidationEventArgs e)
{
// always trust the OPC UA server certificate
if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
{
_logger.LogInformation($"Auto-accepting untrusted OPC UA server certificate {e.Certificate.Subject}");
e.Accept = true;
}
}
private async Task CreateIssuerCertAsync(CancellationToken cancellationToken = default)
{
string pathToIssuerStore = Path.Combine(Directory.GetCurrentDirectory(), "pki", "issuer", "private");
if (!Directory.Exists(pathToIssuerStore))
{
Directory.CreateDirectory(pathToIssuerStore);
}
string[] issuerCerts = Directory.GetFiles(pathToIssuerStore);
if ((issuerCerts == null) || (issuerCerts.Count() == 0))
{
_logger.LogError("Could not load issuer cert file, creating a new one. This means all connected OPC UA servers need to be issued a new cert!");
string subjectName = "CN=" + Settings.Instance.PublisherName + ", O=OPC Foundation";
IssuerCert = await CertificateFactory.CreateCertificate(subjectName)
.SetNotBefore(DateTime.Today.AddDays(-1))
.SetLifeTime(12)
.SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(2048))
.SetCAConstraint()
.SetRSAKeySize(2048)
.CreateForRSA()
.AddToStoreAsync(CertificateStoreType.Directory, Path.Combine(Directory.GetCurrentDirectory(), "pki", "issuer"))
.ConfigureAwait(false);
}
else
{
IssuerCert = X509CertificateLoader.LoadPkcs12FromFile(issuerCerts[0], string.Empty);
}
// also add the issuer cert to our trusted store (public key only) so that certificates
// issued by it are trusted during certificate chain validation
try
{
X509Certificate2 issuerPublicKey = X509CertificateLoader.LoadCertificate(IssuerCert.RawData);
await UAApplicationInstance.AddOwnCertificateToTrustedStoreAsync(issuerPublicKey, cancellationToken).ConfigureAwait(false);
_logger.LogInformation($"Added issuer certificate {issuerPublicKey.Subject} [{issuerPublicKey.Thumbprint}] to the trusted store.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Could not add the issuer certificate to the trusted store.");
}
Settings.Instance.UAIssuerCertThumbprint = IssuerCert.Thumbprint;
Settings.Instance.UAIssuerCertExpiry = IssuerCert.NotAfter;
Settings.Instance.Save();
}
}
}