Skip to content

Instantly share code, notes, and snippets.

@rlanyi
Last active July 10, 2024 21:33
Show Gist options
  • Save rlanyi/f3edad3bd2f1753a937f8a0c6182d55a to your computer and use it in GitHub Desktop.
Save rlanyi/f3edad3bd2f1753a937f8a0c6182d55a to your computer and use it in GitHub Desktop.
How to create Apple PKPass .p12 certificate using Linux
published: true

How to create Apple PKPass .p12 certificate using Linux

You don't need a Mac to do this :-)

For generating PKPass files, you'll need 4 things after this tutorial:

  • Certificate Identifier (pass.com.example.www)
  • Team Identified (Organizational Unit (OU) in the cert generated by Apple)
  • The .p12 file
  • The password for the .p12 file
  1. Login on https://developer.apple.com/account/
  2. Click Certificates, Identifiers & Profiles
  3. Click on Identifiers
  4. On the right, filter to Pass Type IDs
  5. Register a New Identifier, choose Pass Type IDs
  6. Enter Description and Identifier
  7. Finalize by clicking Register
  8. Go to terminal and generate a private key (.key)
openssl genrsa -out pkpass.key 2048
  1. Generate a certificate singing request (.csr)
openssl req -new -key pkpass.key -out pkpass.csr

Fill in the fields with your own data but leave Challenge password empty (press Enter).

  1. On the Developer Portal choose the newly created identifier from the list and click Create Certificate.
  2. Leave the Certificate name empty and upload the .csr file
  3. On the next page click Download and save the downloaded pass.cer to the folder with the .key and .csr files
  4. Download Apple's root certificate (Apple Worldwide Developer Relations Certification Authority)
wget http://developer.apple.com/certificationauthority/AppleWWDRCA.cer
  1. Convert .cer files to .pem format
openssl x509 -inform der -in AppleWWDRCA.cer -out AppleWWDRCA.pem
openssl x509 -inform der -in pass.cer -out pass.pem
  1. Generate the .p12 certificate by using the private key, your certificate and Apple's certificate
openssl pkcs12 -export -clcerts -inkey pkpass.key -in pass.pem -certfile AppleWWDRCA.pem -name "Company Name" -out pkpass.p12

You'll be requested to enter a password. Choose a strong password here. You'll use this password with the .p12 certificate when generating PKPass files.

Please note that the .p12 contains both certificates and a private key as well. Make sure that you distribute it securely to the server that will generate PKPass files and that it is only readable by the PKPass generator application.

  1. You can check the contents of your newly created .p12 certificate
openssl pkcs12 -in pkpass.p12 -nodes

Please note the OU field of the first certificate in the output. This is your Team Identifier.

  1. Create a reminder in your calendar with the expiration date of your certificate.
openssl x509 -in pass.pem -noout -enddate
@cialog
Copy link

cialog commented Feb 16, 2022

I just got the Email from Apple about new Certificates:
"... As a reminder, the intermediate certificate updates are now available for the Apple Push Notification service (APNs) and Developer ID.
Apple Worldwide Developer Relations Intermediate Certificate (G4)
APNs SSL certificates are now issued from a new intermediate certificate (Worldwide Developer Relations G4 sub CA) exclusively focused on APNs. Use this certificate to send push notifications to apps (including VoIP), complications, websites on Safari, and Apple Wallet passes. ..."

https://www.apple.com/certificateauthority/

So is your instruction

wget http://developer.apple.com/certificationauthority/AppleWWDRCA.cer

still valid or should I choose a different .cer ?

@jamiembrown
Copy link

Hey @rlanyi ! Thanks so much! This is all excellent and got me so close to succeeding in my task too.

I wasn't doing a PKPass cert, but I was getting a new Apple Push certificate for my Python app running on Ubuntu - using the Pr0Ger/PyAPNs2 library. But although your steps got me close, with the G4 certificate it didn't work - I just got errors like this in my app:

[SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:1076)

I messed around for ages to get it working, and thought I'd share in case someone else hits the same snag - which they probably will since the current batch of push certs are expiring and all new ones are G4 ones.

Fundamentally I needed two CA certs that my computer couldn't see:

  • Apple Inc. Root
  • Worldwide Developer Relations - G4

So I needed to download both of these:

https://www.apple.com/appleca/AppleIncRootCertificate.cer
https://www.apple.com/certificateauthority/AppleWWDRCAG4.cer

Convert them both to pem files:

openssl x509 -inform der -in AppleIncRootCertificate.cer -out AppleIncRootCertificate.pem
openssl x509 -inform der -in AppleWWDRCAG4.cer -out AppleWWDRCAG4.pem

Combine them into one file, called AppleCerts.pem in a text editor, looking like this:

-----BEGIN CERTIFICATE-----
MIIEVTCCAz2gAwIBAgIUE9x3lVJx5T3GMujM/+Uh88zFztIwDQYJKoZIhvcNAQEL
BQAwYjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsT
HUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBS
b290IENBMB4XDTIwMTIxNjE5MzYwNFoXDTMwMTIxMDAwMDAwMFowdTFEMEIGA1UE
Aww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkxCzAJBgNVBAsMAkc0MRMwEQYDVQQKDApBcHBsZSBJbmMu
MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAf
eKp6JzKwRl/nF3bYoJ0OKY6tPTKlxGs3yeRBkWq3eXFdDDQEYHX3rkOPR8SGHgjo
v9Y5Ui8eZ/xx8YJtPH4GUnadLLzVQ+mxtLxAOnhRXVGhJeG+bJGdayFZGEHVD41t
QSo5SiHgkJ9OE0/QjJoyuNdqkh4laqQyziIZhQVg3AJK8lrrd3kCfcCXVGySjnYB
5kaP5eYq+6KwrRitbTOFOCOL6oqW7Z+uZk+jDEAnbZXQYojZQykn/e2kv1MukBVl
PNkuYmQzHWxq3Y4hqqRfFcYw7V/mjDaSlLfcOQIA+2SM1AyB8j/VNJeHdSbCb64D
YyEMe9QbsWLFApy9/a8CAwEAAaOB7zCB7DASBgNVHRMBAf8ECDAGAQH/AgEAMB8G
A1UdIwQYMBaAFCvQaUeUdgn+9GuNLkCm90dNfwheMEQGCCsGAQUFBwEBBDgwNjA0
BggrBgEFBQcwAYYoaHR0cDovL29jc3AuYXBwbGUuY29tL29jc3AwMy1hcHBsZXJv
b3RjYTAuBgNVHR8EJzAlMCOgIaAfhh1odHRwOi8vY3JsLmFwcGxlLmNvbS9yb290
LmNybDAdBgNVHQ4EFgQUW9n6HeeaGgujmXYiUIY+kchbd6gwDgYDVR0PAQH/BAQD
AgEGMBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBCwUAA4IBAQA/Vj2e5bbD
eeZFIGi9v3OLLBKeAuOugCKMBB7DUshwgKj7zqew1UJEggOCTwb8O0kU+9h0UoWv
p50h5wESA5/NQFjQAde/MoMrU1goPO6cn1R2PWQnxn6NHThNLa6B5rmluJyJlPef
x4elUWY0GzlxOSTjh2fvpbFoe4zuPfeutnvi0v/fYcZqdUmVIkSoBPyUuAsuORFJ
EtHlgepZAE9bPFo22noicwkJac3AfOriJP6YRLj477JxPxpd1F1+M02cHSS+APCQ
A1iZQT0xWmJArzmoUUOSqwSonMJNsUvSq3xKX+udO7xPiEAGE/+QF4oIRynoYpgp
pU8RBWk6z/Kf
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
+FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
UKqK1drk/NAJBzewdXUh
-----END CERTIFICATE-----

And then use, instead of your final command:

openssl pkcs12 -export -clcerts -inkey pkpass.key -in aps.pem -certfile AppleCerts.pem -name "Company Name" -out pkpass.p12 -chain

Once I had done that I could use this to generate the pem file I needed for Pr0Ger/PyAPNs2 to work:

openssl pkcs12 -in pkpass.p12 -nodes -out the-final.pem

And if it's all working you should be able to verify it like this:

openssl verify -CAfile AppleCerts.pem the-final.pem

Even after that, there's one final obstacle - the pem worked on my dev machine but still didn't work on the server Ubuntu box.

I needed to make OpenSSL aware of those CA certs too, so I copied the AppleIncRootCertificate.pem and AppleWWDRCAG4.pem files to my Linux box, renamed them to end with .crt rather than .pem and moved them to here:

/usr/local/share/ca-certificates

And then ran:

sudo update-ca-certificates

It should tell you it installed two certificates:

ubuntu@app:/usr/local/share/ca-certificates$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
2 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

Once you've done that, OpenSSL is ready to use your new PEM file.

Apple likes to make this stuff as complicated as possible, right? There's no other web service in the world where you have to jump through these hoops to send a message.

@rlanyi
Copy link
Author

rlanyi commented Nov 13, 2022

@jamiembrown very nice, thanks for the detailed description!

@jrmadsen67
Copy link

Thanks for these instructions - this was incredibly helpful!

Couple of update notes:

You now need the G4 certificate version or better (you can find them all at https://www.apple.com/certificateauthority/ )

so wget http://developer.apple.com/certificationauthority/AppleWWDRCA.cer
becomes: wget https://www.apple.com/certificateauthority/AppleWWDRCAG4.cer

and then change to AppleWWDRCAG4 throughout the steps

@Corneliuus
Copy link

What is the purpose of creating the .p12 certificate? Can't you sign the passes just by using the two .pem files and your private key created in step 8?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment