Skip to content

Commit 9cf02c6

Browse files
committed
Use bouncycastle for digital signing, to avoid requiring special windows permissions
1 parent 86b6af5 commit 9cf02c6

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

CorePush/Firebase/FirebaseSender.cs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2+
using System.IO;
23
using System.Net.Http;
3-
using System.Security.Cryptography;
44
using System.Text;
55
using System.Threading;
66
using System.Threading.Tasks;
@@ -9,6 +9,9 @@
99
using CorePush.Models;
1010
using CorePush.Serialization;
1111
using CorePush.Utils;
12+
using Org.BouncyCastle.Crypto.Signers;
13+
using Org.BouncyCastle.Crypto;
14+
using Org.BouncyCastle.OpenSsl;
1215

1316
namespace CorePush.Firebase;
1417

@@ -161,12 +164,36 @@ private string GetMasterToken()
161164
var unsignedJwtData = $"{headerBase64}.{payloadBase64}";
162165
var unsignedJwtBytes = Encoding.UTF8.GetBytes(unsignedJwtData);
163166

164-
using var rsa = RSA.Create();
165-
rsa.ImportFromPem(settings.PrivateKey.ToCharArray());
167+
var privateKey = ParsePKCS8PrivateKeyPem(settings.PrivateKey);
168+
ISigner signer = new RsaDigestSigner(new Org.BouncyCastle.Crypto.Digests.Sha256Digest());
169+
signer.Init(true, privateKey);
170+
signer.BlockUpdate(unsignedJwtBytes, 0, unsignedJwtBytes.Length);
166171

167-
var signature = rsa.SignData(unsignedJwtBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
172+
byte[] signature = signer.GenerateSignature();
168173
var signatureBase64 = Convert.ToBase64String(signature);
169174

170175
return $"{unsignedJwtData}.{signatureBase64}";
171176
}
177+
178+
private AsymmetricKeyParameter ParsePKCS8PrivateKeyPem(string key)
179+
{
180+
AsymmetricKeyParameter privateKey;
181+
using var keyReader = new StringReader(key);
182+
PemReader pemReader = new PemReader(keyReader);
183+
object pemObject = pemReader.ReadObject();
184+
185+
// PKCS#8 keys are typically returned as AsymmetricKeyParameter, not AsymmetricCipherKeyPair
186+
if (pemObject is AsymmetricKeyParameter keyParameter)
187+
{
188+
return privateKey = keyParameter;
189+
}
190+
else if (pemObject is AsymmetricCipherKeyPair keyPair) // handle case of key pair
191+
{
192+
return privateKey = keyPair.Private;
193+
}
194+
else
195+
{
196+
throw new InvalidOperationException("Invalid private key format.");
197+
}
198+
}
172199
}

0 commit comments

Comments
 (0)