BouncyCastle undefined length ASN1
Asked Answered
S

2

8

I try to get a X509Certificate2 from a BountyCastle X509Certificate and a PKCS12. I use the following code:

 certificate = new X509Certificate2(rawData, password, storageFlags);

I generate the rawData, like the following:

using (MemoryStream pfxData = new MemoryStream())
{
   X509CertificateEntry[] chain = new X509CertificateEntry[1];

   chain[0] = new X509CertificateEntry(x509);
   pkcsStore.SetKeyEntry(applicationName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain);
   pkcsStore.Save(pfxData, passcode.ToCharArray(), random);
   var rawData = pfx.ToArray();
}

The problem is, that I get the following exception:

enter image description here

After some days of researching, I figured out, that the problem is based on the Mono implementation of ASN1. This implementation doesn't allow "Undefined length encoding". If I use the code on Windows it works great.

My question

Is there any way, to convert the pfxData stream to a valid ASN1 structure?

I have tried it with the following code:

Asn1InputStream asn1InputStream = new Asn1InputStream(pfxData);
var asn1Object = asn1InputStream.ReadObject();

MemoryStream memoryStream = new MemoryStream();
new Asn1OutputStream((Stream)memoryStream).WriteObject(asn1Object);
var asn1ByteArray = memoryStream.ToArray();

certificate = new X509Certificate2(asn1ByteArray);

But with this code, I get the following exception:

"Index was out of range. Must be non-negative and less than the size of the collection.\nParameter name: startIndex"

I use Xamarin PCL with .NET Standard 1.3 and I can only use the "Portable.BouncyCastle" Nuget package.

UPDATE Exception Stack Trace (Converting BER to DER):

05-28 15:19:54.895 D/Mono    ( 3808): Assembly Ref addref Mono.Security[0x9b4fe080] -> System[0xac8de400]: 17
05-28 15:19:54.957 I/mono-stdout( 3808): System.AggregateException: One or more errors occurred. ---> System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
System.AggregateException: One or more errors occurred. ---> System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex
  at System.String.IndexOf (System.String value, System.Int32 startIndex, System.Int32 count, System.StringComparison comparisonType) [0x0002a] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.String.IndexOf (System.String value, System.Int32 startIndex, System.StringComparison comparisonType) [0x00009] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.String.IndexOf (System.String value, System.Int32 startIndex) [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
  at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00014] in <2940be14d5a1446694e2193e9029b558>:0 
   --- End of inner exception stack trace ---
  at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x0002f] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.958 I/mono-stdout( 3808): Parameter name: startIndex
  at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x0000b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
   --- End of inner exception stack trace ---
  at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00031] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.958 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex, System.Int32 count, System.StringComparison comparisonType) [0x0002a] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert) [0x003b5] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:517 
05-28 15:19:54.958 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex, System.StringComparison comparisonType) [0x00009] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] serverDomainNames, System.UInt16 keySize, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits) [0x00001] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:318 
  at APP.Models.Services.ACommunicationService+<ACommunicationServiceAsync>d__18.MoveNext () [0x00972] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:214 
   --- End of inner exception stack trace ---
05-28 15:19:54.959 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex) [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Threading.Tasks.Task.Wait () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at APP.Models.Services.ACommunicationService..ctor (PCLStorage.IFolder rootFolder) [0x00010] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:46 
05-28 15:19:54.959 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.959 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00014] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.959 I/mono-stdout( 3808):    --- End of inner exception stack trace ---
05-28 15:19:54.959 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x0002f] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.959 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x0000b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
---> (Inner Exception #0) System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
05-28 15:19:54.961 I/mono-stdout( 3808):    --- End of inner exception stack trace ---
05-28 15:19:54.961 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00031] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.961 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.962 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.962 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
Parameter name: startIndex
05-28 15:19:54.963 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert) [0x003b5] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:517 
05-28 15:19:54.963 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] serverDomainNames, System.UInt16 keySize, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits) [0x00001] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:318 
05-28 15:19:54.964 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService+<ACommunicationServiceAsync>d__18.MoveNext () [0x00972] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:214 
05-28 15:19:54.964 I/mono-stdout( 3808):    --- End of inner exception stack trace ---
05-28 15:19:54.965 I/mono-stdout( 3808):   at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <d18287e1d683419a8ec3216fd78947b9>:0 
05-28 15:19:54.965 I/mono-stdout( 3808):   at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <d18287e1d683419a8ec3216fd78947b9>:0 
05-28 15:19:54.965 I/mono-stdout( 3808):   at System.Threading.Tasks.Task.Wait () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.String.IndexOf (System.String value, System.Int32 startIndex, System.Int32 count, System.StringComparison comparisonType) [0x0002a] in <d18287e1d683419a8ec3216fd78947b9>:0 
05-28 15:19:54.965 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService..ctor (PCLStorage.IFolder rootFolder) [0x00010] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:46 
05-28 15:19:54.966 I/mono-stdout( 3808): ---> (Inner Exception #0) System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
05-28 15:19:54.966 I/mono-stdout( 3808): Parameter name: startIndex
05-28 15:19:54.967 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex, System.Int32 count, System.StringComparison comparisonType) [0x0002a] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.String.IndexOf (System.String value, System.Int32 startIndex, System.StringComparison comparisonType) [0x00009] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.String.IndexOf (System.String value, System.Int32 startIndex) [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
  at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00014] in <2940be14d5a1446694e2193e9029b558>:0 
   --- End of inner exception stack trace ---
  at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x0002f] in <2940be14d5a1446694e2193e9029b558>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x0000b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
   --- End of inner exception stack trace ---
  at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certif
