using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; using System; using System.IO; using System.Security.Cryptography.X509Certificates; namespace StellaOps.Cryptography.Plugin.OpenSslGost; internal static class OpenSslPemLoader { public static ECPrivateKeyParameters LoadPrivateKey(string path, string? passphrase) { using var reader = File.OpenText(path); var pemReader = string.IsNullOrEmpty(passphrase) ? new PemReader(reader) : new PemReader(reader, new StaticPasswordFinder(passphrase)); var pemObject = pemReader.ReadObject(); return pemObject switch { AsymmetricCipherKeyPair pair when pair.Private is ECPrivateKeyParameters ecPrivate => ecPrivate, ECPrivateKeyParameters ecPrivate => ecPrivate, _ => throw new InvalidOperationException($"Unsupported private key content in '{path}'.") }; } public static ECPublicKeyParameters LoadPublicKey(ECPrivateKeyParameters privateKey, X509Certificate2? certificate) { if (certificate is not null) { var bouncyCert = DotNetUtilities.FromX509Certificate(certificate); var keyParam = bouncyCert.GetPublicKey(); if (keyParam is ECPublicKeyParameters ecPublic) { return ecPublic; } } var q = privateKey.Parameters.G.Multiply(privateKey.D).Normalize(); return new ECPublicKeyParameters(q, privateKey.Parameters); } public static X509Certificate2? LoadCertificate(string? path, string? passphrase) { if (string.IsNullOrWhiteSpace(path)) { return null; } if (string.Equals(Path.GetExtension(path), ".pem", StringComparison.OrdinalIgnoreCase)) { return X509Certificate2.CreateFromPemFile(path); } var password = string.IsNullOrEmpty(passphrase) ? null : passphrase; return string.IsNullOrEmpty(password) ? X509CertificateLoader.LoadPkcs12FromFile(path, ReadOnlySpan.Empty) : X509CertificateLoader.LoadPkcs12FromFile(path, password.AsSpan()); } private sealed class StaticPasswordFinder : IPasswordFinder { private readonly char[] password; public StaticPasswordFinder(string passphrase) => password = passphrase.ToCharArray(); public char[] GetPassword() => password; } }