phpiossslsignpkcs#7

Creating a PKCS #7 detached signature for Apple Wallet passes using PHP


This is an entirely new concept to me, so I'm shooting in the dark.

To create the signature file, make a PKCS #7 detached signature of the manifest file, using the private key associated with your signing certificate. Include the WWDR intermediate certificate as part of the signature. You can download this certificate from Apple’s website. Write the signature to the file signature at the top level of the pass package. Include the date and time that the pass was signed using the S/MIME signing-time attribute.

My understanding:

To create the signature file, make a PKCS #7 detached signature of the manifest file

I'll be using the openssl_pkcs7_sign function using the flag PKCS7_DETACHED.

using the private key associated with your signing certificate.

I'll be using the location of my ssl cert.pem file as the signcert parameter and the location of the cert.key file as the privkey parameter.

Include the WWDR intermediate certificate as part of the signature.

I'll include the path to the WWDR certificate in the extracerts parameter

Include the date and time that the pass was signed using the S/MIME signing-time attribute.

I'll include a an array with a key signing-time and value something like 2015-05-03 10:40:00 for the headers parameter.

My code:

private function createSignature($dir)
{
    $cert = '/etc/ssl/cert.pem';
    $key = '/etc/ssl/private/cert.key';
    $wwdr = '/location/of/apple/wwdr/cert.cer';
    $headers = [
        'signing-time' => (new DateTime())->format('o-m-d H:i:s'),
    ];

    return openssl_pkcs7_sign("$dir/manifest.json", "$dir/signature", $cert, $key, $headers, PKCS7_DETACHED, $wwdr);
}

Other questions:

I've noticed in the examples of the documentation for the openssl_pkcs7_sign function that some locations of the files are prefixed with file://. Why is this?


Solution

    1. Generate a Pass Type ID at https://developer.apple.com/account/ios/identifier/passTypeId
    2. Create a certificate for that Pass Type ID at https://developer.apple.com/account/ios/certificate/create/
    3. Download the certificate and put it in your keychain
    4. Find the certificate in your keychain and export it as Certificates.p12 with no password
    5. Open terminal, run openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out pass_cert.pem -passin pass: to generate the certificate
    6. In terminal, run openssl pkcs12 -in Certificates.p12 -nocerts -out pass_key.pem -passin pass: -passout pass:YourPassword to generate the key
    7. Download the WWDR Certificate from https://www.apple.com/certificateauthority/ and put it in your keychain
    8. Export the WWDR Certificate from your keychain as wwdr.pem

    The function to create the detached signature:

    public function createSignature()
    {
        $cert = "file://location/of/pass_cert.pem";
        $key = "file://location/of/pass_key.pem";
        $wwdr = "/location/of/wwdr.pem";
    
        openssl_pkcs7_sign("/location/of/manifest.json", "/location/of/signature",
            $cert, [$key, 'YourPassword'], [], PKCS7_BINARY | PKCS7_DETACHED, $wwdr);
    
        // convert pem to der
        $signature = file_get_contents("/location/of/signature");
        $begin = 'filename="smime.p7s"';
        $end = '------';
        $signature = substr($signature, strpos($signature, $begin) + strlen($begin));
        $signature = substr($signature, 0, strpos($signature, $end));
        $signature = trim($signature);
        $signature = base64_decode($signature);
    
        file_put_contents("/location/of/signature", $signature);
    }
    

    References: