PeculiarVentures / PKI.js

PKI.js is a pure JavaScript library implementing the formats that are used in PKI applications (signing, encryption, certificate requests, OCSP and TSP requests/responses). It is built on WebCrypto (Web Cryptography API) and requires no plug-ins.
http://pkijs.org
Other
1.25k stars 204 forks source link

Integration with external Key-Management Systems #344

Closed gnarea closed 2 years ago

gnarea commented 2 years ago

For security reasons, I'd like to move away from having private keys in the app's memory and use a KMS/HSM instead. This isn't currently supported, is it? The current implementation of PKI.js depends heavily on WebCrypto private keys, but I don't know if there's a way to make this work today.

I think one (ugly) way to make this work relatively easily is by having a webcrypto provider whose private CryptoKeys actually represent pointers to a key in a KMS/HSM. Of course, this would mean that methods like exportKey() would have to throw errors. This workaround would also require updating methods like EnvelopedData.decrypt() to take a CryptoKey private key (instead of or in addition to an ArrayBuffer) and EnvelopedData.encrypt() to take a private key when using DH (instead of generating one internally).

The ideal solution IMHO would be to make this explicit by creating an abstraction for private keys, which would only support a subset of operations; e.g.:

interface Key {
  getAlgorithm: () => AlgorithmIdentifier;
}

interface AsymmetricKey extends Key {
   getPublicKey: () => Promise<CryptoKey>;
}

interface SigningKey extends AsymmetricKey {
  sign: (...) => Promise<ArrayBuffer>;
}

interface EncryptionKey extends AsymmetricKey {
  encrypt: (...) => Promise<ArrayBuffer>;
}

interface SymmetricKey extends Key {
  encrypt: (...) => Promise<ArrayBuffer>;
  decrypt: (...) => Promise<ArrayBuffer>;
}

... but that'd be a much more invasive change.

Thoughts?

rmhrisk commented 2 years ago

See node-webcrypto-p11

gnarea commented 2 years ago

Thanks @rmhrisk!

I want to use GCP KMS, which offers a C library for PKCS#11, so it seems like I'd simply need to initialise the Crypto class in node-webcrypto-p11 with the path to GCP KMS' shared object libkmsp11.so.

However, the issues above with EnvelopedData would still prevent me from using node-webcrypto-p11, unless I'm missing something. I also use SignedData and Certificate, but I believe those are fine.

gnarea commented 2 years ago

FYI, I ended up integrating the @google-cloud/kms library in a new RSA-PSS provider. I may move it to a separate NPM package if other folks find it useful.

GCP KMS doesn't support (EC)DH, and our protocol only supports EnvelopedData with ECDH, so that's as far as I can take the KMS integration today.

rmhrisk commented 2 years ago

Sounds good