Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to fetch certificate #88

Closed
AiNoKame opened this issue Nov 8, 2017 · 13 comments
Closed

Unable to fetch certificate #88

AiNoKame opened this issue Nov 8, 2017 · 13 comments

Comments

@AiNoKame
Copy link

AiNoKame commented Nov 8, 2017

I just started using graphene, and I'm trying to read a certificate in plain text that I stored using SoftHSMv2. Here's all I've done:

  1. Convert regular PEM formatted private certificate to PKCS#8 format
> openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
-in /Users/AiNoKame/old-key.pem \
-out /Users/AiNoKame/Documents/GitHub/SoftHSMv2/new-key.pem
  1. Initialize token
> softhsm2-util --init-token --slot 0 --label "test"
=== SO PIN (4-255 characters) ===
Please enter SO PIN: **** (1234)
Please reenter SO PIN: **** (1234)
=== User PIN (4-255 characters) ===
Please enter user PIN: **** (9876)
Please reenter user PIN: **** (9876)
The token has been initialized and is reassigned to slot 475181359
  1. Import private certificate into token
> softhsm2-util \
--import /Users/AiNoKame/Documents/GitHub/SoftHSMv2/new-key.pem \
--no-public-key \
--slot 475181359 --label "new-key" --id abcd1234 --pin 9876
  1. Run a simple nodejs app using graphene to fetch certificate
const graphene = require('graphene-pk11')
const {parseCertificate} = require('./parse_certificate')
const mod = graphene.Module.load('/usr/local/lib/softhsm/libsofthsm2.so', 'SoftHSM')

mod.initialize()

const session = mod.getSlots(0).open()

session.login('9876')

const fetchedCertificates = session.find({label: 'new-key'})
const certificate = fetchedCertificates.items(0).toType()

console.log(`======= certificate: `, certificate)
console.log(`======= Object.getOwnPropertyNames(certificate): `, Object.getOwnPropertyNames(certificate))
console.log(`======= certificate.lib: `, certificate.lib)
console.log(`======= certificate.handle: `, certificate.handle)
console.log(`======= certificate.handle.toString('hex'): `, certificate.handle.toString('hex'))
console.log(`======= certificate.id.toString('hex'): `, certificate.id.toString('hex'))
console.log(`======= certificate.label: `, certificate.label)
console.log(`======= certificate.subject: `, certificate.subject)
console.log(`======= certificate.value: `, certificate.value)

mod.finalize()

Output:

======= certificate:  PrivateKey {
  handle: <Buffer 02 00 00 00 00 00 00 00>,
  session:
   Session {
     handle: <Buffer 01 00 00 00 00 00 00 00>,
     slot:
      Slot {
        handle: <Buffer 2f b1 52 1c 00 00 00 00>,
        module: [Object],
        slotDescription: 'SoftHSM slot ID 0x1c52b12f',
        manufacturerID: 'SoftHSM project',
        flags: 1,
        hardwareVersion: [Object],
        firmwareVersion: [Object] },
     state: 0,
     flags: 4,
     deviceError: 0 } }
======= Object.getOwnPropertyNames(certificate):  [ 'lib', 'handle', 'session' ]
======= certificate.lib:  PKCS11 {}
======= certificate.handle:  <Buffer 02 00 00 00 00 00 00 00>
======= certificate.handle.toString('hex'):  0200000000000000
======= certificate.id.toString('hex'):  abcd1234
======= certificate.label:  new-key
======= certificate.subject:  <Buffer >
======= certificate.value:  undefined

I'm not seeing the certificate contents in my certificate object at all!

Any help would be appreciated!

@microshine
Copy link
Contributor

microshine commented Nov 8, 2017

Hello!

As I can see from your steps you don't import certificate to SoftHSM. You use PKCS#8 which is private key and import it to SoftHSM

Eech SessionObject has class property which you can use to understand what object class do you have
https://github.com/PeculiarVentures/graphene/blob/master/index.d.ts#L343

There is another npm module which allows to use PKCS#11 tokens easier node-webcrypto-p11

