Closed filmar25 closed 3 years ago
I already did the job with Xamarin.Android and Windows Application and both are working well.
I do not know which API/service/tool you used in the above case. However what you're doing here is incorrect.
var cert = this.publicKey.GetExternalRepresentation();
This does not return an X.509 certificate. This is why your WCF service won't accept it.
The usual way to create a .509 certificate is to:
Neither the .net framework (I have not checked net5+), nor Apple APIs, provide a certificate authority or any API to create a certificate.
Since it's not generated (locally) and you did not import a certificate (from a CA) then you cannot export it (as it does not exists).
Hello spouliot,
Thank you for taking your time to answer me.
With Xamarin.Android, I proceed like this :
First I generate the Key Pair and I can easily extract the certificate without create a certificate request. I only use the Xamarin.Android sdk :
public void InitDeviceCertificate(bool deleteCertIfExists)
{
try
{
var ks = KeyStore.GetInstance("AndroidKeyStore");
ks.Load(null);
if (ks.ContainsAlias(RSAStrings.LocalCertificateName) && deleteCertIfExists)
{
ks.DeleteEntry(RSAStrings.LocalCertificateName);
}
if (ks.ContainsAlias(RSAStrings.LocalCertificateName) == false)
{
// // // // // // // // // // // // // // // // // //
// Generate new certificate on the Android Device //
// // // // // // // // // // // // // // // // //
var kpg = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, ks.Provider);
var cal = Calendar.GetInstance(Java.Util.TimeZone.Default);
cal.Set(DateTime.Now.Year + 50, 1, 1);
var expiration = new Date(cal.TimeInMillis);
kpg.Initialize(
new KeyGenParameterSpec.Builder
(RSAStrings.LocalCertificateName, KeyStorePurpose.Sign | KeyStorePurpose.Verify | KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
.SetCertificateSubject(new Javax.Security.Auth.X500.X500Principal($"CN={RSAStrings.LocalCertificateName}"))
.SetDigests(KeyProperties.DigestSha256)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingRsaPkcs1)
.SetSignaturePaddings(KeyProperties.SignaturePaddingRsaPss)
.SetCertificateNotAfter(expiration)
.SetRandomizedEncryptionRequired(false)
.SetBlockModes(KeyProperties.BlockModeEcb)
.SetUserPresenceRequired(false)
.SetUnlockedDeviceRequired(false)
.SetUserConfirmationRequired(false)
.SetKeySize(2048).Build()
);
var kp = kpg.GenerateKeyPair();
this.privateKey = kp.Private;
this.publicKey = kp.Public;
this.certificate = ks.GetCertificate(RSAStrings.LocalCertificateName);
this.key = ks.GetKey(RSAStrings.LocalCertificateName, null);
}
else
{
this.certificate = ks.GetCertificate(RSAStrings.LocalCertificateName);
this.publicKey = this.certificate.PublicKey;
KeyStore.IEntry entry = ks.GetEntry(RSAStrings.LocalCertificateName, null);
this.privateKey = ((KeyStore.PrivateKeyEntry)entry).PrivateKey;
this.key = ks.GetKey(RSAStrings.LocalCertificateName, null);
}
}
catch (Exception ex)
{
var i = 0;
}
}
Second, I extract the certificate :
public string GetDevicePublicCertificate()
{
return Convert.ToBase64String(this.certificate.GetEncoded(), Base64FormattingOptions.InsertLineBreaks);
}
Third, I use it on the server :
public void SetDistantCertificate(string cer)
{
try
{
var bytes = Convert.FromBase64String(cer);
X509Certificate2 cert = new X509Certificate2(bytes); <========= This line crash on iOS : Cannot find the requested object.
this.rsaDistant = cert.GetRSAPublicKey();
}
catch (Exception ex)
{
throw ex;
}
}
According to the Apple documentation, it seems that the publicKey is exportable and usable externally like Android is doing : https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/storing_keys_as_data?language=objc
On Xamarin.macios, GetExternalRepresentation using SecKeyCopyExternalRepresentation like the Apple documentation explain :
I also found this post of 2011 about iOS : https://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/
This blog is base on https://blog.wingsofhermes.org/?p=75
The Apple documentation said that SecKeyCopyExternalRepresentation give a PKCS#1 data. But like I saw in the post we have to make manipulation of the data before using it outside of iOS.
I will investigate those post to see what I can do with the publicKey to add bytes to the result of GetExternalRepresentation.
I am newbie with RSA, so I miss a lot of things.
Thank you !
According to the Apple documentation, it seems that the publicKey is exportable and usable externally
Yes, but a public key is not a X.509 certificate. A X.509 certificate includes the public key. A public key does not include a certificate.
If you need the later (X.509) then someone, somewhere needs to create it (and that won't come from iOS).
I am newbie with RSA, so I miss a lot of things.
It's X.509, not RSA, related. Sadly that does not make it easier
Hello,
I would like to submit this case.
My goal is to generate RSA Key Pair on iOS and after send the certificate (X509) to our WCF Service to be stored. We use it to create a token for the device that has generated the certificate. This securise our communication with this device.
Steps to Reproduce
First, I generate a key pair on iOS :
Second, I extract the certificate. At this stage, I send the string directly to the WCF Service to be stored :
Third, on the server, I want to use it :
Expected Behavior
I already did the job with Xamarin.Android and Windows Application and both are working well. I can create RSA Key Pair on the device and send the certificate to the WCF Service to be stored and after I can use it without problem. I use the device certificate to encrypt the token generated on the server.
Actual Behavior
I spend long time checking posts and saw many examples in swift, objectif c. It seems that iOS didn't export to X.509 format. I also saw that Microsoft has made classes like SecCertificate and SecCertificate2 in Xamarin.iOS that can export X.509 certificate, but when I use it, debugger freeze at the export of X509Certificate.
Environment