3

I am trying to make a request from my Firebase function to a custom server that requires a certficate (.pfx). Based on this answer:

Upload TLS client certificate to Firebase cloud functions

My code is as follows:

const functions = require('firebase-functions');
const request = require('request');

var fs = require('fs');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

exports.postBankId = functions.https.onRequest(async (req, res) => {
  console.log('PostBankId');
  const ipAddress = req.query.ipAddress;
  const requestBody = '{ "endUserIp": "' + ipAddress +'" }';
  console.log('requestBody:', requestBody); 
  const options = {
      url: 'https://appapi2.test.bankid.com/rp/v5/auth',
      json: true,
      pfx: fs.readFileSync('bankidtest.pfx'),
      passphrase: 'myPassPhraseHere',
      body: requestBody
  }

  request.post(options, (err, response) => {
      if (err) {
            console.log('bankid creation error: ' + JSON.stringify(err))
            res.status(500).send('Failed with error: ' + JSON.stringify(err));
      }
      if (response) {
          res.status(200).send('Success');
          console.log('Succes body: ' + response.body)
      }
  });
});

The answer I get:

{"code":"UNABLE_TO_VERIFY_LEAF_SIGNATURE"}

I place the bankidtest.pfx in the same folder as index.js. And it seems to be uploaded, because if removing it produces another error:

Error: could not handle the request

Edit1:

placing the path to the cert in agentOptions does not work either. Gives same UNABLE_TO_VERIFY_LEAF_SIGNATURE error.

var options = {
    url: 'https://appapi2.test.bankid.com/rp/v5/auth',
    headers: {
        "content-type": "application/json",
    },
    agentOptions: {
        pfx: fs.readFileSync('bankidtest.pfx'),
        passphrase: '********'
    }
};

Edit2: Got it semi-working. Setting the request-parameter "rejectUnauthorized" to "false", makes the request work. But according to BankId, this is not a safe or recommended way. The semi-working code is:

  request({
    url: "https://appapi2.test.bankid.com/rp/v5/auth",
    host: "appapi2.test.bankid.com",
    rejectUnauthorized: false, // This like makes it work
    requestCert: true,
    method: "POST",
    headers: {
        "content-type": "application/json", 
        'Connection': "Keep-Alive"
    },

    body: requestBody,
    agentOptions: {
        pfx: fs.readFileSync('bankidtest.pfx'),
        passphrase: '*****'
    },

Edit3: Tried npm install ssl-root-cas and then added this to the top of my index.js:

var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()

But then I got this error:

Error: EROFS: read-only file system, open '/srv/node_modules/ssl-root-cas/pems/mozilla-certdata.txt'
   at Object.fs.openSync (fs.js:646:18)
   at Object.fs.writeFileSync (fs.js:1299:33)
   at /srv/node_modules/ssl-root-cas/ca-store-generator.js:219:10
   at IncomingMessage.<anonymous> 
     (/srv/node_modules/@coolaj86/urequest/index.js:154:9)

Edit4: Tried these instead for depricated inject() but without success. No read-only-error this time, but still UNABLE_TO_VERIFY_LEAF_SIGNATURE:

var rootCas = require('ssl-root-cas/latest').create();

//rootCas.addFile(__dirname + '/mycerts.crt');
rootCas.addFile('mycerts.cer');
rootCas.addFile('mycerts.crt');
rootCas.addFile('bankidtest.pfx'); // Also tried with __dirname

require('https').globalAgent.options.ca = rootCas;

// Also tried this:
//require('https').globalAgent.options.ca = require('ssl-root-cas').rootCas

Edit5 Solved it

Seemed as a CA was needed that was not derived from the pfx file.

Sunkas
  • 9,542
  • 6
  • 62
  • 102
  • Check this [answer](https://stackoverflow.com/a/22263280/12232507). – Emil Gi Mar 13 '20 at 10:54
  • "This package contains many intermediary certificates that browsers trust but node doesn't." You think this url contains certificates that will make the request work. Sounds odd to me. I have the certificate on file. That link does not sound like it's gonna work. – Sunkas Mar 13 '20 at 11:30
  • Tried it. See Edit 3 above. – Sunkas Mar 13 '20 at 11:54
  • According to his github page inject() is deprecated. Try using [this](https://git.coolaj86.com/coolaj86/ssl-root-cas.js#user-content-rootcas) – Emil Gi Mar 13 '20 at 12:07
  • Just for context, I understand this issue so that nodejs doesn't trust the CA that issued your certificate and rejects it. This library tries to solve this by adding a lot of CAs to nodejs's trusted list. – Emil Gi Mar 13 '20 at 12:10
  • Now it does not give me read-only error, but still gives me `UNABLE_TO_VERIFY_LEAF_SIGNATURE` error. See Edit4. – Sunkas Mar 13 '20 at 12:42
  • 1
    Maybe your CA is not present in this library. Try workaround from [this answer](https://stackoverflow.com/a/25591249/12232507) – Emil Gi Mar 13 '20 at 13:13
  • 1
    As for your edit 4, you are using 'request' module, I think you should add it like this: `agentOptions: {..., ca: rootCas}`. – Emil Gi Mar 13 '20 at 13:28
  • Hmm, I think I solved it. The CA was not added. It thought it could be generated from the pfx file, but BankId did provide this in text-form. So adding the cert-text (starting with -----BEGIN CERTIFICATE) to a pem-fil and adding it according to Edit5 did the trick! – Sunkas Mar 13 '20 at 16:32

1 Answers1

1

Bank-ID provided a CA as a text in their documentation. Starting with "-----BEGIN CERTIFICATE"... I copied the text into a pem file and referenced it from my index.js-file like this:

agentOptions: {
    pfx: fs.readFileSync('bankidtest.pfx'),
    passphrase: '*****',
    ca: fs.readFileSync('certificate.pem')
},
Sunkas
  • 9,542
  • 6
  • 62
  • 102