RSA => SecKey.GenerateKeyPair => Create SelfSigned Certificate X.509

Hi,

I'm certainly not an expert in RSA, Certificate, etc and I miss a lot of things. But I have made it working in Android and Windows.

There is my goal : I want to generate a KeyPair with RSA and be able on the iPhone to communicate securely with my server. So on my server I create a self-signed certificate for the iPhone and I want iPhone to create a self-signed certificate for the server. At this point I can both encrypt and sign exchange information between iPhone and the server.

Actually I can easily create a KeyPair with SecKey.GenerateKeyPair, but after that I'm struggling to create the self-signed certificate.

Is it possible with iOS ? If so, how can I do it ?

Thank you

Answered by DTS Engineer in 678270022

So, the thing about self-signed certificates is that they don’t make a lot of sense (-: Lemme explain a bit…

The whole point of a certificate is that the issuer (the entity that signed the certificate) certifies that the subject (the entity that requested the certificate) holds the private key associated with the public key that’s wrapped up in the certificate. For example, when you upload a CSR to the developer web site and have it issue you a certificate, that CSR contains your public key and the developer web site acts as the issuer. It creates and signs a certificate that says that “I, the Apple developer web site, certify that developer XXX holds the private key associated with the public key in this certificate”. So, the certificate contains both a public key /and/ identifying information.

Once you understand this you can see the problem with self-signed certificates. Like all certificates they contain a public key, info about the subject, and info about the issuer. However, because they’re self signed then the last two items are meaningless. There’s no way to check that the info is good because there’s no issuer to consult.

In some cases creating a self-signed certificate is necessary. For example, the TLS protocol requires [1] that you start with a digital identity (the combination of a private key and a certificate whose public key matches that private key) and so you may end up needing to generate a self-signed certificate just to meet that requirement.

However, in your situation that doesn’t seem to be case. AFAICT you’re planning to do this:

  1. Generate a key pair.

  2. Hold on to the private key.

  3. Wrap the public key in a certificate.

  4. Send that certificate to your server.

  5. Have your server extract the public key from the certificate.

  6. Then do crypto stuff with that public key.

So, you don’t actually need a certificate. Rather, in step 3 you could export the public key and send that to the server, cutting out the certificate completely. And that’s important because iOS has good APIs to export public keys but it has no APIs for generating self-signed certificates.

So, does my analysis sound right? If so, I’d be happy to help you with the whole ‘exporting a public key’ malarkey.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Not quite. TLS also supports a pre-shared key mode but that mode is not widely supported.

Presumably you plan to pair your private key and your self-signed certificate to form a digital identity. What happens next? Are you using that digital identity for HTTPS requests? Or a TLS connection? Or something else?

Oh, and is your server running on iOS? Or some other Apple platform? Or some non-Apple platform?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hello Quinn,

Thank you very much take your time to answer me.

I will take example to my Android App. Android communicate with our Microsoft WCF Service that is part of our ASP.NET MVC 5 Web application. Android create Key Pair and Self-Signed certificate and also WCF create Key Pair and Self-Signed certificate for this device. After they exchange their self-signed certificate X.509 to exchange information with RSA encryption.

With Android, I create Key Pair and a self-signed certificate that is store in AndroidKeyStore like that :

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);

But with iOS on iPhone, I am not finding easy way to do the same.

Thank you for your help !

Unfortunately I’m not familiar enough of the Microsoft ecosystem to understand what you’re getting at here. So, let’s try another tack…

Imagine iOS has an API that generates a self-signed digital identity, that is, a private key and a self-signed certificate that embeds its associated public key. What would you then do with that digital identity? Where does it go? And what operations do you use it for?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hello Quinn,

With RSA, I want to secure data exchange between devices and our server. But I am trying to make my best by my limited knowledge.

So I register a device on the server by receiving the self-signed certificate generated by our client application on this device. At this point, the server generate a key pair for this device and return self-signed certificate of the server side. Now the dance can begin to exchange information between our client application and our server. This manner, If a device is compromise, the others will be ok. We just lock the compromise device.

The client application on the device ask user/pwd to login. I use the server certificate on the device to encrypt the token, but I use the device private key to sign it. The server can validate the signature of the token because it has the device self-signed certificate. If the credential is ok, the server use the device certificate to encrypt a new token but it is using his private key to sign the token. So when the device is receiving the token, it can validate the signature because it has the server certificate.

May be it is not the right way to do the things, but it is what I can do with my knowledge.

I saw in this link https://github.com/svdo/swift-SelfSignedCert/tree/b598d8e4960a25347cce4266457580e5bce66224 that "Apple does not provide this functionality in their security frameworks". That's explain why I have difficulties to get some example of what I was searching.

Finally, I was forced to use Portable.BouncyCastle that is already developed in .NETStandard because I use Xamarin to create our client application. With that, now I can create my self-signed certificate. But I would have preferred not to integrate it.

If you have some advice for me Quinn, it will be well received. Be sure that your help is quite appreciated.

Accepted Answer

So, the thing about self-signed certificates is that they don’t make a lot of sense (-: Lemme explain a bit…

The whole point of a certificate is that the issuer (the entity that signed the certificate) certifies that the subject (the entity that requested the certificate) holds the private key associated with the public key that’s wrapped up in the certificate. For example, when you upload a CSR to the developer web site and have it issue you a certificate, that CSR contains your public key and the developer web site acts as the issuer. It creates and signs a certificate that says that “I, the Apple developer web site, certify that developer XXX holds the private key associated with the public key in this certificate”. So, the certificate contains both a public key /and/ identifying information.

Once you understand this you can see the problem with self-signed certificates. Like all certificates they contain a public key, info about the subject, and info about the issuer. However, because they’re self signed then the last two items are meaningless. There’s no way to check that the info is good because there’s no issuer to consult.

In some cases creating a self-signed certificate is necessary. For example, the TLS protocol requires [1] that you start with a digital identity (the combination of a private key and a certificate whose public key matches that private key) and so you may end up needing to generate a self-signed certificate just to meet that requirement.

However, in your situation that doesn’t seem to be case. AFAICT you’re planning to do this:

  1. Generate a key pair.

  2. Hold on to the private key.

  3. Wrap the public key in a certificate.

  4. Send that certificate to your server.

  5. Have your server extract the public key from the certificate.

  6. Then do crypto stuff with that public key.

So, you don’t actually need a certificate. Rather, in step 3 you could export the public key and send that to the server, cutting out the certificate completely. And that’s important because iOS has good APIs to export public keys but it has no APIs for generating self-signed certificates.

So, does my analysis sound right? If so, I’d be happy to help you with the whole ‘exporting a public key’ malarkey.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Not quite. TLS also supports a pre-shared key mode but that mode is not widely supported.

Hello Quinn,

All you said makes a lot of sens. Your explanation help me having a better understanding about certificates. Just one post and you unblock my understanding !

Now I have a better direction for my research and implementation. I thank you for that !

I saw one of your answers here https://developer.apple.com/forums/thread/85915 to export publickey for external platform. If I understand, I can use SecKeyCopyExternalRepresentation that can be imported in my server. I will try it next Monday.

Thank you very much again Quinn !

RSA => SecKey.GenerateKeyPair => Create SelfSigned Certificate X.509
 
 
Q