Hyperledger Fabric - PKCS8 private keys from identity javascript Object

Viewed 39

I am building a project using hyperledger fabric running on a local IBM MicroFab blockchain network. I have been experiencing issues in regard to identity and retrieving connection information from the MicroFab api (/ak/api/v1/components). Formatting the private key and certificate properly seems to be the fix to me but I am dumbfounded on a solution. Microfab unfortunately does not have any or much documentation.

error:

malformed plain PKCS8 private key(code:001)

The returned json object from the api contains the following information (long key text omitted):

[
  {
    id: 'p0000admin',
    display_name: 'p0000 Admin',
    type: 'identity',
    cert: 'LS0tLS.....0tLS0tCg==',
    private_key: 'LS0t....FIEtFWS0tLS0tCg==',
    ca: 'LS0tL....LS0tCg==',
    msp_id: 'p0000MSP',
    wallet: 'p0000',
    hide: false
  }
]

I am currently taking the first and only json within this object and pulling out the Private key and Certificate strings, which is then concatenated within the following identity object which is my attempt to convert the raw keys to PEM:

const identityLabel = `p${userid} Admin`;
  const identity = {
    credentials: {
        certificate: `-----BEGIN CERTIFICATE-----\n${rawcertificate}\n-----END CERTIFICATE-----\n`,
        privateKey: `-----BEGIN PRIVATE KEY-----\n${rawprivatekey}\n-----END PRIVATE KEY-----\n`,
    },
    mspId: `p${userid}MSP`,
    type: 'X.509',
};

my console error is as follows:

error: [crypto_ecdsa_aes]: createKeyFromRaw - Failed to parse key from PEM:  message=malformed plain PKCS8 private key(code:001), stack=Error: malformed plain PKCS8 private key(code:001)
    at Object.parsePlainPrivatePKCS8Hex (/home/tylr/Documents/IEEE/next-energychain/node_modules/jsrsasign/lib/jsrsasign.js:238:5296)
    at Object.getKeyFromPlainPrivatePKCS8Hex (/home/tylr/Documents/IEEE/next-energychain/node_modules/jsrsasign/lib/jsrsasign.js:238:6073)
    at Object.getKeyFromPlainPrivatePKCS8PEM (/home/tylr/Documents/IEEE/next-energychain/node_modules/jsrsasign/lib/jsrsasign.js:238:5975)
    at KEYUTIL.getKey (/home/tylr/Documents/IEEE/next-energychain/node_modules/jsrsasign/lib/jsrsasign.js:238:11905)
    at CryptoSuite_ECDSA_AES.createKeyFromRaw (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js:132:18)
    at X509Provider.getUserContext (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-network/lib/impl/wallet/x509identity.js:61:46)
    at Gateway.connect (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-network/lib/gateway.js:257:41)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async evaluateTransaction (webpack-internal:///(api)/./hyperledger/api-EvaluateTransaction.js:82:9)
API failed to fetch: Error: Failed to parse key from PEM: Error: malformed plain PKCS8 private key(code:001)
    at CryptoSuite_ECDSA_AES.createKeyFromRaw (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js:135:10)
    at X509Provider.getUserContext (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-network/lib/impl/wallet/x509identity.js:61:46)
    at Gateway.connect (/home/tylr/Documents/IEEE/next-energychain/node_modules/fabric-network/lib/gateway.js:257:41)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async evaluateTransaction (webpack-internal:///(api)/./hyperledger/api-EvaluateTransaction.js:82:9)

Project code below:

const microfabjson = await fetch('http://console.127.0.0.1.nip.io:8081/ak/api/v1/components', { 
    headers: {
      'Accept': 'application/json',
      'Path': '/',
    }
  })
    .then(response => response.json())
  
  // console.log(res)
  console.log(microfabjson)


  const connectionProfile = microfabjson.filter(obj=> obj.type == "gateway" && obj.wallet == `p${userid}`)
  const identity_json = microfabjson.filter(obj=> obj.type == "identity" && obj.id == `p${userid}admin`)
  const rawcertificate = identity_json[0].cert
  const rawprivatekey = identity_json[0].private_key
  const mspid = identity_json[0].msp_id

  const identityLabel = `p${userid} Admin`;
  const identity = {
    credentials: {
        certificate: `-----BEGIN CERTIFICATE-----\n${rawcertificate}\n-----END CERTIFICATE-----\n`,
        privateKey: `-----BEGIN PRIVATE KEY-----\n${rawprivatekey}\n-----END PRIVATE KEY-----\n`,
    },
    mspId: `p${userid}MSP`,
    type: 'X.509',
};
1 Answers

It seems that the certificates and private keys returned by the Microfab REST API are the complete PEM-encoded content, additionally base64-endoded. So if you just base64 decode the raw cert and private_key fields then you have the complete PEM with no need to add the BEGIN and END elements.

For example, on my system:

const http = require('http');

http.get('http://console.127.0.0.1.nip.io:8080/ak/api/v1/components', response => {
    const chunks = [];
    response.on('data', chunk => chunks.push(chunk));
    response.on('end', () => {
        const data = chunks.join('');
        JSON.parse(data)
            .filter(entry => entry.type === 'identity')
            .forEach(entry => {
                const certificate = Buffer.from(entry.cert, 'base64').toString();
                const privateKey = Buffer.from(entry.private_key, 'base64').toString();
                const credentials = { certificate, privateKey };
                console.log(`${entry.id}:`, credentials);
            });
    });
}).on('error', console.error);

Gives this output (with all but one identity removed to keep it concise!):

ordereradmin: {
  certificate: '-----BEGIN CERTIFICATE-----\n' +
    'MIIB1TCCAXugAwIBAgIRAICUAsKQVM5DKllfmC7us6swCgYIKoZIzj0EAwIwFTET\n' +
    'MBEGA1UEAxMKT3JkZXJlciBDQTAeFw0yMjA5MjEwOTE2MTBaFw0zMjA5MTgwOTE2\n' +
    'MTBaMCgxDjAMBgNVBAsTBWFkbWluMRYwFAYDVQQDEw1PcmRlcmVyIEFkbWluMFkw\n' +
    'EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErYZwEFjbqYvkpaCok27K1GK9jsYAzcR3\n' +
    'vwIo0YwMN6/G/na/tJiDYxI7vSwhVrWhmUjXCNQDUQcesrrNEFWFhqOBmDCBlTAO\n' +
    'BgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwG\n' +
    'A1UdEwEB/wQCMAAwKQYDVR0OBCIEIHg+NWsNrjwB99CSjRhY/mJUeIJ2uFl3LpXp\n' +
    'pworjoY5MCsGA1UdIwQkMCKAINKbV22Xkrv6Ok0W8GfZqqpr6QBLHjTCAg9WTAJm\n' +
    'tRAfMAoGCCqGSM49BAMCA0gAMEUCIDKWitYF0Pg0YdFOOyXhmYGXSpmYsKaQHbFb\n' +
    'hDLx7ktYAiEAuhrXUaXvddGAMotkpRfTEbXCvG1gDlg74dNt2Qg/qMk=\n' +
    '-----END CERTIFICATE-----\n',
  privateKey: '-----BEGIN PRIVATE KEY-----\n' +
    'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCNjF+ONc9zVWoqzN\n' +
    'V/KlGxzHRXowo/8EVseqj8svTAGhRANCAASthnAQWNupi+SloKiTbsrUYr2OxgDN\n' +
    'xHe/AijRjAw3r8b+dr+0mINjEju9LCFWtaGZSNcI1ANRBx6yus0QVYWG\n' +
    '-----END PRIVATE KEY-----\n'
}
Related