Creating a X509Certificate2 instance from a byte array works on Windows but fails on Linux with a "CryptographicException".
static void Main(string[] args)
{
var cert = new X509Certificate2(Cert.CertBytes);
}
On Windows: Valid X509Certificate2 instance is created On Linux: An exception is thrown:
{System.Security.Cryptography.CryptographicException: Cannot find the
original signer.
at Internal.Cryptography.Pal.PkcsFormatReader.TryReadPkcs7(SafePkcs7Handle pkcs7, Boolean single, ICertificatePal& certPal, List`1& certPals)
at Internal.Cryptography.Pal.PkcsFormatReader.TryReadPkcs7Der(Byte[] rawData, Boolean single, ICertificatePal& certPal, List`1& certPals)
at Internal.Cryptography.Pal.CertificatePal.FromBlob(Byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] data)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData)
at CertTest.Program.Main(String[] args) in /home/CertTest/Program.cs:line 14}
Am I doing something wrong? I assume that a certificate is a certificate, regardless of the OS on which it is parsed.
You find a valid X509 certificate which can be parsed on Windows but not Linux here: https://gist.github.com/secana/9c13f8fa495681f8a30adb5d8754450e
I tried multiple certificates, but none worked on Linux. I don't own a Mac so I couldn't test if it would work there.
Tested with .Net Core 2.0.2 on Ubuntu 16.04, Ubuntu 17.10, OpenSuse Tumbleweed, Windows 10
Since new X509Certficate2()
does not return the signing certificate under Linux like it does under Windows you have to parse the ASN.1 structure of the PKCS7 to find the signing certificate.
Example:
// Import all certificates in the structure into a collection
var collection = new X509Certificate2Collection();
collection.Import(Cert.CertBytes);
// Find the signing cert
var signingCert = collection.Cast<X509Certificate2>().FirstOrDefault(cert =>
string.Equals(cert.SerialNumber, SignerSerialNumber,
StringComparison.CurrentCultureIgnoreCase));
The only difficulty is to get the serial number of the signing cert. For that I've parsed the ASN.1 structure. The serial number is in the ASN.1 path 1/0/4/0/1/1
.
Example:
// Get signing cert serial number from ASN.1
var serialNumber = asn1[1][0][4][0][1][1];
As an ASN.1 parser I've used code from the Mono project, but there are several parser available on Nuget.