123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- diff --git a/EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll b/EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll
- index 42f3575..e8dce54 100644
- Binary files a/EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll and b/EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll differ
- diff --git a/EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs b/EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs
- index 1698606..0cb0fea 100644
- --- a/EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs
- +++ b/EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs
- @@ -72,6 +72,7 @@ public partial class ProfileHandler
- //private readonly IDbContextFactory<MeterValueDBContext> metervaluedbContextFactory;
- private readonly IBusinessServiceFactory businessServiceFactory;
- private readonly IMainDbService mainDbService;
- + private readonly CertificateService certService;
- private OuterHttpClient httpClient;
-
- public ProfileHandler(
- @@ -82,6 +83,7 @@ public partial class ProfileHandler
- MeterValueDbService meterValueDbService,
- IBusinessServiceFactory businessServiceFactory,
- IMainDbService mainDbService,
- + CertificateService certService,
- ILogger<ProfileHandler> logger,
- OuterHttpClient httpClient)
- {
- @@ -93,6 +95,7 @@ public partial class ProfileHandler
- this.webDbConnectionFactory = webDbConnectionFactory;
- this.meterValueDbService = meterValueDbService;
- this.mainDbService = mainDbService;
- + this.certService = certService;
- //this.metervaluedbContextFactory = metervaluedbContextFactory;
- this.businessServiceFactory = businessServiceFactory;
- this.httpClient = httpClient;
- diff --git a/EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs b/EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs
- index 96b07ba..cd277eb 100644
- --- a/EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs
- +++ b/EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs
- @@ -3,12 +3,20 @@ using EVCB_OCPP.Packet.Messages;
- using System;
- using Microsoft.Extensions.Logging;
- using EVCB_OCPP.WSServer.Service.WsService;
- +using EVCB_OCPP.Packet.Messages.RemoteTrigger;
- +using Microsoft.EntityFrameworkCore;
- +using EVCB_OCPP.Packet.Messages.Security;
- +using Microsoft.IdentityModel.Tokens;
- +using System.Runtime.ConstrainedExecution;
- +using System.Security.Cryptography.X509Certificates;
- +using System.Security.Cryptography;
- +using System.Text.RegularExpressions;
-
- namespace EVCB_OCPP.WSServer.Message
- {
- public partial class ProfileHandler
- {
- - internal MessageResult ExecuteSecurityRequest(Actions action, WsClientData session, IRequest request)
- + internal async Task<MessageResult> ExecuteSecurityRequest(Actions action, WsClientData session, IRequest request)
- {
- MessageResult result = new MessageResult() { Success = false };
-
- @@ -16,8 +24,68 @@ namespace EVCB_OCPP.WSServer.Message
- {
- switch (action)
- {
- + case Actions.SignCertificate:
- + {
- + SignCertificateRequest _request = request as SignCertificateRequest;
- + SignCertificateConfirmation confirm = new();
- +
- + if (string.IsNullOrEmpty(_request.csr))
- + {
- + result.Success = false;
- + return result;
- + }
-
- + bool isCsrValid = CheckCsr(session.ChargeBoxId, _request.csr);
- + if (!isCsrValid)
- + {
- + confirm.status = Packet.Messages.SubTypes.GenericStatusEnumType.Rejected;
- + result.Message = confirm;
- + result.Success = false;
- + return result;
- + }
- + _ = certService.SignCertificate(session.ChargeBoxId, _request.csr);
-
- + confirm.status = Packet.Messages.SubTypes.GenericStatusEnumType.Accepted;
- + result.Message = confirm;
- + result.Success = true;
- + return result;
- + }
- + case Actions.SecurityEventNotification:
- + {
- + SecurityEventNotificationRequest _request = request as SecurityEventNotificationRequest;
- + SecurityEventNotificationConfirmation confirm = new();
- +
- + logger.LogInformation("{chargeBoxId} security notification {sects} {sectype} {secmsg}", session.ChargeBoxId, _request.timestamp, _request.type, _request.techInfo);
- +
- + result.Message = confirm;
- + result.Success = true;
- + return result;
- + }
- + case Actions.LogStatusNotification:
- + {
- + LogStatusNotificationRequest _request = request as LogStatusNotificationRequest;
- + LogStatusNotificationConfirmation confirm = new();
- +
- + if (_request.status != Packet.Messages.SubTypes.UploadLogStatusEnumType.Idle)
- + {
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var item = await db.MachineOperateRecords.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.Action == "GetLog" && x.RequestType == 1)
- + .OrderByDescending(x => x.CreatedOn).FirstOrDefaultAsync();
- + if (item != null)
- + {
- + item.EvseStatus = (int)_request.status;
- + item.FinishedOn = DateTime.UtcNow;
- + }
- +
- + await db.SaveChangesAsync();
- + }
- +
- + }
- + result.Message = confirm;
- + result.Success = true;
- + return result;
- + }
- default:
- {
- logger.LogWarning(string.Format("Not Implement {0} Logic(ExecuteCoreRequest)", request.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
- @@ -37,13 +105,141 @@ namespace EVCB_OCPP.WSServer.Message
-
- return result;
- }
- - internal MessageResult ExecuteSecurityConfirm(Actions action, WsClientData session, IConfirmation confirm, string requestId)
- +
- + private bool CheckCsr(string chargeBoxId, string csrString)
- + {
- + string subject = certService.GetCertificateRequestSubject(csrString);
- + logger.LogInformation("{chargeBoxId} send scr {subject}", chargeBoxId, subject);
- + if (subject == null)
- + {
- + return false;
- + }
- +
- + Dictionary<string,string> csrInfo = certService.SubjectToDictionary(subject);
- + if (csrInfo == null ||
- + !csrInfo.ContainsKey("CN") ||
- + csrInfo["CN"] != chargeBoxId)
- + {
- + return false;
- + }
- + return true;
- + }
- +
- + internal async Task<MessageResult> ExecuteSecurityConfirm(Actions action, WsClientData session, IConfirmation confirm, string requestId)
- {
- MessageResult result = new MessageResult() { Success = false };
-
- switch (action)
- {
- -
- + case Actions.ExtendedTriggerMessage:
- + {
- + ExtendedTriggerMessageConfirmation _confirm = confirm as ExtendedTriggerMessageConfirmation;
- + //ExtendedTriggerMessageRequest _request = _confirm.GetRequest() as ExtendedTriggerMessageRequest;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- + case Actions.CertificateSigned:
- + {
- + CertificateSignedConfirmation _confirm = confirm as CertificateSignedConfirmation;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- + case Actions.GetInstalledCertificateIds:
- + {
- + GetInstalledCertificateIdsConfirmation _confirm = confirm as GetInstalledCertificateIdsConfirmation;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- + case Actions.DeleteCertificate:
- + {
- + DeleteCertificateConfirmation _confirm = confirm as DeleteCertificateConfirmation;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- + case Actions.InstallCertificate:
- + {
- + InstallCertificateConfirmation _confirm = confirm as InstallCertificateConfirmation;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- + case Actions.GetLog:
- + {
- + GetLogConfirmation _confirm = confirm as GetLogConfirmation;
- + using (var db = await maindbContextFactory.CreateDbContextAsync())
- + {
- + var operation = await db.MachineOperateRecords.Where(x => x.SerialNo == requestId &&
- + x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefaultAsync();
- + if (operation != null)
- + {
- + operation.FinishedOn = DateTime.UtcNow;
- + operation.Status = 1;//電樁有回覆
- + operation.EvseStatus = (int)_confirm.status;//OK
- + operation.EvseValue = _confirm.status.ToString();
- + await db.SaveChangesAsync();
- + }
- + }
- + }
- + break;
- default:
- {
- logger.LogWarning(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
- diff --git a/EVCB_OCPP.WSServer/Program.cs b/EVCB_OCPP.WSServer/Program.cs
- index a2b2b57..493bd08 100644
- --- a/EVCB_OCPP.WSServer/Program.cs
- +++ b/EVCB_OCPP.WSServer/Program.cs
- @@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Hosting;
- using EVCB_OCPP.WSServer.Service.WsService;
- using EVCB_OCPP.Service;
- using Microsoft.Extensions.Logging;
- +using System.Net.Security;
- +using System.Security.Cryptography.X509Certificates;
-
- namespace EVCB_OCPP.WSServer
- {
- @@ -51,11 +53,19 @@ namespace EVCB_OCPP.WSServer
- //services.AddTransient<BlockingTreePrintService>();
- //services.AddTransient<GoogleGetTimePrintService>();
- });
- + builder.WebHost.ConfigureKestrel(opt => {
- + opt.ConfigureHttpsDefaults(opt =>
- + {
- + opt.ClientCertificateMode = Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode.AllowCertificate;
- + opt.ClientCertificateValidation = ValidateClientCertficatel;
- + });
- + });
- var app = builder.Build();
- app.UseHeaderRecordService();
- app.UseOcppWsService();
- app.MapApiServce();
- app.Urls.Add("http://*:80");
- + app.Urls.Add("https://*:443");
- app.Run();
- }
-
- @@ -69,5 +79,10 @@ namespace EVCB_OCPP.WSServer
- }
- return timevalue;
- }
- +
- + private static bool ValidateClientCertficatel(X509Certificate2 clientCertificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
- + {
- + return true;
- + }
- }
- }
- diff --git a/EVCB_OCPP.WSServer/ProtalServer.cs b/EVCB_OCPP.WSServer/ProtalServer.cs
- index 4a5cebc..a16a7f8 100644
- --- a/EVCB_OCPP.WSServer/ProtalServer.cs
- +++ b/EVCB_OCPP.WSServer/ProtalServer.cs
- @@ -21,6 +21,8 @@ using System.Net;
- using System.Text;
- using EVCB_OCPP.WSServer.Service.WsService;
- using System.ServiceModel.Channels;
- +using EVCB_OCPP.Packet.Messages.RemoteTrigger;
- +using EVCB_OCPP.Packet.Messages.Security;
-
- namespace EVCB_OCPP.WSServer
- {
- @@ -697,6 +699,18 @@ namespace EVCB_OCPP.WSServer
- {
- session.IsCheckIn = true;
-
- + if (session.IsSignedByCPO == false)
- + {
- + var _request = new ExtendedTriggerMessageRequest()
- + {
- + requestedMessage = Packet.Messages.SubTypes.MessageTriggerEnumType.SignChargePointCertificate
- + };
- +
- + var uuid = session.queue.store(_request);
- + string rawRequest = BasicMessageHandler.GenerateRequest(uuid, _request.Action, _request);
- + SendMsg(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), "");
- + }
- +
- await messageService.SendGetEVSEConfigureRequest(session.ChargeBoxId);
-
- await messageService.SendChangeConfigurationRequest(
- @@ -831,7 +845,7 @@ namespace EVCB_OCPP.WSServer
- break;
- case "Security":
- {
- - var replyResult = profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message);
- + var replyResult = await profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message);
- if (replyResult.Success)
- {
- string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
- @@ -905,7 +919,7 @@ namespace EVCB_OCPP.WSServer
- break;
- case "Security":
- {
- - confirmResult = profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
- + confirmResult = await profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
- }
- break;
- default:
- diff --git a/EVCB_OCPP.WSServer/Service/CertificateService.cs b/EVCB_OCPP.WSServer/Service/CertificateService.cs
- new file mode 100644
- index 0000000..2f19f25
- --- /dev/null
- +++ b/EVCB_OCPP.WSServer/Service/CertificateService.cs
- @@ -0,0 +1,142 @@
- +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<CertificateService> 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<CertificateService> 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<int> CheckClientCertificate(string chargeboxId, X509Certificate2 cert)
- + {
- + return CheckClientCertificate(chargeboxId, cert.ExportCertificatePem());
- + }
- +
- + public async Task<int> 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<int> 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<string, string> 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;
- + }
- + }
- + }
- +}
- diff --git a/EVCB_OCPP.WSServer/Service/ServerMessageService.cs b/EVCB_OCPP.WSServer/Service/ServerMessageService.cs
- index 9a3b0e2..6379c21 100644
- --- a/EVCB_OCPP.WSServer/Service/ServerMessageService.cs
- +++ b/EVCB_OCPP.WSServer/Service/ServerMessageService.cs
- @@ -1,6 +1,9 @@
- using EVCB_OCPP.Packet.Features;
- using EVCB_OCPP.Packet.Messages.Core;
- using Microsoft.Extensions.Logging;
- +using static System.Runtime.InteropServices.JavaScript.JSType;
- +using System.ServiceModel.Channels;
- +using EVCB_OCPP.Packet.Messages.Security;
-
- namespace EVCB_OCPP.WSServer.Service;
-
- @@ -52,4 +55,16 @@ public class ServerMessageService
- }
- );
- }
- +
- + internal Task SendCertificateSignedRequest(string chargeBoxId, string crt)
- + {
- + return mainDbService.AddServerMessage(
- + ChargeBoxId: chargeBoxId,
- + OutAction: Actions.SignCertificate.ToString(),
- + OutRequest: new CertificateSignedRequest()
- + {
- + certificateChain = crt
- + }
- + );
- + }
- }
- diff --git a/EVCB_OCPP.WSServer/Service/WsService/OcppWebsocketService.cs b/EVCB_OCPP.WSServer/Service/WsService/OcppWebsocketService.cs
- index ba1df1c..8cd38ae 100644
- --- a/EVCB_OCPP.WSServer/Service/WsService/OcppWebsocketService.cs
- +++ b/EVCB_OCPP.WSServer/Service/WsService/OcppWebsocketService.cs
- @@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using System.Net.WebSockets;
- +using System.Security.Cryptography.X509Certificates;
- using System.Text;
-
- namespace EVCB_OCPP.WSServer.Service.WsService;
- @@ -13,6 +14,7 @@ public static partial class AppExtention
- {
- public static void AddOcppWsServer(this IServiceCollection services)
- {
- + services.AddTransient<CertificateService>();
- services.AddTransient<WsClientData>();
- services.AddSingleton<OcppWebsocketService>();
- }
- @@ -45,6 +47,7 @@ public class OcppWebsocketService : WebsocketService<WsClientData>
-
- private readonly IConfiguration configuration;
- private readonly IMainDbService mainDbService;
- + private readonly CertificateService certificateService;
- private readonly ILogger<OcppWebsocketService> logger;
-
- private readonly QueueSemaphore handshakeSemaphore;
- @@ -53,11 +56,13 @@ public class OcppWebsocketService : WebsocketService<WsClientData>
- IConfiguration configuration,
- IServiceProvider serviceProvider,
- IMainDbService mainDbService,
- + CertificateService certificateService,
- ILogger<OcppWebsocketService> logger
- ) : base(serviceProvider)
- {
- this.configuration = configuration;
- this.mainDbService = mainDbService;
- + this.certificateService = certificateService;
- this.logger = logger;
-
- handshakeSemaphore = new QueueSemaphore(5);
- @@ -182,11 +187,46 @@ public class OcppWebsocketService : WebsocketService<WsClientData>
- securityProfile = 0;
- }
-
- - if (securityProfile == 3 && session.UriScheme == "ws")
- + if (securityProfile == 3 )
- {
- - context.Response.StatusCode = StatusCodes.Status401Unauthorized;
- - logger.LogTrace("{id} {func} {Statuscode}", context.TraceIdentifier, nameof(ValidateHandshake), context.Response.StatusCode);
- - return false;
- + if (session.UriScheme == "ws")
- + {
- + context.Response.StatusCode = StatusCodes.Status401Unauthorized;
- + logger.LogTrace("{id} {func} {Statuscode}", context.TraceIdentifier, nameof(ValidateHandshake), context.Response.StatusCode);
- + return false;
- + }
- +
- + X509Certificate2 clientCertificate = null;
- + if (context.Request.Headers.ContainsKey("X-ARR-ClientCert"))
- + {
- + byte[] bytes = Encoding.ASCII.GetBytes(context.Request.Headers["X-ARR-ClientCert"]);
- + clientCertificate = new X509Certificate2(bytes);
- + }
- + if (context.Connection.ClientCertificate is not null)
- + {
- + clientCertificate = context.Connection.ClientCertificate;
- + }
- + if (clientCertificate is null)
- + {
- + clientCertificate = await context.Connection.GetClientCertificateAsync();
- + }
- + if (clientCertificate == null)
- + {
- + context.Response.StatusCode = StatusCodes.Status401Unauthorized;
- + logger.LogTrace("{id} {func} {Statuscode}", context.TraceIdentifier, nameof(ValidateHandshake), context.Response.StatusCode);
- + return false;
- + }
- +
- + int checkResult = await certificateService.CheckClientCertificate(session.ChargeBoxId, clientCertificate);
- + if (checkResult == -1)
- + {
- + context.Response.StatusCode = StatusCodes.Status401Unauthorized;
- + logger.LogTrace("{id} {func} {Statuscode}", context.TraceIdentifier, nameof(ValidateHandshake), context.Response.StatusCode);
- + return false;
- + }
- +
- + session.IsSignedByCPO = checkResult == 0;
- + return true;
- }
-
- if (securityProfile == 1 || securityProfile == 2)
- diff --git a/EVCB_OCPP.WSServer/Service/WsService/WsClientData.cs b/EVCB_OCPP.WSServer/Service/WsService/WsClientData.cs
- index 30b3365..486eaa3 100644
- --- a/EVCB_OCPP.WSServer/Service/WsService/WsClientData.cs
- +++ b/EVCB_OCPP.WSServer/Service/WsService/WsClientData.cs
- @@ -74,6 +74,7 @@ public class WsClientData : WsSession
- public string CustomerName { get; set; }
-
- public string StationId { set; get; }
- + public bool? IsSignedByCPO { set; get; } = null;
-
- public event EventHandler<string> m_ReceiveData;
-
- diff --git a/EVCB_OCPP.WSServer/appsettings.json b/EVCB_OCPP.WSServer/appsettings.json
- index b52e084..8e7b622 100644
- --- a/EVCB_OCPP.WSServer/appsettings.json
- +++ b/EVCB_OCPP.WSServer/appsettings.json
- @@ -4,6 +4,7 @@
- "LocalAuthAPI": "",
- "apipass": "12345678",
- "LogProvider": "NLog",
- + "CertificateServerUrl": "http://localhost:81/",
- "OCPP20_WSUrl": "ws://ocpp.phihong.com.tw:5004",
- "OCPP20_WSSUrl": "ws://ocpp.phihong.com.tw:5004",
- "MaintainMode": 0,
|