you can get list of allowed keys or certificates by using CryptoStorage
https://github.com/PeculiarVentures/node-webcrypto-p11#key-storage
https://github.com/PeculiarVentures/node-webcrypto-p11#certificate-storage

@AiNoKame
Copy link
Author

AiNoKame commented Nov 8, 2017

@microshine Thanks for the quick response! 😄 Regarding node-webcrypto-p11, I was a bit worried when I saw this https://www.npmjs.com/package/node-webcrypto-p11#warning

Question 1: Is there a way to get the certificate contents via only graphene?

Also regarding your comment:

As I can see from your steps you don't import certificate to SoftHSM. You use PKCS#8 which is private key and import it to SoftHSM

Question 2: Do you mean according to my steps, I forgot to import the certificate to SoftHSM (I thought I did in step 2 😉 )? Or do you mean, I shouldn't use SoftHSM to import the certificate?

Follow-up question (that's more about the use of SoftHSM 😅 ):

Question 3: Is there a way to import a certificate using softhsm2-util --import so that graphene recognizes the certificate as an x509 certificate instead of a public/private key?

@microshine
Copy link
Contributor

1

You can use this example. I use filter for find function. objects contains all certificates from token

var graphene = require("graphene-pk11");

const lib = "/usr/local/lib/softhsm/libsofthsm2.so";

const mod = graphene.Module.load(lib, "LIB");
mod.initialize();

try {
    const slot = mod.getSlots(0);
    const session = slot.open(4);

    const objects = session.find({class: graphene.ObjectClass.CERTIFICATE});
    for (let i=0; i<objects.length; i++) {
        const cert = objects.items(i).toType();

        console.log(cert.value.toString("hex"));
    }

} catch (e) {
    console.error(e);
}

mod.finalize();

2

You use

--import /Users/AiNoKame/Documents/GitHub/SoftHSMv2/new-key.pem

As I can see it's private key. I don't see openssl certificate creation and cert.pem file importing

3

It looks you cannot use softhsm2-util to import certificate

--import <path>   Import a key pair from the given path.
                  The file must be in PKCS#8-format.
                  Use with --slot or --token or --serial, --file-pin,
                  --label, --id, --no-public-key, and --pin.

You can use graphene to do it https://github.com/PeculiarVentures/node-webcrypto-p11/blob/master/lib/cert.ts#L181

@AiNoKame
Copy link
Author

AiNoKame commented Nov 9, 2017

@microshine 😄 Thanks again for the quick response! I've tried several things since yesterday, but I still can't find a way to see my private certificate contents in plain text 😞

  1. First, re-initialized my token and used pkcs11-tool to generate a fresh key pair in case the issue was my imported private key:
pkcs11-tool --module=/usr/local/lib/softhsm/libsofthsm2.so -l -k \
-d abcd1234 -a new-key --key-type rsa:2048
  1. I copied your code completely from Answer 1 above, and nothing was logged

  2. I tried using your suggested node-webcryto-p11 module and wrote another small node app:

const p11 = require('node-webcrypto-p11')

const crypto = new p11.WebCrypto({
  library: '/usr/local/lib/softhsm/libsofthsm2.so',
  slot: 0,
  readWrite: true
})

Promise.resolve()
.then(() => crypto.keyStorage.keys())
.then(indexes => {
  console.log('\n\n========== indexes', indexes)
  return crypto.keyStorage.getItem(indexes[0])
})
.then(cert => {
  console.log('\n\n========== cert', cert)
  console.log('\n\n========== cert.toJSON()', cert.toJSON())
})
.catch(error => {
  console.error('ERROR', error)
})

Output:

========== indexes [ 'public-0200000000000000-abcd1234' ]


========== cert RsaCryptoKey {
  p11Object:
   PublicKey {
     handle: <Buffer 02 00 00 00 00 00 00 00>,
     session:
      Session {
        handle: <Buffer 01 00 00 00 00 00 00 00>,
        slot: [Object],
        state: 2,
        flags: 6,
        deviceError: 0 } },
  usages: [ 'encrypt', 'verify', 'wrapKey' ],
  type: 'public',
  extractable: true,
  algorithm:
   { name: 'RSASSA-PKCS1-v1_5',
     hash: { name: 'SHA-256' },
     modulusLength: 2048,
     publicExponent: Uint8Array [ 1, 0, 1 ] },
  id: 'public-0200000000000000-abcd1234' }


========== cert.toJSON() { algorithm:
   { name: 'RSASSA-PKCS1-v1_5',
     hash: { name: 'SHA-256' },
     modulusLength: 2048,
     publicExponent: Uint8Array [ 1, 0, 1 ] },
  type: 'public',
  usages: [ 'encrypt', 'verify', 'wrapKey' ],
  extractable: true }

...I'm not sure why indexes [ 'public-0200000000000000-abcd1234' ] only contained the public key (and not the private key, which is what I need), and even then, there was no plain text data that I could find in the public key

Am I completely on the wrong path here? I just want to be able to securely store a private key in my HSM and use a node module to fetch the private key in plain text for use in my node app

@microshine
Copy link
Contributor

It's not secure to put private key to HSM and then export it as plain text.

May I ask you? What are you using for exported private key? Maybe I can suggest you another way

Otherwise I can write example how to export private key from KeyStorage

@rmhrisk
Copy link
Contributor

rmhrisk commented Nov 9, 2017

Mainstream HSMs do not support clear text export of private keys. I think there must be some confusion here.

@AiNoKame
Copy link
Author

AiNoKame commented Nov 9, 2017

I'd love to see an example on how to export private key from KeyStorage! 😃

I have a pretty simple use case - I just want to store my private keys on an HSM and access those private keys using a node module when creating my https node server (https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener)

@microshine
Copy link
Contributor

I see. You need PKCS#8 private key

// @ts-check
const { WebCrypto } = require("node-webcrypto-p11");

const crypto = new WebCrypto({
    library: '/usr/local/lib/softhsm/libsofthsm2.so',
    slot: 0,
    readWrite: true,
    pin: "12345", // you need login to get private objects
});

async function main() {
    if (crypto.isLoggedIn) {
        crypto.login("12345"); // you need login to get private objects
    }

    const indexes = await crypto.keyStorage.keys();
    let privateKey;
    for(const index of indexes) {
        const parts = index.split("-");
        if (parts[0] === "private") {
            privateKey = await crypto.keyStorage.getItem(index);
            break;
        }
    }

    if (privateKey) {
        // NOTE: You can export only exportable private key
        const raw = await crypto.subtle.exportKey("pkcs8", privateKey);
        const bufRaw = new Buffer(raw);
        
        console.log(bufRaw.toString("hex"));
    } else {
        console.log("Private key is not found");
    }
}

main()
    .catch((err) => {
        console.error(err);
    })

@microshine
Copy link
Contributor

bufRaw - PKCS#8 private key in DER format
If you need PEM you need to do it manually

@AiNoKame
Copy link
Author

Thanks for all the support so far, @microshine and @rmhrisk 😸 I think I'm asking for the impossible here 😆 I just opened up another ticket at nodejs (nodejs/help#964) now that I'm a bit more knowledgeable about the actual functionality of an HSM, but I'm doubtful regarding any positive response there

@rmhrisk
Copy link
Contributor

rmhrisk commented Nov 11, 2017

Re:

I have a pretty simple use case - I just want to store my private keys on an HSM and access those private keys using a node module when creating my https node server (https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener)

HSMs are used most commonly when keys live cradle to grave in the HSM.

@rmhrisk
Copy link
Contributor

rmhrisk commented Nov 11, 2017

FYI: Node crypto is a just a thin layer ontop of OpenSSL. It is possible to have node honor your OpenSSL configuration file when doing crypto, specifically with TLS. It is possible to specify a "OpenSSL engine module" in your configuration. You can usually get your HSM to be loaded in this fashion.

@AiNoKame
Copy link
Author

AiNoKame commented Nov 13, 2017

Thanks for the info, @rmhrisk ! I responded to your comment on the nodejs issue (nodejs/help#964) 😄 I'm going to close this issue on the graphene repo since I think it's evolved into a generic nodejs question, so if you happen to have any further comments, please add them to the nodejs thread!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants