iosin-app-purchaseapp-storeapp-store-connect

"PEM routines::no start line" With "SignedDataVerifier" in Production


I'm validating subcription from an Apple's IAP Receipt using app-store-server-library-node. Everything is fine during dev in Apple's "Sandbox" mode.

Once I upload my app and run it from a testFlight build I've go this error:

Error: error:0480006C:PEM routines::no start line at new X509Certificate (node:internal/crypto/x509:119:21) at /opt/app/node_modules/@apple/app-store-server-library/jws_verification.ts:55:65 at Array.map () at new SignedDataVerifier (/opt/app/node_modules/@apple/app-store-server-library/jws_verification.ts:55:53)

Here is how I initiate the call :

(keys and ids have been changed for obvious security reason)


    const issuerId = '6f1337a3-1234-4929-9ccd-774e8c02fa18';
    const keyId = 'FG7N3NY68Y';
    const bundleId = 'com.appname.app';
    const teamId = '6JZPD4JMSJ';
    
    // appAppleId is required when the environment is Production
    const appAppleId = teamId+"."+bundleId;
    const appleEnv = Environment.PRODUCTION;

    const filePath = path.join(ROOT_FOLDER, `/keys/AppleApi_AuthKey_${keyId}.p8`);
    const privateKey = fs.readFileSync(filePath, 'utf8');

    const client = new AppStoreServerAPIClient(privateKey, keyId, issuerId, bundleId, appleEnv);

    const appleRootCAs = [
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleIncRootCertificate.cer')),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleComputerRootCertificate.cer')),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G2.cer')),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G3.cer')),
    ];
    const enableOnlineChecks = true;

    console.log('privateKey = ', privateKey);

    const verifier = new SignedDataVerifier(appleRootCAs, enableOnlineChecks, appleEnv, bundleId, appAppleId);

I'm first trying to run in Production env then in sandbox as requested in apple's documentation. The files are correctly read. Login private key shows:

privateKey = -----BEGIN PRIVATE KEY----- MIGTAbEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4n35kqKOEJA5ITBZ lf5QfWlaj1re4R60jFflAmzfJQKgCgYIKoZIzj0DABehRANCAATvNxWUh/WGfw+q OW1kMsTRNyBN7IwS861VjFvtQKN7r8wlvG1jTw+vTpsv/84xZw/H+IDmFLnOkAbS yRfk1PcT -----END PRIVATE KEY-----

more log values :

enableOnlineChecks : true

environment : Production

bundleId : com.appname.app

appAppleId : 6JZPD4JMSJ.com.appname.app <= is this appId format correct ?

(All keys and appname/ team id have been change for obvious security reason)

Can you see anything I do wrong ?

Should we "enableOnlineChecks" ?

Thank you for your help.


Solution

  • The "PEM routines::no start line" error is referenced a lot on the web when trying to decode a .PEM file certificate with format :

    -----BEGIN PRIVATE KEY----- MIGTAbEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4n35kqKOEJA5ITBZ lf5QfWlaj1re4R60jFflAmzfJQKgCgYIKoZIzj0DABehRANCAATvNxWUh/WGfw+q OW1kMsTRNyBN7IwS861VjFvtQKN7r8wlvG1jTw+vTpsv/84xZw/H+IDmFLnOkAbS yRfk1PcT -----END PRIVATE KEY-----

    I've fix the issue by replacing Apple's root certificate binary files ( .cer ) with .pem files.

    Change the file format of each root certificate file using:

    openssl x509 -inform der -in AppleRootCA-G3.cer -out AppleRootCA-G3.pem
    

    Then reference them in the code using

    const appleRootCAs = [
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleIncRootCertificate.pem'), 'utf-8'),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleComputerRootCertificate.pem'), 'utf-8'),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G2.pem'), 'utf-8'),
      fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G3.pem'), 'utf-8'),
    ];
    

    Don't forget the second parameter on each line: " 'utf-8')," as we are now decoding a string from the .pem file.

    This is solving the issue.