icates.X509KeyStorageFlags keyStorageFlags) [0x00031] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, 
System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert) [0x003b5] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:517 
  at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] serverDomainNames, System.UInt16 keySize, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits) [0x00001] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:318 
  at APP.Models.Services.ACommunicationService+<ACommunicationServiceAsync>d__18.MoveNext () [0x00972] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:214 <---
05-28 15:19:54.968 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex, System.StringComparison comparisonType) [0x00009] in <d18287e1d683419a8ec3216fd78947b9>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):   at System.String.IndexOf (System.String value, System.Int32 startIndex) [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00014] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):    --- End of inner exception stack trace ---
05-28 15:19:54.969 I/mono-stdout( 3808):   at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x0002f] in <2940be14d5a1446694e2193e9029b558>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x0000b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.969 I/mono-stdout( 3808):    --- End of inner exception stack trace ---
05-28 15:19:54.969 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00031] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.970 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.970 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.970 I/mono-stdout( 3808):   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
05-28 15:19:54.970 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert) [0x003b5] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:517 
05-28 15:19:54.971 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService.CreateCertificate (System.String storeType, System.String storePath, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] serverDomainNames, System.UInt16 keySize, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits) [0x00001] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:318 
05-28 15:19:54.971 I/mono-stdout( 3808):   at APP.Models.Services.ACommunicationService+<ACommunicationServiceAsync>d__18.MoveNext () [0x00972] in C:\projects\APP - Kopie\APP_XamarinApplication\APP\APP\APP\Models\Services\ACommunicationService.cs:214 <---

EDIT: I have posted the same question in BouncyCastle GitHub: BouncyCastle GitHub

EDIT 2: I have tested to save the PKCS and create a X509Certificate2 with string constructor, like the following:

var pkcsPath = pkcsStorePath + "/pkcs.p12";
File.WriteAllBytes(pkcsPath, pfxData.ToArray());

// Exception is thrown on this line (Undefined length):
certificate = new X509Certificate2(pkcsPath, string.Empty);

Edit 3: I have found the method var util = Pkcs12Utilities.ConvertToDefiniteLength(pfxData.ToArray(), certPassword.ToCharArray()); in the BouncyCastle library and if I use this method right before the File.WriteAllBytes(pkcsPath, util); line, the exception "Undefined length encoding." is gone. But now, I get the following exception:

06-01 21:05:54.903 I/mono-stdout(31001): System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate.
System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate.
  at Mono.Security.X509.X509Certificate.Parse (System.Byte[] data) [0x0003b] in <2940be14d5a1446694e2193e9029b558>:0 
   --- End of inner exception stack trace ---
  at Mono.Security.X509.X509Certificate.Parse (System.Byte[] data) [0x00322] in <2940be14d5a1446694e2193e9029b558>:0 
  at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
06-01 21:05:54.905 I/mono-stdout(31001):   at Mono.Security.X509.X509Certificate.Parse (System.Byte[] data) [0x0003b] in <2940be14d5a1446694e2193e9029b558>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00041] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData, System.String password) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
  at Pkcs12TestProject.MyClass.CreateCertific
