Swift 3/4 - Generate SecCertificate from Elliptic Curve Keypair - swift

Currently i am generating an Elliptic Curve KeyPair in my iOS App successfully:
let privateKeyParams: [String: Any] = [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: privateTag
]
let publicKeyParams: [String: Any] = [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: publicTag,
kSecAttrAccessible as String: kSecAttrAccessibleAlways
]
let query: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecPrivateKeyAttrs as String: privateKeyParams,
kSecPublicKeyAttrs as String: publicKeyParams,
kSecAttrKeySizeInBits as String: 256 as AnyObject,
]
let status = SecKeyGeneratePair(query as CFDictionary, &self.publicKey, &self.privateKey)
guard status == errSecSuccess else {
print("Could not generate keypair")
return
}
guard let pubKey = self.publicKey, let privKey = self.privateKey else {
print("Keypair null")
return
}
This one works because when i check if my keys exist they do and i can also encrypt/decrypt and sign/verify.
Soo.. in the next step i need to generate a SecCertificate which will basically hold my public key... this is simply a requirement.
But there is literally no API/Documentation on how to do this..the only api i saw is on how to generate SecCertificate from existing der file etc..
So my question is:
How do i generate an SecCertificate object from my existing Elliptic Curve KeyPair (SecKey)?
Thanks and Greetings!

Certificates and cryptographic functions in general are very bad documented and barely supported in Swift / iOS.
But the first question here is: Why do you need a certificate and what do you want to do? The main problem is that you just cannot create a valid certificate out of thin air. A certificate has to be signed by a a certificate authority (CA) so that anyone with the CA certificate can verify that the certificate is valid.
(Of course you can create a self signed certificate but this would be useless in most cases. Additionally, I do not know how to do this easily. All API calls in Swift / iOS assume that you already have a valid certificate. It seems that it is not intended to create certificates inside your app.)
So first, you need a certificate authority, which can sign your certificate. Then, you need to create a certificate signing request from your key pair and send it to your CA. You then will obtain a signed certificate, which you can use in your app. The steps in correct order are:
Create / find a certificate authority (CA)
Create your keypair
Create a certificate signing request (CSR). I currently use CertificateSigningRequestSwift because Apple simply does not provide any functionality to do this.
Send your CSR to the CA and receive the certificate (CRT).
Save the CRT together with the private key in a P12 trust store. I use OpenSSL-for-iPhone to do this.
Get the SecIdentity or the SecCertificate from the P12 trust store
This is a lot of work but after a long time of researching this is the only way I got certificates working in Swift / iOS. Especially the handling with OpenSSL is very tricky (have a look at this post of me to get an idea of the complexity). So, again, the question is what you want to do. If you want to create a SSL client, you need to go the full way, but if you just want to encrypt some stuff, the solution may be a lot easier.

Related

ACM PCA Issue certificate for client authentication and signing data

I'm trying to implement MTLS client authentication using AWS ACM Private CA to issue X.509 client certificates.
The certificate and the correlating private key is supposed to be stored in a password protected PKCS#12 file.
The private key will also be used by the client to sign data.
If I request a new certificate using aws-acm-sdk:
RequestCertificateResult response = acm.requestCertificate(new RequestCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withIdempotencyToken("1234")
.withDomainName("localhost.com"));
return response.getCertificateArn();
And then export the it using the arn, I get a certificate, certificateChain and a privateKey as strings.
ExportCertificateResult response = acm.exportCertificate(new ExportCertificateRequest()
.withCertificateArn(certificateArn)
.withPassphrase(ByteBuffer.wrap(password.getBytes())));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
String privateKey = response.getPrivateKey();
But I'm not able to add any type of identifier that let's me tie the certificate to a user during authentication (I'm using Java and Spring security x509 authentication, which extracts e.g. the subject CN (Common Name) from the certificate which then can be used to identify a user).
If I want to add custom attributes to the certificate, I need to issue a certificate through the aws-acm-pca-sdk:
IssueCertificateRequest request = new IssueCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCsr(stringToByteBuffer(getCSR()))
.withTemplateArn("arn:aws:acm-pca:::template/EndEntityClientAuthCertificate_APIPassthrough/V1")
.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA)
.withValidity(new Validity()
.withValue(365L)
.withType(ValidityPeriodType.DAYS))
.withIdempotencyToken(userId)
.withApiPassthrough(new ApiPassthrough()
.withSubject(new ASN1Subject()
.withCustomAttributes(List.of(
new CustomAttribute()
.withObjectIdentifier("1.3.6.1.4.1") // CustomOID
.withValue("userId")))));
return acmPca.issueCertificate(request).getCertificateArn();
But if I use the sdk to get the certificate, it doesn't contain any private key.
GetCertificateResult response = acmPca.getCertificate(new GetCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCertificateArn(certificateArn));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
So, when I read documentation I found that I need to import it to ACM in order to export it and get the private key.
But in order to import it to ACM I also need to provide the private key..
But as I understand it, the private key should be used when issuing the certificate in the first place?
Should I create a new public/private key pair using KMS or what am I supposed to do?
Im confused.. Please help!
I had misinterpreted the responsibility of the PCA.
The PCA is only responsible for issuing certificates, not keys or even CSR (Certificate Signing Requests).
I assumed that the CSR were created by PCA, so the getCSR() method actually fetched the CA's CSR from PCA, while the actual CSR should be generated internally using a private key which has been generated either programmatically or using KMS.

jsonwebtoken.verify method giving error from keycloak token

