diff --git a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs
index 8986fcb4..99910ec9 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,26 +257,12 @@ 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;
-
- 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;
-
- return cert;
+ store.Save(ms, passwordChars, new SecureRandom());
+ return new X509Certificate2(ms.ToArray(), certPassword);
}
}
}
@@ -285,8 +270,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..c05e0cb6 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,15 @@ 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 LoginResponse
+ { UserName = token.UserName,
+ Password = token.Password,
+ 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 +130,45 @@ 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 password.
+ ///
+ public string Password { 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