using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Json; using System.Runtime; using System.Runtime.ConstrainedExecution; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace EVCB_OCPP.WSServer.Service { public class CertificateService { public CertificateService( ServerMessageService messageService, IConfiguration configuration, ILogger logger) { _serverUrl = configuration["CertificateServerUrl"]; _cpon = configuration["ChargingPointOperator"]; this.messageService = messageService; this.logger = logger; } private readonly string _serverUrl; private readonly string _cpon; private readonly ServerMessageService messageService; private readonly ILogger logger; public async Task SignCertificate(string chargeBoxId, string csr) { HttpClient client = new HttpClient(); client.BaseAddress = new Uri(_serverUrl); var signResult = await client.PostAsJsonAsync("cert/csr", new { csr = csr }); if (!signResult.IsSuccessStatusCode) { logger.LogWarning("{chargeBoxId} csr failed {csr}", chargeBoxId, csr); return; } var crt = await signResult.Content.ReadAsStringAsync(); await messageService.SendCertificateSignedRequest(chargeBoxId, crt); client.Dispose(); } public Task CheckClientCertificate(string chargeboxId, X509Certificate2 cert) { return CheckClientCertificate(chargeboxId, cert.ExportCertificatePem()); } public async Task CheckClientCertificate(string chargeboxId, string certString) { var subject = GetCertificateSubject(certString); logger.LogInformation("{chargeboxId} with cert subject {subject}", chargeboxId, subject); if (string.IsNullOrEmpty(subject)) { return -1; } var crtInfo = SubjectToDictionary(subject); if (crtInfo == null || //!crtInfo.ContainsKey("O") || //crtInfo["O"] != _cpon || !crtInfo.ContainsKey("CN") || crtInfo["CN"] != chargeboxId) { return -1; } int certServerResult = await CheckClientCertificateRca(certString); logger.LogInformation("{chargeboxId} with cert authenticate {subject}", chargeboxId, certServerResult); return certServerResult; } public async Task CheckClientCertificateRca(string certString) { using HttpClient client = new HttpClient(); client.BaseAddress = new Uri(_serverUrl); var result = await client.PutAsJsonAsync("cert/crt", new { crt = certString }); if (!result.IsSuccessStatusCode) { return -1; } var resultContentString = await result.Content.ReadAsStringAsync(); return Convert.ToInt32(resultContentString); } public Dictionary SubjectToDictionary(string subject) { try { MatchCollection regexResult = Regex.Matches(subject, "([a-zA-Z]*)=([a-zA-Z0-9]*)"); if (regexResult.Count == 0) { return null; } return regexResult.Where(x => x.Success == true && x.Groups.Count == 3).ToDictionary(x => x.Groups[1].Value, x => x.Groups[2].Value); } catch (Exception e) { logger.LogCritical(e.Message); logger.LogCritical(e.StackTrace); return null; } } public string GetCertificateSubject(string crt) { try { byte[] bytes = Encoding.ASCII.GetBytes(crt); var clientCertificate = new X509Certificate2(bytes); return clientCertificate.Subject; } catch { return null; } } public string GetCertificateRequestSubject(string csrString) { try { var csr = CertificateRequest.LoadSigningRequestPem(csrString, HashAlgorithmName.SHA512); var test = csr.SubjectName.Name; return test; } catch { return null; } } } }