I use the /auth/realms//protocol/openid-connect/certs endpoint and hardcode the x5c public key returned from this endpoint to try to get this code working (wrapped in BEGIN RSA/END RSA tags) like so:
let x5c = "MIICnTCCAYUCBgF9TkI2ijANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdldmlkZW5zMB4XDTIxMTEyMzE5MjMyMVoXDTMxMTEyMzE5MjUwMVowEjEQMA4GA1UEAwwHZXZpZGVuczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALgx8kfUyhUz6146LcXJHykE5d/kfkJGHZ1+AH4wfk0Z1rGeNqRUH7bllutre2xrq/EfuKGkuUul8uf7WH3GTyOFJyr1MECnzilYdN8onobpVHXr3SwANCACMsh6tFc6oiQT0XEt1ovzTzB6vxA6qmmsdLPG9giJ9eNqJNHHQiIJosF3yBBoNFDiQDonRNdWNQz5JVxbsdIOhFrdD+mDU0ry9FIs6qMAvD84QVBOzJr/IOCdSy3bfWYyAUsLHqoJbytAzl5EgjVSU2UT+HLs7M2wfZoRGITztmvkcPjqd7PnSOuuAimonwP7uKHtvG+edRabyHaBDSemEA1LUs7+FGkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAIh4QCe6Y3fJtDV6nBi/E3CGo/SIjDCmNnOV413QtmwODZSWFqo6pxs2fJoDb8jIkTf+l8/bI+mKEesXK1CptBpXXyo7Il0jhk5M0c1VT7EkLa/jkVFNr0CoB3UmH56/29Qp8+Xr8TaejGjgS8HoxAMpSFrtjPlKElCcy8dVQgRMxFonry5Iipd4vutc8Afe/GLzJew0IJ5Az1VUum3bJD0IfeecB8F+YOMmaET0oJIQyfdUxVI985Ui30q4K8/p34+WqwvNy2x4vuulvDVRBsHG64PStzhqZQfsfi59lOps4WvYlQ1JEHTu3acZMyTzij6wrVTAFoh1C3FptZ0wPoQ==";
let pemEncoded = `-----BEGIN RSA PUBLIC KEY-----\n${x5c}\n-----END RSA PUBLIC KEY-----\n`;
const payload = verify(token, pemEncoded, { "algorithms": ["RS256"] }));
But I don't think I've got correct PEM and I've been at it all day trying to find how to setup this certificate for verification. The error says "error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag". The token is valid, but it doesn't like my certificate. Any idea what I've got wrong here?
What's the correct way to pass this certificate to the jsonwebtoken.verify method in this case? Thanks!
That is certificate, so:
let pemEncoded = `-----BEGIN CERTIFICATE-----\n${x5c}\n-----END CERTIFICATE-----\n`;

How to encrypt JWT secret code for protect it in case of APK decompilation?

I have a problem with JWT. If someone decompiles my APK, they can see the secret code I used to create my token. Example code, the code is secret:
String originalInput = "secret";
String encodedString =Base64Utils.encode(originalInput.getBytes());
String jwt = Jwts.builder().claim("emailId","test123#gmail.com").claim("user", "123456")
.claim("phoneNo", "1111111111")
.signWith(SignatureAlgorithm.HS256, encodedString)
.compact();
As there are a client (the APK) and a backend, you should use an asymmetric algorithm such as RS256, PS256 or ES256, not a symmetric one (HS256).
If the issuer of the token is your backend, you only need the public key on client side (your APK). This key can safely be shipped as it is public.
If the client is the issuer, key should not be shipped with your application but generated on the device and securely stored using the Keystore API (https://developer.android.com/training/articles/keystore). The associated public key should be sent to the backend. This means that each client has a uniquely generated private key.

Swift 3 Mac OSX - can't cast SecCertificate object in my Keychain to SecKeychainItem?

I am trying to delete an identity from my Keychain in Swift 3.0. My code is currently:
var idCert: SecCertificate? = nil
var idKey: SecKey? = nil
SecIdentityCopyCertificate(id, &idCert)
SecIdentityCopyPrivateKey(id, &idKey)
SecKeychainItemDelete(idCert as! SecKeychainItem)
SecKeychainItemDelete(idKey as! SecKeychainItem)
"id" is a SecIdentity object that I got by using SecItemCopyMatching to get all of my identities, and then used that list to find the identity associated with a specific email address.
My code fails when I try to cast idCert to SecKeychainItem. Apple's Documentation says:
A SecCertificate object for a certificate that is stored in a keychain
can be safely cast to a SecKeychainItem for manipulation as a keychain
item. On the other hand, if the SecCertificate is not stored in a
keychain, casting the object to a SecKeychainItem and passing it to
Keychain Services functions returns errors.
but upon checking Keychain Access I can plainly see that the certificate is in the Keychain. What is going on? Is it possible for a certificate to appear to be in my Keychain but actually isn't or can't be found for some reason? Is there a way for me to programmatically check if the SecCertificate object is in my Keychain?

Jwt Key is not valid for HmacSHA256

i have a problem that when i create claim after signing it while sending i am getting key is not valid, not able to get the reason ..
*code:*
OctetSequenceJsonWebKey key = OctJwkGenerator.generateJwk(2048);
JsonWebSignature jws = new JsonWebSignature();
jws.setKey(key.getKey());
jws.setPayload(claims.toJson());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
signedJWT = jws.getCompactSerialization();
return signedJWT;
For Hmac algorithms, you are supposed to use an octet key.
From your code, I can see you are loading a RSA key (RsaJsonWebKey)