Closed mischasigtermans closed 6 years ago
As we spoke via gitter you have to convert your certificate into the keys to be used by RSA algorithm. This is achievable using openssl
. Probably there's a simpler way to get to pub/private keys directly but I didn't have time to research a bit more - I just dig a bit after you called me on gitter.
1. Creating the certificate - this is not applicable to you since you already have the certificate but I'd never ask you to send it to me :) (https://stackoverflow.com/questions/8500874/how-to-generate-pkcs8-key-with-pem-encode-using-aes-128-ecb-alg-in-openssl)
Running the command bellow will create the file cert.p8
with our new PKCS8 certificate:
$ openssl genrsa | openssl pkcs8 -topk8 -v2 aes-128-ecb -out cert.p8
2. Converting it to traditional format (http://openssl.cs.utah.edu/docs/apps/pkcs8.html)
This command creates the file cert.pem
$ openssl pkcs8 -in cert.p8 -out cert.pem
3. Converting the traditional format to a RSA private key (https://stackoverflow.com/questions/2957742/how-to-convert-pkcs8-formatted-pem-private-key-to-the-traditional-format)
This command generates the file private.key
to be used by the libraries.
$ openssl rsa -in cert.pem -out private.key
4. Extracting public key from private key (https://stackoverflow.com/questions/5244129/use-rsa-private-key-to-generate-public-key)
This command prints out the public key:
$ openssl rsa -in private.key -pubout
These keys are usable by any RSA algorithm available in this lib and others (https://jwt.io works fine too).
@Pixelstart can you please try it out and let us know if this works. If so, could you please submit a PR to extend our documentation here?
Thanks for figuring this out.
On step two I had to add -nocrypt since my .p8 file is not encrypted. On the third step however I receive the following error:
140736141493292:error:06FFF07F:digital envelope routines:CRYPTO_internal:expecting an rsa key:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.200.2/libressl-2.6/crypto/evp/p_lib.c:295:
Seems like step two is not converting it as it should.
I can't help you more than that since I don't have access to the .p8
file... can you generate one just for testing purposes and then revoke it?
Sure, here you go!
AuthKey_4W5TU4DR28.p8
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgir767IOFOYHsYtNQ
wsvLeJVu3bxCLL/SURQvMZw6QumgCgYIKoZIzj0DAQehRANCAARuwGOLtHY99zLl
iyACJp6xmj6YfE8bOLxHTZGkoC/+yNgf/fBpwf5Nin2pzyM8FUOYXg1R1v2bQqJy
wHYtSkc1
-----END PRIVATE KEY-----
This following command may help you. It requires PHP 7.1 and the OpenSSL extension.
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
chmod +x jose.phar
./jose.phar key:convert:pkcs1 $(./jose.phar key:load:key ./AuthKey_4W5TU4DR28.p8) > key.pem
rm jose.phar*
It will convert your key in PKCS#1 PEM instead of PKSC#8. You can then use it with the library.
@Pixelstart I just saw that the key you gave looks like an ECDSA key instead of RSA:
$key = openssl_pkey_get_private('file://cert.p8');
var_dump(openssl_pkey_get_details($key));
/*
array(4) {
'bits' =>
int(256)
'key' =>
string(178) "-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbsBji7R2Pfcy5YsgAiaesZo+mHxP
Gzi8R02RpKAv/sjYH/3wacH+TYp9qc8jPBVDmF4NUdb9m0KicsB2LUpHNQ==
-----END PUBLIC KEY-----
"
'ec' =>
array(5) {
'curve_name' =>
string(10) "prime256v1"
'curve_oid' =>
string(19) "1.2.840.10045.3.1.7"
'x' =>
string(32) "n?c??v=?2? &???>?|O ?GM???/??"
'y' =>
Q???B?r?v-JG5" "???i??M?}??#<C?^
'd' =>
string(32) "???샅9??b?P???x?nݼB,??Q/1?:B?"
}
'type' =>
int(3)
}
*/
And that's why the OpenSSL conversion to RSA doesn't work. Using what @Spomky said gives us the ECDSA private key (thanks @Spomky):
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIq++uyDhTmB7GLTUMLLy3iVbt28Qiy/0lEULzGcOkLpoAoGCCqGSM49
AwEHoUQDQgAEbsBji7R2Pfcy5YsgAiaesZo+mHxPGzi8R02RpKAv/sjYH/3wacH+
TYp9qc8jPBVDmF4NUdb9m0KicsB2LUpHNQ==
-----END EC PRIVATE KEY-----
Thanks to you both for making me understand this. So if I understand this correctly, I still have to convert the new key.pem to a .key which then has a public and private key?
So I've figured this our. Finally. I had to convert the .p8
key to a .pem
key first. I've used @Spomky's tip. After this I've used @lcobucci's way of retrieving the public key from the new created .pem
key.
After adding the new keys to the builder, I ran into a new error;
Mdanter\Ecc\EccFactory' not found
After searching the Issues again I figured I needed to add Ecc to 'composer.json'.
composer require mdanter/ecc:~0.3.1
Keep in mind that you need PHP 7.1 for retrieving the public key and PHP 5.6 for the added mdanter/ecc
.
Thanks guys!
@Pixelstart cool! We're removing the dependency on that lib quite soon (for v3.3 and v4.0-alpha2) then things will be a little easier as well.
Closing this issue then 😄
Good news.
You can still use the application to convert a key from private to public:
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
chmod +x jose.phar
./jose.phar key:load:key ./AuthKey_4W5TU4DR28.p8 > private_key.jwk
./jose.phar key:convert:public $(cat private_key.jwk) > public_key.jwk
./jose.phar key:convert:pkcs1 $(cat private_key.jwk) > private_key.pem
./jose.phar key:convert:pkcs1 $(cat public_key.jwk) > public_key.pem
rm *.jwk
rm jose.phar*
This will create private_key.pem
and public_key.pem
files.
@Spomky Cool! Thanks for that additional info.
@lcobucci So will it work on PHP 7.2 then?
@lcobucci So will it work on PHP 7.2 then?
@Pixelstart yeap!
In 2020, I am seeing this error with the suggested jose script:
Not enough arguments (missing: "jwk").
Any ideas?
In 2020, I am seeing this error with the suggested jose script:
Not enough arguments (missing: "jwk").
Any ideas?
Perhaps opening an issue in the tool's repository might be a good start? 😁
Hey guys,
Trying this solution on my end to use an Apple generated .p8 file, but I'm stuck on this step:
./jose.phar key:convert:public private_key.jwk > public_key.jwk
In PublicKeyCommand.php line 52:
Invalid JWK
@michelvermeulen you're using the tool in the wrong way, check https://github.com/lcobucci/jwt/issues/244#issuecomment-395447760 and https://github.com/lcobucci/jwt/issues/244#issuecomment-395661512
@michelvermeulen you're using the tool in the wrong way, check #244 (comment) and #244 (comment)
I actually did, sorry if that wasn't clear.
I did exactly what @Spomky suggested:
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
chmod +x jose.phar
./jose.phar key:load:key ./AuthKey_XXXXX.p8 > private_key.jwk
./jose.phar key:convert:public private_key.jwk > public_key.jwk
And this last line doesn't work
@michelvermeulen you forgot to read the file to get the jwk (using cat
as per the example).
My mistake. The update line should row work fine
Thank guys! The script works this way, it didn't solve my problem with Apple Sign In but at least I can now generate a client secret and send the request.
Here's the JWT I generate to init the Oauth (don't know if this is the right place to ask, sorry):
# Your 10-character Team ID
$iss = 'XXXXXXXXXX';
# Your Services ID, e.g. com.aaronparecki.services
$sub = 'com.xxxxxx.web';
# Find the 10-char Key ID value from the portal
$kid = 'XXXXXXXXXX';
$header = [
'alg' => 'ES256',
'kid' => $kid
];
$body = [
'iss' => $iss,
'iat' => time(),
'exp' => time() + 3600,
'aud' => 'https://appleid.apple.com',
'sub' => $sub
];
$privKey = openssl_pkey_get_private("file://" . app_path('private_key.pem'));
if (!$privKey) {
return false;
}
$payload = $this->encode(json_encode($header)) . '.' . $this->encode(json_encode($body));
$signature = '';
$success = openssl_sign($payload, $signature, $privKey, OPENSSL_ALGO_SHA256);
if (!$success) return false;
$raw_signature = $this->fromDER($signature, 64);
return $payload . '.' . $this->encode($raw_signature);
And when using Socialite::driver('apple')->user()
on the redirect page I get a
It was not possible to parse your key, reason: error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib
This worked for me. The -nocrypt
option is important.
openssl pkcs8 -nocrypt -in AuthKey_XXXXXXXXXX.p8 -traditional -out AuthKey.pem
base64 -w 0 < ./AuthKey.pem
then paste its output:
$configuration = Configuration::forSymmetricSigner(
new Sha256(),
InMemory::base64Encoded('Paste=here=the=base64=output===')
);
Here are more details.
@karser this is curious... In https://github.com/lcobucci/jwt/issues/819#issuecomment-1028934299 we confirmed that PEM PKCS8 keys work out of the box with the PHP openssl extension.
The problem they had was actually related to requirements of Apple's API regarding the exp claim (must be short lived).
Is your use case different from the author of the other thread?
@lcobucci Well, my case is Sign-in with Apple. I was using v3 of this library (requirement from other deps), Probably I need to try the v4.
Hello, having shame issue, and trying to follow the instructions as shown here, but it looks @Spomky provided links are now broken (404):
https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
Any suggestions?
Hi, it is still available, but not at the axact same URL https://github.com/web-token/jwt-app/releases
Hi there,
The new MapKit JS by Apple uses JWT, however, Apple gives a .p8 certificate which only holds a private key. How can I use this to verify the signature?
Thanks!