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
It is not an X509 certificate but some signed data (PKCS#7 format). Windows can export certificate in PKCS#7 format with other certificates in the certificate path. That is most likely your case. Try to rename it to p7b and open it in windows.
There are two certificates in the PKCS#7:
- CN=Microsoft Windows, Serial number: 330000016143159d469b7f968b000000000161, issued by Microsoft Windows Production PCA 2011
- CN=Microsoft Windows Production PCA 2011, Serial number: 61077656000000000008, issued by Microsoft Root Certificate Authority 2010
The PKCS#7 is signed with timestamp from Microsoft Time-Stamp PCA 2010.
Why does it work on windows but not on linux I don't know. File an issue here or try to debug it.
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.