mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-07-02 10:38:16 +00:00
Merge pull request #1418 from PepperDash/fix/devtools-fixex
Fix/devtools fixex
This commit is contained in:
commit
beb77ec468
2 changed files with 62 additions and 24 deletions
|
|
@ -15,12 +15,10 @@ using Org.BouncyCastle.Asn1.X509;
|
||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.Crypto.Generators;
|
using Org.BouncyCastle.Crypto.Generators;
|
||||||
using Org.BouncyCastle.Crypto.Operators;
|
using Org.BouncyCastle.Crypto.Operators;
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
|
||||||
using Org.BouncyCastle.Math;
|
using Org.BouncyCastle.Math;
|
||||||
using Org.BouncyCastle.Pkcs;
|
using Org.BouncyCastle.Pkcs;
|
||||||
using Org.BouncyCastle.Security;
|
using Org.BouncyCastle.Security;
|
||||||
using Org.BouncyCastle.X509;
|
using Org.BouncyCastle.X509;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using Serilog.Formatting;
|
using Serilog.Formatting;
|
||||||
using Serilog.Formatting.Json;
|
using Serilog.Formatting.Json;
|
||||||
|
|
||||||
|
|
@ -244,9 +242,10 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a PKCS#12 file written by BouncyCastle and returns an <see cref="X509Certificate2"/> with
|
/// Loads a PKCS#12 file written by BouncyCastle and returns an <see cref="X509Certificate2"/> with
|
||||||
/// private key attached via <see cref="RSACryptoServiceProvider"/>.
|
/// private key attached.
|
||||||
/// Using BouncyCastle's own reader avoids the .NET/Mono PFX parser, which can reject
|
/// The PFX is parsed and re-encoded by BouncyCastle (ensuring format compatibility), then passed as
|
||||||
/// BouncyCastle-generated archives on the Crestron runtime.
|
/// raw bytes to <see cref="X509Certificate2"/> so neither <c>RSACryptoServiceProvider</c> nor the
|
||||||
|
/// <c>EphemeralKeySet</c> flag (unsupported on the Crestron/Mono runtime) is needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static X509Certificate2 LoadCertFromBouncyCastle(string certPath, string certPassword)
|
private static X509Certificate2 LoadCertFromBouncyCastle(string certPath, string certPassword)
|
||||||
{
|
{
|
||||||
|
|
@ -258,24 +257,16 @@ namespace PepperDash.Core
|
||||||
var store = new Pkcs12StoreBuilder().Build();
|
var store = new Pkcs12StoreBuilder().Build();
|
||||||
store.Load(stream, passwordChars);
|
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);
|
if (!cert.HasPrivateKey)
|
||||||
var certChain = store.GetCertificateChain(alias);
|
throw new InvalidOperationException(
|
||||||
if (certChain == null || certChain.Length == 0) continue;
|
string.Format("Certificate loaded from '{0}' does not contain a private key and cannot be used as a server certificate.", certPath));
|
||||||
|
|
||||||
// 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;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
@ -285,8 +276,6 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
Array.Clear(passwordChars, 0, passwordChars.Length);
|
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 = "")
|
private void Start(int port, string certPath = "", string certPassword = "")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Crestron.SimplSharp.CrestronAuthentication;
|
using Crestron.SimplSharp.CrestronAuthentication;
|
||||||
using Crestron.SimplSharp.WebScripting;
|
using Crestron.SimplSharp.WebScripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -91,7 +92,19 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
context.Response.StatusDescription = "OK";
|
context.Response.StatusDescription = "OK";
|
||||||
context.Response.ContentType = "application/json";
|
context.Response.ContentType = "application/json";
|
||||||
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
|
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();
|
context.Response.End();
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
|
|
@ -121,4 +134,40 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a LoginResponse
|
||||||
|
/// </summary>
|
||||||
|
internal class LoginResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the username.
|
||||||
|
/// </summary>
|
||||||
|
public string UserName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the access level.
|
||||||
|
/// </summary>
|
||||||
|
public Authentication.UserAuthenticationLevelEnum Access { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the token authenticated state.
|
||||||
|
/// </summary>
|
||||||
|
public Authentication.eTokenAuthenticatedState State { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the list of groups.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Groups { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the active directory connection flag.
|
||||||
|
/// </summary>
|
||||||
|
public int ADConnect { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the valid flag indicating whether the token is valid.
|
||||||
|
/// </summary>
|
||||||
|
public bool Valid { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue