260 lines
7.5 KiB
C#
260 lines
7.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using Org.BouncyCastle.Asn1;
|
|
using Org.BouncyCastle.Asn1.Cms;
|
|
using Org.BouncyCastle.Asn1.Pkcs;
|
|
using Org.BouncyCastle.Asn1.Sec;
|
|
using Org.BouncyCastle.Asn1.X509;
|
|
using Org.BouncyCastle.Asn1.X9;
|
|
using Org.BouncyCastle.Crypto;
|
|
using Org.BouncyCastle.Crypto.EC;
|
|
using Org.BouncyCastle.Crypto.Generators;
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Pkcs;
|
|
using Org.BouncyCastle.Security;
|
|
using Org.BouncyCastle.Utilities;
|
|
using Org.BouncyCastle.Utilities.Encoders;
|
|
using Org.BouncyCastle.Utilities.IO.Pem;
|
|
using Org.BouncyCastle.X509;
|
|
|
|
namespace Org.BouncyCastle.OpenSsl;
|
|
|
|
public class PemReader : Org.BouncyCastle.Utilities.IO.Pem.PemReader
|
|
{
|
|
private readonly IPasswordFinder pFinder;
|
|
|
|
static PemReader()
|
|
{
|
|
}
|
|
|
|
public PemReader(TextReader reader)
|
|
: this(reader, null)
|
|
{
|
|
}
|
|
|
|
public PemReader(TextReader reader, IPasswordFinder pFinder)
|
|
: base(reader)
|
|
{
|
|
this.pFinder = pFinder;
|
|
}
|
|
|
|
public object ReadObject()
|
|
{
|
|
PemObject pemObject = ReadPemObject();
|
|
if (pemObject == null)
|
|
{
|
|
return null;
|
|
}
|
|
if (Platform.EndsWith(pemObject.Type, "PRIVATE KEY"))
|
|
{
|
|
return ReadPrivateKey(pemObject);
|
|
}
|
|
switch (pemObject.Type)
|
|
{
|
|
case "PUBLIC KEY":
|
|
return ReadPublicKey(pemObject);
|
|
case "RSA PUBLIC KEY":
|
|
return ReadRsaPublicKey(pemObject);
|
|
case "CERTIFICATE REQUEST":
|
|
case "NEW CERTIFICATE REQUEST":
|
|
return ReadCertificateRequest(pemObject);
|
|
case "CERTIFICATE":
|
|
case "X509 CERTIFICATE":
|
|
return ReadCertificate(pemObject);
|
|
case "PKCS7":
|
|
case "CMS":
|
|
return ReadPkcs7(pemObject);
|
|
case "X509 CRL":
|
|
return ReadCrl(pemObject);
|
|
case "ATTRIBUTE CERTIFICATE":
|
|
return ReadAttributeCertificate(pemObject);
|
|
default:
|
|
throw new IOException("unrecognised object: " + pemObject.Type);
|
|
}
|
|
}
|
|
|
|
private AsymmetricKeyParameter ReadRsaPublicKey(PemObject pemObject)
|
|
{
|
|
RsaPublicKeyStructure instance = RsaPublicKeyStructure.GetInstance(Asn1Object.FromByteArray(pemObject.Content));
|
|
return new RsaKeyParameters(isPrivate: false, instance.Modulus, instance.PublicExponent);
|
|
}
|
|
|
|
private AsymmetricKeyParameter ReadPublicKey(PemObject pemObject)
|
|
{
|
|
return PublicKeyFactory.CreateKey(pemObject.Content);
|
|
}
|
|
|
|
private X509Certificate ReadCertificate(PemObject pemObject)
|
|
{
|
|
try
|
|
{
|
|
return new X509CertificateParser().ReadCertificate(pemObject.Content);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new PemException("problem parsing cert: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private X509Crl ReadCrl(PemObject pemObject)
|
|
{
|
|
try
|
|
{
|
|
return new X509CrlParser().ReadCrl(pemObject.Content);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new PemException("problem parsing cert: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private Pkcs10CertificationRequest ReadCertificateRequest(PemObject pemObject)
|
|
{
|
|
try
|
|
{
|
|
return new Pkcs10CertificationRequest(pemObject.Content);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new PemException("problem parsing cert: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private IX509AttributeCertificate ReadAttributeCertificate(PemObject pemObject)
|
|
{
|
|
return new X509V2AttributeCertificate(pemObject.Content);
|
|
}
|
|
|
|
private Org.BouncyCastle.Asn1.Cms.ContentInfo ReadPkcs7(PemObject pemObject)
|
|
{
|
|
try
|
|
{
|
|
return Org.BouncyCastle.Asn1.Cms.ContentInfo.GetInstance(Asn1Object.FromByteArray(pemObject.Content));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new PemException("problem parsing PKCS7 object: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private object ReadPrivateKey(PemObject pemObject)
|
|
{
|
|
string text = pemObject.Type.Substring(0, pemObject.Type.Length - "PRIVATE KEY".Length).Trim();
|
|
byte[] array = pemObject.Content;
|
|
IDictionary dictionary = Platform.CreateHashtable();
|
|
foreach (PemHeader header in pemObject.Headers)
|
|
{
|
|
dictionary[header.Name] = header.Value;
|
|
}
|
|
string text2 = (string)dictionary["Proc-Type"];
|
|
if (text2 == "4,ENCRYPTED")
|
|
{
|
|
if (pFinder == null)
|
|
{
|
|
throw new PasswordException("No password finder specified, but a password is required");
|
|
}
|
|
char[] password = pFinder.GetPassword();
|
|
if (password == null)
|
|
{
|
|
throw new PasswordException("Password is null, but a password is required");
|
|
}
|
|
string text3 = (string)dictionary["DEK-Info"];
|
|
string[] array2 = text3.Split(new char[1] { ',' });
|
|
string dekAlgName = array2[0].Trim();
|
|
byte[] iv = Hex.Decode(array2[1].Trim());
|
|
array = PemUtilities.Crypt(encrypt: false, array, password, dekAlgName, iv);
|
|
}
|
|
try
|
|
{
|
|
Asn1Sequence instance = Asn1Sequence.GetInstance(array);
|
|
AsymmetricKeyParameter publicParameter;
|
|
AsymmetricKeyParameter asymmetricKeyParameter;
|
|
switch (text)
|
|
{
|
|
case "RSA":
|
|
{
|
|
if (instance.Count != 9)
|
|
{
|
|
throw new PemException("malformed sequence in RSA private key");
|
|
}
|
|
RsaPrivateKeyStructure instance2 = RsaPrivateKeyStructure.GetInstance(instance);
|
|
publicParameter = new RsaKeyParameters(isPrivate: false, instance2.Modulus, instance2.PublicExponent);
|
|
asymmetricKeyParameter = new RsaPrivateCrtKeyParameters(instance2.Modulus, instance2.PublicExponent, instance2.PrivateExponent, instance2.Prime1, instance2.Prime2, instance2.Exponent1, instance2.Exponent2, instance2.Coefficient);
|
|
break;
|
|
}
|
|
case "DSA":
|
|
{
|
|
if (instance.Count != 6)
|
|
{
|
|
throw new PemException("malformed sequence in DSA private key");
|
|
}
|
|
DerInteger derInteger = (DerInteger)instance[1];
|
|
DerInteger derInteger2 = (DerInteger)instance[2];
|
|
DerInteger derInteger3 = (DerInteger)instance[3];
|
|
DerInteger derInteger4 = (DerInteger)instance[4];
|
|
DerInteger derInteger5 = (DerInteger)instance[5];
|
|
DsaParameters parameters = new DsaParameters(derInteger.Value, derInteger2.Value, derInteger3.Value);
|
|
asymmetricKeyParameter = new DsaPrivateKeyParameters(derInteger5.Value, parameters);
|
|
publicParameter = new DsaPublicKeyParameters(derInteger4.Value, parameters);
|
|
break;
|
|
}
|
|
case "EC":
|
|
{
|
|
ECPrivateKeyStructure instance3 = ECPrivateKeyStructure.GetInstance(instance);
|
|
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, instance3.GetParameters());
|
|
PrivateKeyInfo keyInfo = new PrivateKeyInfo(algorithmIdentifier, instance3.ToAsn1Object());
|
|
asymmetricKeyParameter = PrivateKeyFactory.CreateKey(keyInfo);
|
|
DerBitString publicKey = instance3.GetPublicKey();
|
|
if (publicKey != null)
|
|
{
|
|
SubjectPublicKeyInfo keyInfo2 = new SubjectPublicKeyInfo(algorithmIdentifier, publicKey.GetBytes());
|
|
publicParameter = PublicKeyFactory.CreateKey(keyInfo2);
|
|
}
|
|
else
|
|
{
|
|
publicParameter = ECKeyPairGenerator.GetCorrespondingPublicKey((ECPrivateKeyParameters)asymmetricKeyParameter);
|
|
}
|
|
break;
|
|
}
|
|
case "ENCRYPTED":
|
|
{
|
|
char[] password2 = pFinder.GetPassword();
|
|
if (password2 == null)
|
|
{
|
|
throw new PasswordException("Password is null, but a password is required");
|
|
}
|
|
return PrivateKeyFactory.DecryptKey(password2, EncryptedPrivateKeyInfo.GetInstance(instance));
|
|
}
|
|
case "":
|
|
return PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(instance));
|
|
default:
|
|
throw new ArgumentException("Unknown key type: " + text, "type");
|
|
}
|
|
return new AsymmetricCipherKeyPair(publicParameter, asymmetricKeyParameter);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
throw new PemException("problem creating " + text + " private key: " + ex2.ToString());
|
|
}
|
|
}
|
|
|
|
private static X9ECParameters GetCurveParameters(string name)
|
|
{
|
|
X9ECParameters byName = CustomNamedCurves.GetByName(name);
|
|
if (byName == null)
|
|
{
|
|
byName = ECNamedCurveTable.GetByName(name);
|
|
}
|
|
if (byName == null)
|
|
{
|
|
throw new Exception("unknown curve name: " + name);
|
|
}
|
|
return byName;
|
|
}
|
|
}
|