ate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert, System.String pkcsStorePath) [0x00377] in C:\OneDrive\VS\Pkcs12TestProject\Pkcs12TestProject\Pkcs12TestProject\MyClass.cs:223 
06-01 21:05:54.906 I/mono-stdout(31001):    --- End of inner exception stack trace ---
06-01 21:05:54.906 I/mono-stdout(31001):   at Mono.Security.X509.X509Certificate.Parse (System.Byte[] data) [0x00322] in <2940be14d5a1446694e2193e9029b558>:0 
06-01 21:05:54.906 I/mono-stdout(31001):   at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00030] in <2940be14d5a1446694e2193e9029b558>:0 
06-01 21:05:54.906 I/mono-stdout(31001):   at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00041] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
06-01 21:05:54.906 I/mono-stdout(31001):   at System.Security.Cryptography.X509Certificates.X509Helper2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Boolean disableProvider) [0x00020] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
06-01 21:05:54.906 I/mono-stdout(31001):   at System.Security.Cryptography.X509Certificates.X509Certificate2.Import (System.Byte[] rawData, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
06-01 21:05:54.907 I/mono-stdout(31001):   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Byte[] rawData, System.String password) [0x00011] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
06-01 21:05:54.907 I/mono-stdout(31001):   at Pkcs12TestProject.MyClass.CreateCertificate (System.String storeType, System.String storePath, System.String password, System.String applicationUri, System.String applicationName, System.String subjectName, System.Collections.Generic.IList`1[T] domainNames, System.UInt16 keySize, System.DateTime startTime, System.UInt16 lifetimeInMonths, System.UInt16 hashSizeInBits, System.Boolean isCA, System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCAKeyCert, System.String pkcsStorePath) [0x00377] in C:\OneDrive\VS\Pkcs12TestProject\Pkcs12TestProject\Pkcs12TestProject\MyClass.cs:223 

Edit 4: If I use the X509 certificate from BountyCastle as rawdata in the X509Certificate2 method, it works great! But it is without the private key..

Sn answered 27/5, 2017 at 21:8 Comment(10)
Indefinite length is not allowed in DER (DER is more restricted subset of BER).Gabriellia
Thank you, but how can I use your hint in c#?Sn
Do you have a DotNetUtilities class from Bouncy Castle available? It can convert bouncy cert to .Net cert, than you can use .Net cert to create X509Certificate2Jaffe
I can't use DotNetUtilities. But if I try to create a X509Certificate2 from a BC X509Certificate, it works great. Only if I add the PKCS stream, which contains the private key and the X509certificate, I get this error.Sn
If it were possible, to use the DotNetUtilities, then I could create a .Net cert and add it to the Mono.Security PKCS12. Because if I use the Mono PKCS12, it works great. But the problem is, that I have a BC X509 cert.Sn
Can you share the full exception stack trace from after attempting to convert the BER to DER?Fakery
Of course, I have added the full exception stack trace to the question.Sn
@bartonjs: I have set a bounty for my question, to motivate you. ;)Sn
I'm trying to replicate your environment... it's going slowly :). I'm wondering if you ended up with Base64, or something. It also seems like Mono doesn't load PFX through the byte[] ctor which doesn't take a password.Fakery
@Fakery There seems to be a workaround that you can use the ctor with byte[] and string.empty (byte[], string) if you don't have a password which would work better than the ctor with only byte[].Envious
E
5

I found some bugreports on your problem with possible workarounds outlined. I don't have an appropriate environment to test this myself - sorry. But from the history it looks like it hasn't really been resolved:

  1. Bugreport:

This explicitly states problems with BouncyCastle just like you experience. Sebastian Pouliot posts a sample code in comment3 that he thinks can be used (or parts of it) to work around the problem using mono.security.dll. I don't know if your usecase allows to use it. It is shipped with MonoDroid.
He goes into details in this comment and has the example code linked on github: https://github.com/mono/mono/blob/master/mcs/tools/security/makecert.cs

  1. There is also someone else who posted a problem with this. BouncyCastle is not explicitly mentioned: http://lists.ximian.com/pipermail/mono-bugs/2010-October/104908.html

His workaround at the end of post:
[Once you have the correct PKCS#12] Quote:

Write the byte[] PKCS#12 into a temporary file and load it with string constructor.


Update on source provided in comments

Hope my system worked correctly as it took hours to get it running. But then I got the following working.

The solution is to change the StoreBuilder to UseDEREncoding to true

Small bugfix up front
Finding: You put in a string.empty as password but protected the cert with a password. I think this is not correct. If I put in the password I get the first error again CryptographicException Certificate cannot be coded to valid certificate.

So first I changed this:

certificate = new X509Certificate2(pkcsPath, string.Empty);

to

certificate = new X509Certificate2(pkcsPath, certPassword);

Fix
And now I don't know if this is what you want but after changing it I didn't get an exception but a certificate object.

The complete changes of the "using memory stream" block finally looked like this:

using (MemoryStream pfxData = new MemoryStream())
{
    // **Change 1**: The DER Encoding is enabled on the
    // store builder
    Pkcs12StoreBuilder builder = new Pkcs12StoreBuilder();
    builder.SetUseDerEncoding(true);
    Pkcs12Store pkcsStore = builder.Build();
    // change - end

    X509CertificateEntry[] chain = new X509CertificateEntry[1];
    string certPassword = Guid.NewGuid().ToString();
    chain[0] = new X509CertificateEntry(x509);
    pkcsStore.SetKeyEntry(applicationName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain);
    pkcsStore.Save(pfxData, certPassword.ToCharArray(), random);

    var pkcsPath = pkcsStorePath + "/pkcs.p12";

    File.WriteAllBytes(pkcsPath, pfxData.ToArray());

    // **Change 2**: Use certificate password
    certificate = new X509Certificate2(pkcsPath, certPassword);
    // **Change 3**: Possible to use array instead of filename
    // works as well. Just uncomment
    //certificate = new X509Certificate2(pfxData.ToArray(), certPassword);

}
Envious answered 31/5, 2017 at 14:29 Comment(6)
Thank you for your answer. 1. I have tried to use some code of the makecert.cs, but I can't compile it. The problem is, that the X509CertificateBuilder has some properties which are not available. For example: X509CertificateBuilder.SubjectPublicKey (Error: Reference to type 'AsymmetricAlgorithm' claims it is defined in 'mscorlib', but it could not be found) 2. It doesn't work for me. Perhaps, the PKCS#12 isn't correct!? I updated my question with the code to save the file and I have created a test project: 1drv.ms/u/s!Aq2x4hOwAC2nl5J9ZzkHXyB-2-DObwSn
@SeanStayn Looks like I need a Mac for that? and a VS2017? Can't get it to run as I don't have both of that. But one question from code reading: right before the exception line (215) you create a certPassword but you use string.empty in the ctor? Wouldn't that need to be the certPassword (your newGuid)?Envious
You don't need a mac, but you need the android sdk, xamarin, and so on.. You are right, in normal I enter the certPassword to that, but for trying, I changed it to string.Empty.Sn
@SeanStayn Updated my answer. Let me know if you cannot use this solution for some reason or its not working.Envious
You should change your name to hero! Thank you! :) It works perfectly!!!!!! :) The keything was your first change. You should make a hint in your answer, that 'builder.SetUseDerEncoding(true);' was the problem. :)Sn
Now if only SetUseDerEncoding(true) was the default it'd have saved a lot of trouble. I was finally about to have the time load up the solution and see what was what. Nice find, Uwe.Fakery
F
0

Part of the problem seems to be that Mono's X509Certificate2 byte[] constructors don't behave the same as .NET Framework's X509Certificate2 byte[] constructors.

Browsing through the mono source it looks like X509Certificate2(byte[]) will try to load as a X.509 (individual) certificate, then as a PFX with a null (vs empty) password.

What has me the most confused about your callstack, and I was hoping to reproduce, is that it tried a PEM decode... which should only happen when the first byte isn't 0x30 (per the source), but 0x30 should be the first byte of the PFX as well. (Then there's their mishandling of not finding -----BEGIN CERTIFICATE----- resulting in the ArgumentOutOfRangeException which sent me down a bad path. Oh, well.)

The .NET Framework implementation of new X509Certificate2(byte[]) is more flexible:

  • X.509 DER
  • X.509 PEM
  • PFX null password
  • PFX empty password
  • PKCS#7 SignedCms signer certificate
  • AuthentiCode signer certificate

(So Mono only tries half the things .NET Framework / .NET Core does)

Based on comments it seems like you are using a PFX with an empty password, so changing your post-DER normalization call from

new X509Certificate2(asn1ByteArray)

to

new X509Certificate2(asn1ByteArray, string.Empty)

should solve this particular aspect of the problem.

Fakery answered 1/6, 2017 at 14:55 Comment(1)
Thank you for your answer. I'm using the password parameter with a real password and I've tried it with string.Empty, but the exception is still existing. I have created a test project with the code. The code is in the PCL in the MyClass.cs: 1drv.ms/u/s!Aq2x4hOwAC2nl5J9ZzkHXyB-2-DObwSn

© 2022 - 2024 — McMap. All rights reserved.