diff --git a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs index 8986fcb4..eeba5772 100644 --- a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs +++ b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs @@ -15,12 +15,10 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Operators; -using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; -using System.Security.Cryptography; using Serilog.Formatting; using Serilog.Formatting.Json; @@ -244,9 +242,10 @@ namespace PepperDash.Core /// /// Loads a PKCS#12 file written by BouncyCastle and returns an with - /// private key attached via . - /// Using BouncyCastle's own reader avoids the .NET/Mono PFX parser, which can reject - /// BouncyCastle-generated archives on the Crestron runtime. + /// private key attached. + /// The PFX is parsed and re-encoded by BouncyCastle (ensuring format compatibility), then passed as + /// raw bytes to so neither RSACryptoServiceProvider nor the + /// EphemeralKeySet flag (unsupported on the Crestron/Mono runtime) is needed. /// private static X509Certificate2 LoadCertFromBouncyCastle(string certPath, string certPassword) { @@ -258,24 +257,16 @@ namespace PepperDash.Core var store = new Pkcs12StoreBuilder().Build(); store.Load(stream, passwordChars); - foreach (string alias in store.Aliases) + // Re-encode through BouncyCastle to guarantee PKCS#12 format compatibility, + // then hand raw bytes to X509Certificate2 — no RSACryptoServiceProvider needed. + using (var ms = new MemoryStream()) { - if (!store.IsKeyEntry(alias)) continue; + store.Save(ms, passwordChars, new SecureRandom()); + var cert = new X509Certificate2(ms.ToArray(), certPassword); - var keyEntry = store.GetKey(alias); - var certChain = store.GetCertificateChain(alias); - if (certChain == null || certChain.Length == 0) continue; - - // Build X509Certificate2 from raw DER — no PFX parsing by .NET needed. - var cert = new X509Certificate2(certChain[0].Certificate.GetEncoded()); - - // Attach the private key via RSACryptoServiceProvider (available on all target runtimes). - var rsaParams = DotNetUtilities.ToRSAParameters( - (RsaPrivateCrtKeyParameters)keyEntry.Key); - var rsa = new RSACryptoServiceProvider(); - rsa.PersistKeyInCsp = false; - rsa.ImportParameters(rsaParams); - cert.PrivateKey = rsa; + if (!cert.HasPrivateKey) + throw new InvalidOperationException( + string.Format("Certificate loaded from '{0}' does not contain a private key and cannot be used as a server certificate.", certPath)); return cert; } @@ -285,8 +276,6 @@ namespace PepperDash.Core { Array.Clear(passwordChars, 0, passwordChars.Length); } - - throw new InvalidOperationException("No key entry found in PKCS#12 store: " + certPath); } private void Start(int port, string certPath = "", string certPassword = "") diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoginRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoginRequestHandler.cs index 5a4b7df7..949f8bd5 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoginRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoginRequestHandler.cs @@ -1,5 +1,6 @@ using System; +using System.Collections.Generic; using Crestron.SimplSharp.CrestronAuthentication; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; @@ -91,7 +92,19 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; - context.Response.Write(JsonConvert.SerializeObject(new { Token = token }, Formatting.Indented), false); + context.Response.Write(JsonConvert.SerializeObject( + new + { + Token = new LoginResponse + { + UserName = token.UserName, + Access = token.Access, + State = token.State, + Groups = token.Groups, + ADConnect = token.ADConnect, + Valid = token.Valid + } + }, Formatting.Indented), false); context.Response.End(); } catch (System.Exception ex) @@ -121,4 +134,40 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers /// public string Password { get; set; } } + + /// + /// Represents a LoginResponse + /// + internal class LoginResponse + { + /// + /// Gets or sets the username. + /// + public string UserName { get; set; } + + /// + /// Gets or sets the access level. + /// + public Authentication.UserAuthenticationLevelEnum Access { get; set; } + + /// + /// Gets or sets the token authenticated state. + /// + public Authentication.eTokenAuthenticatedState State { get; set; } + + /// + /// Gets or sets the list of groups. + /// + public List Groups { get; set; } + + /// + /// Gets or sets the active directory connection flag. + /// + public int ADConnect { get; set; } + + /// + /// Gets or sets the valid flag indicating whether the token is valid. + /// + public bool Valid { get; set; } + } } \ No newline at end of file