When generating ECDSA certificate got persistent error with Xamarin iOS, but same code works perfectly on Windows 10.
Exception message: "Unable to decode certificate."
{System.Security.Cryptography.CryptographicException: Unable to decode certificate.
at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono..ctor (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Securit…}
var convertedCertificate =
new X509Certificate2(stream.ToArray(),
password,
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
This trow an exception "unable to decode certicate"
Full code
`using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FO_Framework;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509.Extension;
using B = Org.BouncyCastle;
using System.Security.Cryptography.X509Certificates;
namespace XamarinFormLib.Framework
{
public class BugX509Certificate
{
private const string FriendlyName = "Certificat A";
public void Run()
{
String CN = "1234567890";
String O = "ABC-9999-ABC";
String OU = "1234567890AB1234";
String SN = FriendlyName;
String GN = "AA9999";
String L = TimeZoneInfo.Local.BaseUtcOffset.ToString().Substring(0, 6);
String S = "ON";
String C = "CA";
GenerateCertificate(CN, O, SN, OU, GN, L, S, C);
}
private X509Certificate2 GenerateCertificate(string CN, string O, string SN, string OU, string GN, string L, string S, string C)
{
//ECDSA_P256
var kpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
var secureRandom = new SecureRandom();
kpg.Init(new KeyGenerationParameters(secureRandom, 256));
var keys = kpg.GenerateKeyPair();
var attributes = new Dictionary<DerObjectIdentifier, string>
{
{ X509Name.CN, CN },
{ X509Name.O, O },
{ X509Name.Surname, SN },
{ X509Name.OU, OU },
{ X509Name.GivenName, GN },
{ X509Name.L, L },
{ X509Name.ST, S },
{ X509Name.C, C }
};
B.X509.X509V3CertificateGenerator extgen2 = new B.X509.X509V3CertificateGenerator();
var signatureFactory = new Asn1SignatureFactory("SHA256WithECDSA", keys.Private, secureRandom);
extgen2.SetPublicKey(keys.Public);
extgen2.SetIssuerDN(new X509Name(attributes.Keys.ToList(), attributes));
extgen2.AddExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(false));
var extendedKeyUsage2 = new ExtendedKeyUsage(new[] { new DerObjectIdentifier("1.3.6.1.5.5.7.3.8") });
extgen2.AddExtension(X509Extensions.ExtendedKeyUsage, true, extendedKeyUsage2.ToAsn1Object());
extgen2.AddExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.NonRepudiation));
extgen2.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(new DerOctetString(new SubjectKeyIdentifierStructure(keys.Public))));
extgen2.SetSerialNumber(GenerateSerialNumber(secureRandom));
extgen2.SetNotBefore(DateTime.UtcNow.AddDays(-1));
extgen2.SetNotAfter(DateTime.UtcNow.AddYears(3));
extgen2.SetSubjectDN(new X509Name(attributes.Keys.ToList(), attributes));
var certificate = extgen2.Generate(signatureFactory);
try
{
//Convert BouncyCastle certificate with private key to MS System.Security X509Certificate2
X509Certificate2 x509Certificate2 = ConvertCertificate(certificate,
keys,
secureRandom);
return x509Certificate2;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
private BigInteger GenerateSerialNumber(SecureRandom random)
{
var timestamp = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var serialNumber =
BigIntegers.CreateRandomInRange(
BigInteger.ValueOf(timestamp), BigInteger.ValueOf(Int64.MaxValue), random);
return serialNumber;
}
private X509Certificate2 ConvertCertificate(B.X509.X509Certificate certificate,
B.Crypto.AsymmetricCipherKeyPair subjectKeyPair,
B.Security.SecureRandom random)
{
var store = new Pkcs12Store();
string friendlyName = FriendlyName; // certificate.SubjectDN.ToString();
// Add the certificate.
var certificateEntry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(friendlyName, certificateEntry);
// Add the private key.
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });
const string password = "password";
var stream = new MemoryStream();
store.Save(stream, password.ToCharArray(), random);
var convertedCertificate =
new X509Certificate2(stream.ToArray(),
password,
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
return convertedCertificate;
}
}
}
`
Running the code
var bugTest = new BugX509Certificate(); bugTest.Run();
Expected Behavior
Should create an object of X509Certificate2 no error
Same code works on Windows.
Actual Behavior
Throw exception
Exception message: "Unable to decode certificate."
{System.Security.Cryptography.CryptographicException: Unable to decode certificate.
at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono..ctor (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Securit…}
Basic Information
Version with issue: Xamarin.iOS Version: 16.2.0.5, iPad OS 16.5
Last known good version:
Platform Target Frameworks:
iOS: Xamarin.iOS Version: 16.2.0.5
NuGet Packages:
Portable.BouncyCastle
version 1.9.0
If this is a bug in Mono then you probably want to see if there is an issue already on their repo or report it there. This is not specific to Xamarin.Forms.
Description
When generating ECDSA certificate got persistent error with Xamarin iOS, but same code works perfectly on Windows 10. Exception message: "Unable to decode certificate." {System.Security.Cryptography.CryptographicException: Unable to decode certificate. at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono..ctor (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Securit…}
Found similar issue on stackoverflow. Not sure if it's related since it looks internal to Mono. https://github.com/dotnet/runtime/issues/23763 https://github.com/xamarin/xamarin-android/issues/5440
Steps to Reproduce
Sample code:
var convertedCertificate = new X509Certificate2(stream.ToArray(), password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
This trow an exception "unable to decode certicate"
`using System; using System.Collections.Generic; using System.IO; using System.Linq; using FO_Framework; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Operators; using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509.Extension; using B = Org.BouncyCastle; using System.Security.Cryptography.X509Certificates;
namespace XamarinFormLib.Framework { public class BugX509Certificate { private const string FriendlyName = "Certificat A";
}
`
Running the code
var bugTest = new BugX509Certificate(); bugTest.Run();
Expected Behavior
Should create an object of X509Certificate2 no error Same code works on Windows.
Actual Behavior
Throw exception Exception message: "Unable to decode certificate." {System.Security.Cryptography.CryptographicException: Unable to decode certificate. at System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono..ctor (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Securit…}
Basic Information
Version with issue: Xamarin.iOS Version: 16.2.0.5, iPad OS 16.5
Last known good version:
Platform Target Frameworks:
NuGet Packages: Portable.BouncyCastle version 1.9.0
Affected Devices: iPad Gen 8, OS 16.5
Environment
Show/Hide Visual Studio info
``` Visual Studio Community 2022 for Mac Version 17.5.4 (build 8) Installation UUID: f1242899-4c62-4c3d-8f47-186cabba6e4f Runtime .NET 7.0.1 (64-bit) Architecture: X64 Microsoft.macOS.Sdk 12.3.2372; git-rev-head:754abbf6a3563f6267e5717ae832b4ac25b1f2fb; git-branch:release/7.0.1xx-xcode13.3 Roslyn (Language Service) 5.5.0-3.23056.2+97881342e427ff5cdcba8f12b12ff8e6f3564431 NuGet Version: 6.4.0.117 .NET SDK (x64) SDK: /usr/local/share/dotnet/sdk/7.0.203/Sdks SDK Versions: 7.0.203 6.0.408 6.0.301 5.0.101 3.1.410 3.1.200 2.1.701 2.1.700 2.1.505 MSBuild SDKs: /Applications/Visual Studio.app/Contents/MonoBundle/MSBuild/Current/bin/Sdks .NET Runtime (x64) Runtime: /usr/local/share/dotnet/dotnet Runtime Versions: 7.0.5 7.0.16 5.0.7 5.0.1 3.1.16 3.1.2 2.1.23 2.1.17 2.1.16 2.1.12 2.1.11 2.1.9 Xamarin.Profiler Version: 1.8.0.49 Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler Updater Version: 11 Apple Developer Tools Xcode: 14.2 21534 Build: 14C18 Xamarin.Mac Version: 9.1.0.5 Visual Studio Community Hash: 7738c90c9 Branch: xcode14.2 Build date: 2023-01-25 15:56:14-0500 Xamarin.iOS Version: 16.2.0.5 Visual Studio Community Hash: 7738c90c9 Branch: xcode14.2 Build date: 2023-01-25 15:56:15-0500 Xamarin Designer Version: 17.5.3.47 Hash: e8b5d371c3 Branch: remotes/origin/d17-5 Build date: 2023-04-05 15:57:59 UTC Xamarin.Android Version: 13.2.0.0 (Visual Studio Community) Commit: xamarin-android/d17-5/797e2e1 Android SDK: /Users/vassoume/Library/Developer/Xamarin/android-sdk-macosx Supported Android versions: 8.0 (API level 26) 8.1 (API level 27) 10.0 (API level 29) 8.1 (API level 25) 9.0 (API level 28) 13.0 (API level 33) SDK Command-line Tools Version: 7.0 SDK Platform Tools Version: 33.0.3 SDK Build Tools Version: 32.0.0 Build Information: Mono: 6dd9def Java.Interop: xamarin/java.interop/main@149d70fe SQLite: xamarin/sqlite/3.40.0@fdc1e34 Xamarin.Android Tools: xamarin/xamarin-android-tools/main@9f02d77 Microsoft Build of OpenJDK Java SDK: /Library/Java/JavaVirtualMachines/microsoft-11.jdk 11.0.16.1 Android Designer EPL code available here: https://github.com/xamarin/AndroidDesigner.EPL Eclipse Temurin JDK Java SDK: /Library/Java/JavaVirtualMachines/temurin-8.jdk 1.8.0.302 Android Designer EPL code available here: https://github.com/xamarin/AndroidDesigner.EPL Android SDK Manager Version: 17.5.0.33 Hash: f0c0c52 Branch: remotes/origin/d17-5~2 Build date: 2023-04-05 15:58:04 UTC Android Device Manager Version: 0.0.0.1245 Hash: 7f8a990 Branch: 7f8a990 Build date: 2023-04-05 15:58:04 UTC Build Information Release ID: 1705040008 Git revision: 9a2f0e1a7e2107e6b1174c241a1ca232cde57c49 Build date: 2023-04-05 15:56:22+00 Build branch: release-17.5 Build lane: release-17.5 Operating System Mac OS X 13.4.0 Darwin 22.5.0 Darwin Kernel Version 22.5.0 Mon Apr 24 20:51:50 PDT 2023 root:xnu-8796.121.2~5/RELEASE_X86_64 x86_64 ```Build Logs
Screenshots
Reproduction Link
Workaround