Create a JLS KeyStore from an Apple .p8 key

Hi,

Starting from a .p8 file which contains both a private and a public key, I'm looking for the required steps to create a certificate, then create a JKS KeyStore, and finally import the certificate into the KeyStore.

I've searching on the Net without success.

Maybe someone could help on this one?

Thank you

contains both a private and a public key

Apple .p8 files generally don’t contain a public key. Rather, they have a private key and you can derive a public key from that.

I'm looking for the required steps to create a certificate

Why do you need a certificate? A certificate associates metadata, like the subject’s name, with a public key, which is then signed by an issuer to certify that association. If you have a private key, as represented by a .p8 file, there’s no subject and there’s no issuer, so the whole concept of a certificate is meaningless.

Share and Enjoy

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

Apple .p8 files generally don’t contain a public key. Rather, they have a private key and you can derive a public key from that.

The dumpasn1 tool shows 2 octet sequences: ecPublicKey and prime256v1. That's why I supposed so.

Why do you need a certificate?

I'm implementing an OAuth2 Social Login from Salesforce. To authenticate on the Apple side, I use an Apex method called Crypto.sign(). The invalid_client error message I'm getting from Apple probably tells me that the JWT Salesforce sends is not signed correctly.

After doublechecking the JWT structure, I came to the conclusion that the P-256 curve needed by Apple is not part of this method's implementation.

As an alternative solution, I thought about using another Apex method named Crypto.signWithCertificate(), that says it all...

The dumpasn1 tool shows 2 octet sequences: ecPublicKey and prime256v1.

Can you post an example of that? Feel free to redact the actual key bytes, although leave the key structure intact (so, rather than delete them, replace each byte with XX).

Share and Enjoy

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

Sure, there you go:

SEQUENCE {                                                                                                                         
  INTEGER 0                                                                                                                        
  SEQUENCE {                                                                                                                       
    OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)                                                                              
    OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)                                                                             
    }                                                                                                                              
  OCTET STRING, encapsulates {                                                                                                     
    SEQUENCE {                                                                                                                     
      INTEGER 1                                                                                                                    
      OCTET STRING XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
      [0] {                                                                                                                        
        OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)                                                                         
        }                                                                                                                          
      [1] {                                                                                                                        
        BIT STRING                                                                                                                 
          XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
          XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
          XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
          XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
          XX                                                                          
        }                                                                                                                          
      }                                                                                                                            
    }                                                                                                                              
  }                                                                                                                                
                                                                                                                                   

Sure, there you go

Thanks!

The ecPublicKey oid is misleading here; it doesn’t indicate that this is a public key, but rather than this key uses elliptic curve public key encryption. In short, that is a PKCS#8 private key.

Note For more background on this, see my On Cryptographic Key Formats post.

Given that, this statement in your original post is wrong:

Starting from a .p8 file which contains both a private and a public key

Your .p8 contains just a private key.

I’m also concerned about this:

I'm looking for the required steps to create a certificate, then create a JKS KeyStore, and finally import the certificate into the KeyStore.

You shouldn’t need to create a certificate just to work with a private key.

And that brings me to this:

To authenticate on the Apple side, I use an Apex method called Crypto.sign(). The invalid_client error message I'm getting from Apple probably tells me that the JWT Salesforce sends is not signed correctly.

You’re probably right about that (-:

But this:

As an alternative solution, I thought about using another Apex method named Crypto.signWithCertificate(), that says it all...

is taking you down the wrong path. Adding a certificate into this mix won’t help. Rather, you need to debug why signing with the key is failing.

What Apple service is this key for?

Share and Enjoy

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

First I enjoyed reading your answer. Very constructive, very clear.

What Apple service is this key for?

This endpoint: https://appleid.apple.com/auth/token

As explained here, this key's used to build the client_secret param.

Since this key is stored in a text file and the sign method needs a string key, what I do is concatenating every line of the file, removing both carriage returns and BEGIN/END boundaries obviously.

Ah, Sign in with Apple! I don’t have much experience with that, so I’m going to retag your question and hope that someone else chimes in.


Also, it would be nice if the page you reference included a test vector, that is, a private key, the JWT input, and the JWT output. That would you could check whether this problem is with the JWT signing or the content itself. If you feel that would have helped you here, please file an enhancement request against the docs (and post your bug number, just for the record).

Share and Enjoy

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

Ah, Sign in with Apple!

Love it ;-)

so I’m going to retag your question and hope that someone else chimes in

Thanks

If you feel that would have helped you here, please file an enhancement request against the docs

It would definitely have! Thanks for the advice, I'll sure give some feedback about that

Create a JLS KeyStore from an Apple .p8 key
 
 
Q