private async Task UpdateApiKeyAndCertificateAsync()

in src/Azure.IIoT.OpcUa.Publisher/src/Services/RuntimeStateReporter.cs [215:366]


        private async Task UpdateApiKeyAndCertificateAsync()
        {
            var apiKeyStore = _stores.Find(s => s.State.TryGetValue(
                OpcUa.Constants.TwinPropertyApiKeyKey, out var key) && key.IsString);
            if (apiKeyStore != null)
            {
                ApiKey = (string?)apiKeyStore.State[OpcUa.Constants.TwinPropertyApiKeyKey];
                _logger.LogInformation("Api Key exists in {Store} store...", apiKeyStore.Name);
            }

            if (!string.IsNullOrWhiteSpace(_options.Value.ApiKeyOverride) &&
                ApiKey != _options.Value.ApiKeyOverride)
            {
                Debug.Assert(_stores.Count > 0);
                _logger.LogInformation("Using Api Key provided in configuration...");
                ApiKey = _options.Value.ApiKeyOverride;

                _stores[0].State.Add(OpcUa.Constants.TwinPropertyApiKeyKey, ApiKey);
            }

            if (string.IsNullOrWhiteSpace(ApiKey))
            {
                Debug.Assert(_stores.Count > 0);

                _logger.LogInformation("Generating new Api Key in {Store} store...",
                    _stores[0].Name);
                ApiKey = RandomNumberGenerator.GetBytes(20).ToBase64String();
                _stores[0].State.Add(OpcUa.Constants.TwinPropertyApiKeyKey, ApiKey);
            }

            var dnsName = Dns.GetHostName();

            // The certificate must be in the same store as the api key or else we generate a new one.
            if (!(_options.Value.RenewTlsCertificateOnStartup ?? false) &&
                apiKeyStore != null &&
                apiKeyStore.State.TryGetValue(OpcUa.Constants.TwinPropertyCertificateKey,
                    out var cert) && cert.IsBytes)
            {
                try
                {
                    // Load certificate
                    Certificate?.Dispose();
                    Certificate = X509CertificateLoader.LoadPkcs12((byte[])cert!, ApiKey);
                    var now = _timeProvider.GetUtcNow().AddDays(1);
                    if (now < Certificate.NotAfter && Certificate.HasPrivateKey &&
                        Certificate.SubjectName.EnumerateRelativeDistinguishedNames()
                            .Any(a => a.GetSingleElementValue() == dnsName))
                    {
                        var renewalAfter = Certificate.NotAfter - now;
                        _logger.LogInformation(
                    "Using valid Certificate found in {Store} store (renewal in {Duration})...",
                            apiKeyStore.Name, renewalAfter);
                        _renewalTimer.Change(renewalAfter, Timeout.InfiniteTimeSpan);
                        // Done
                        return;
                    }
                    _logger.LogInformation(
                        "Certificate found in {Store} store has expired. Generate new...",
                        apiKeyStore.Name);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Provided Certificate invalid.");
                }
            }

            // Create new certificate
            var nowOffset = _timeProvider.GetUtcNow();
            var expiration = nowOffset.AddDays(kCertificateLifetimeDays);

            Certificate?.Dispose();
            Certificate = null;
            if (_workload != null)
            {
                try
                {
                    var certificates = await _workload.CreateServerCertificateAsync(
                        dnsName, expiration.Date).ConfigureAwait(false);

                    Debug.Assert(certificates.Count > 0);
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        using var certificate = certificates[0];
                        //
                        // https://github.com/dotnet/runtime/issues/45680)
                        // On Windows the certificate in 'result' gives an error
                        // when used with kestrel: "No credentials are available"
                        //
                        Certificate = X509CertificateLoader.LoadCertificate(
                            certificate.Export(X509ContentType.Pkcs12));
                    }
                    else
                    {
                        Certificate = certificates[0];
                    }

                    if (!Certificate.HasPrivateKey)
                    {
                        Certificate.Dispose();
                        Certificate = null;
                        _logger.LogWarning(
                            "Failed to get certificate with private key using workload API.");
                    }
                    else
                    {
                        _logger.LogInformation(
                            "Using server certificate with private key from workload API...");
                    }
                }
                catch (NotSupportedException nse)
                {
                    _logger.LogWarning("Not supported: {Message}. " +
                        "Unable to use workload API to obtain the certificate!", nse.Message);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Failed to create certificate using workload API.");
                }
            }
            if (Certificate == null)
            {
                using var ecdsa = ECDsa.Create();
                var req = new CertificateRequest("DC=" + dnsName, ecdsa, HashAlgorithmName.SHA256);
                var san = new SubjectAlternativeNameBuilder();
                san.AddDnsName(dnsName);
                var altDns = _identity?.ModuleId ?? _identity?.DeviceId;
                if (!string.IsNullOrEmpty(altDns) &&
                    !string.Equals(altDns, dnsName, StringComparison.OrdinalIgnoreCase))
                {
                    san.AddDnsName(altDns);
                }
                req.CertificateExtensions.Add(san.Build());
                Certificate = req.CreateSelfSigned(DateTimeOffset.Now, expiration);
                Debug.Assert(Certificate.HasPrivateKey);
                _logger.LogInformation("Created self-signed ECC server certificate...");
            }

            Debug.Assert(_stores.Count > 0);
            Debug.Assert(ApiKey != null);
            apiKeyStore ??= _stores[0];

            var pfxCertificate = Certificate.Export(X509ContentType.Pfx, ApiKey);
            apiKeyStore.State.AddOrUpdate(OpcUa.Constants.TwinPropertyCertificateKey, pfxCertificate);

            var renewalDuration = Certificate.NotAfter - nowOffset.Date - TimeSpan.FromDays(1);
            _renewalTimer.Change(renewalDuration, Timeout.InfiniteTimeSpan);

            _logger.LogInformation(
                "Stored new Certificate in {Store} store (and scheduled renewal after {Duration}).",
                apiKeyStore.Name, renewalDuration);
            _certificateRenewals++;
        }