Skip to content

Commit 841279e

Browse files
authored
Merge pull request #1415 from PepperDash/feat/use-bouncycastle
Feat/use bouncycastle
2 parents 1ecfca7 + 1b32761 commit 841279e

2 files changed

Lines changed: 59 additions & 41 deletions

File tree

src/PepperDash.Core/Logging/DebugWebsocketSink.cs

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
using WebSocketSharp;
99
using System.Security.Authentication;
1010
using WebSocketSharp.Net;
11-
using System.Security.Cryptography;
1211
using System.Security.Cryptography.X509Certificates;
1312
using System.IO;
13+
using Org.BouncyCastle.Asn1;
1414
using Org.BouncyCastle.Asn1.X509;
15+
using Org.BouncyCastle.Crypto;
16+
using Org.BouncyCastle.Crypto.Generators;
17+
using Org.BouncyCastle.Crypto.Operators;
18+
using Org.BouncyCastle.Math;
19+
using Org.BouncyCastle.Pkcs;
20+
using Org.BouncyCastle.Security;
21+
using Org.BouncyCastle.X509;
1522
using Serilog.Formatting;
1623
using Serilog.Formatting.Json;
1724

@@ -114,51 +121,62 @@ private static void CreateCert()
114121
var subjectName = string.Format("CN={0}.{1}", hostName, domainName);
115122
var fqdn = string.Format("{0}.{1}", hostName, domainName);
116123

117-
using (var rsa = RSA.Create(2048))
124+
var random = new SecureRandom();
125+
126+
// Generate RSA 2048 key pair
127+
var keyPairGenerator = new RsaKeyPairGenerator();
128+
keyPairGenerator.Init(new KeyGenerationParameters(random, 2048));
129+
var keyPair = keyPairGenerator.GenerateKeyPair();
130+
131+
// Build certificate
132+
var certGenerator = new X509V3CertificateGenerator();
133+
certGenerator.SetSerialNumber(BigInteger.ValueOf(Math.Abs(DateTime.UtcNow.Ticks)));
134+
certGenerator.SetIssuerDN(new X509Name(subjectName));
135+
certGenerator.SetSubjectDN(new X509Name(subjectName));
136+
certGenerator.SetNotBefore(DateTime.UtcNow);
137+
certGenerator.SetNotAfter(DateTime.UtcNow.AddYears(2));
138+
certGenerator.SetPublicKey(keyPair.Public);
139+
140+
// Extended Key Usage: server + client auth
141+
certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false,
142+
new ExtendedKeyUsage(new[] { KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth }));
143+
144+
// Subject Alternative Names: DNS + IP
145+
System.Net.IPAddress parsedIp;
146+
if (System.Net.IPAddress.TryParse(ipAddress, out parsedIp))
118147
{
148+
certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false,
149+
new GeneralNames(new GeneralName[] {
150+
new GeneralName(GeneralName.DnsName, fqdn),
151+
new GeneralName(GeneralName.IPAddress, ipAddress)
152+
}));
153+
}
154+
else
155+
{
156+
certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false,
157+
new GeneralNames(new GeneralName(GeneralName.DnsName, fqdn)));
158+
}
119159

120-
var request = new CertificateRequest(
121-
subjectName,
122-
rsa,
123-
HashAlgorithmName.SHA256,
124-
RSASignaturePadding.Pkcs1);
125-
126-
// Subject Key Identifier
127-
request.CertificateExtensions.Add(
128-
new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
129-
130-
// Extended Key Usage: server + client auth
131-
request.CertificateExtensions.Add(
132-
new X509EnhancedKeyUsageExtension(
133-
new OidCollection
134-
{
135-
new Oid("1.3.6.1.5.5.7.3.1"), // id-kp-serverAuth
136-
new Oid("1.3.6.1.5.5.7.3.2") // id-kp-clientAuth
137-
},
138-
false));
139-
140-
// Subject Alternative Names: DNS + IP
141-
var sanBuilder = new SubjectAlternativeNameBuilder();
142-
sanBuilder.AddDnsName(fqdn);
143-
if (System.Net.IPAddress.TryParse(ipAddress, out var ip))
144-
sanBuilder.AddIpAddress(ip);
145-
request.CertificateExtensions.Add(sanBuilder.Build());
146-
147-
var notBefore = DateTimeOffset.UtcNow;
148-
var notAfter = notBefore.AddYears(2);
149-
150-
using (var cert = request.CreateSelfSigned(notBefore, notAfter))
151-
{
160+
// Sign with SHA256withRSA
161+
var signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keyPair.Private, random);
162+
var certificate = certGenerator.Generate(signatureFactory);
152163

153-
var separator = Path.DirectorySeparatorChar;
154-
var outputPath = string.Format("{0}user{1}{2}.pfx", separator, separator, _certificateName);
164+
// Export as PKCS12/PFX
165+
var pkcs12Store = new Pkcs12StoreBuilder().Build();
166+
var certEntry = new X509CertificateEntry(certificate);
167+
pkcs12Store.SetCertificateEntry(_certificateName, certEntry);
168+
pkcs12Store.SetKeyEntry(_certificateName, new AsymmetricKeyEntry(keyPair.Private), new[] { certEntry });
155169

156-
var pfxBytes = cert.Export(X509ContentType.Pfx, _certificatePassword);
157-
File.WriteAllBytes(outputPath, pfxBytes);
170+
var separator = Path.DirectorySeparatorChar;
171+
var outputPath = string.Format("{0}user{1}{2}.pfx", separator, separator, _certificateName);
158172

159-
CrestronConsole.PrintLine(string.Format("CreateCert: Certificate written to {0}", outputPath));
160-
}
173+
using (var ms = new MemoryStream())
174+
{
175+
pkcs12Store.Save(ms, _certificatePassword.ToCharArray(), random);
176+
File.WriteAllBytes(outputPath, ms.ToArray());
161177
}
178+
179+
CrestronConsole.PrintLine(string.Format("CreateCert: Certificate written to {0}", outputPath));
162180
}
163181
catch (Exception ex)
164182
{

src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public string SystemUuid
137137
"No system_url value defined in config. Checking for value from SIMPL Bridge."
138138
);
139139

140-
if (!string.IsNullOrEmpty(SystemUrl))
140+
if (string.IsNullOrEmpty(SystemUrl))
141141
{
142142
this.LogError(
143143
"No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control."

0 commit comments

Comments
 (0)