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

crypto: add key pair generation #22660

Closed

Conversation

tniessen
Copy link
Member

@tniessen tniessen commented Sep 2, 2018

At last: asymmetric key generation for Node.js! 🎉


I thought about the API design a lot, so if something feels strange to you, feel free to ask or make suggestions.

The new API supports RSA, DSA, EC and a variety of key encodings (both PEM and DER):

RSA (public) RSA (private) DSA (public) DSA (private) EC (public) EC (private)
PKCS#1 ✔️ ✔️ ✖️ ✖️ ✖️ ✖️
PKCS#1, encrypted ✖️ ✔️ ✖️ ✖️ ✖️ ✖️
SPKI ✔️ ✖️ ✔️ ✖️ ✔️ ✖️
PKCS#8 ✖️ ✔️ ✖️ ✔️ ✖️ ✔️
PKCS#8, encrypted ✖️ ✔️ ✖️ ✔️ ✖️ ✔️
SEC1 ✖️ ✖️ ✖️ ✖️ ✖️ ✔️
SEC1, encrypted ✖️ ✖️ ✖️ ✖️ ✖️ ✔️

This table has been updated according to #23151.

DER is not particularly useful with other Node.js APIs, but it is the only format supported by the WebCrypto standard and thus mainly exists here for interoperability, at least for now.


I understand that this might be difficult to review, so please feel free to ask any questions you might have. I also appreciate partial reviews. There is example code in the API documentation.

As always: cc @nodejs/security-wg @nodejs/crypto

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added the lib / src Issues and PRs related to general changes in the lib or src directory. label Sep 2, 2018
@addaleax addaleax added crypto Issues and PRs related to the crypto subsystem. semver-minor PRs that contain new features and should be released in the next minor version. labels Sep 2, 2018
@tniessen tniessen added c++ Issues and PRs that require attention from people who are familiar with C++. and removed lib / src Issues and PRs related to general changes in the lib or src directory. labels Sep 2, 2018
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
lib/internal/errors.js Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
src/node_crypto.cc Outdated Show resolved Hide resolved
@tniessen tniessen force-pushed the crypto-add-keypair-generation branch from d7ffa8f to 937dbaf Compare September 2, 2018 16:59
doc/api/crypto.md Outdated Show resolved Hide resolved
doc/api/crypto.md Outdated Show resolved Hide resolved
test/parallel/test-crypto-keygen.js Show resolved Hide resolved
@tniessen
Copy link
Member Author

tniessen commented Sep 2, 2018

@mcollina I understand your points and I tend to agree with you. The reason that there currently is no default pem: true and that there is no API to convert between formats is that I would like to plan an API for keys before doing that. Staying as close to WebCrypto compatibility as possible was a main concern when I wrote this PR, e.g. many of the options are compatible to WebCrypto. We might consider having key objects in the future, most other crypto APIs do, since they come with a couple of advantages. Converting between PEM and DER is trivial, that's not what users will get stuck on. Other operations, e.g. retrieving fields from an RSA key, are difficult to implement in JS (see e.g. the ursa package for an implementation), and I think we should make a plan before adding more and more functions. That's also the reason why there is no default publicKeyEncoding / privateKeyEncoding: If we decide to add key objects, we can simply return the key pair as objects if no encoding is specified without breaking compatibility with the current API.
About pem: true: This comes from WebCrypto, the standard only permits DER, not PEM, so I thought it might be good not to have a contrary default. If we improve our API to better support keys, both formats might be equally valid to use.
The other reason I didn't add any defaults is simple: We can always add defaults, but we cannot change them or take them away. These options are also not security-relevant.

(The way we handle keys is a mess, to be honest. #22553 was a first step on a long road.)

@tniessen tniessen added the notable-change PRs with changes that should be highlighted in changelogs. label Sep 4, 2018
@tniessen
Copy link
Member Author

tniessen commented Sep 9, 2018

Ping. I'd be okay with adding some defaults if that helps.

Rebased, old HEAD was 54f96676166414db1cd1fe7e06f32fb70d7625c6.

@tniessen tniessen force-pushed the crypto-add-keypair-generation branch from 54f9667 to d1f285b Compare September 9, 2018 15:27
@mcollina

This comment has been minimized.

@tniessen

This comment has been minimized.

@jasnell

This comment has been minimized.

@tniessen

This comment has been minimized.

@mcollina

This comment has been minimized.

@tniessen
Copy link
Member Author

I changed the code to ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS due to lack of a better idea. PTAL.

@daviddias
Copy link

daviddias commented Sep 12, 2018

thank you so much for making this happen. It will make the crypto bundle for libp2p way faster and smaller

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tniessen

This comment has been minimized.

tniessen added a commit to tniessen/node that referenced this pull request Sep 28, 2018
This adds support for PEM-level encryption as defined in RFC 1421.
PEM-level encryption is intentionally unsupported for PKCS#8 private
keys since PKCS#8 defines a newer encryption format.

Refs: nodejs#22660
tniessen added a commit that referenced this pull request Oct 2, 2018
This adds support for PEM-level encryption as defined in RFC 1421.
PEM-level encryption is intentionally unsupported for PKCS#8 private
keys since PKCS#8 defines a newer encryption format.

PR-URL: #23151
Refs: #22660
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
jasnell added a commit that referenced this pull request Oct 2, 2018
Notable changes:

* Build
  * FreeBSD 10 is no longer supported. [#22617](#22617)
* `child_process`
  * The default value of the `windowsHide` option has been changed to `true`. [#21316](#21316)
* `console`
  * `console.countReset()` will emit a warning if the timer being reset does not exist. [#21649](#21649)
  * `console.time()` will no longer reset a timer if it already exists. [#20442](#20442)
* `crypto`
  * PEM-level encryption is now supported. [#23151](#23151)
  * An API for key pair generation has been added. [#22660](#22660)
* Dependencies
  * V8 has been updated to 7.0. [#22754](#22754)
* `fs`
  * The `fs.read()` method now requires a callback. [#22146](#22146)
  * The previously deprecated `fs.SyncWriteStream` utility has been removed.[#20735](#20735)
* `http`
  * The `http`, `https`, and `tls` modules now use the WHATWG URL parser by default. [#20270](#20270)
* `http2`
  * An event will be emitted when a `PING` frame is received. [#23009](#23009)
  * Support for the `ORIGIN` frame has been added. [#22956](#22956)
* General
  * Use of `process.binding()` has been deprecated. Userland code using `process.binding()` should re-evaluate that use and begin migrating.
  * An experimental implementation of `queueMicrotask()` has been added. [#22951](#22951)
* Internal
  * Windows performance-counter support has been removed. [#22485](#22485)
  * The `--expose-http2` command-line option has been removed. [#20887](#20887)
* Promises
  * A new `multipleResolves` event will be emitted when a Promise is resolved (or rejected) more than once. [#22218](#22218)
* Timers
  * Interval timers will be rescheduled even if previous interval threw an error. [#20002](#20002)
* `util`
  * The WHATWG `TextEncoder` and `TextDecoder` are now globals. [#22281](#22281)
  * `util.inspect()` output size is limited to 128 MB by default. [#22756](#22756)
  * A runtime warning will be emitted when `NODE_DEBUG` is set for either `http` or `http2`. [#21914](#21914)
@jasnell jasnell mentioned this pull request Oct 2, 2018
4 tasks
targos pushed a commit that referenced this pull request Oct 3, 2018
This adds support for PEM-level encryption as defined in RFC 1421.
PEM-level encryption is intentionally unsupported for PKCS#8 private
keys since PKCS#8 defines a newer encryption format.

PR-URL: #23151
Refs: #22660
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos added a commit that referenced this pull request Oct 7, 2018
Notable changes:

* assert
  * The diff output is now a tiny bit improved by sorting object
    properties when inspecting the values that are compared with each
    other. #22788
* cli
  * The options parser now normalizes `_` to `-` in all multi-word
    command-line flags, e.g. `--no_warnings` has the same effect as
    `--no-warnings`. #23020
  * Added bash completion for the `node` binary. To generate a bash
    completion script, run `node --completion-bash`. The output can be
    saved to a file which can be sourced to enable completion.
    #20713
* crypto
  * Added support for PEM-level encryption.
    #23151
  * Added an API asymmetric key pair generation. The new methods
    `crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
    used to generate public and private key pairs. The API supports
    RSA, DSA and EC and a variety of key encodings (both PEM and DER).
    #22660
* fs
  * Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
    this option is set to true, non-existing parent folders will be
    automatically created. #21875
* http2
  * Added a `'ping'` event to `Http2Session` that is emitted whenever a
    non-ack `PING` is received.
    #23009
  * Added support for the `ORIGIN` frame.
    #22956
* module
  * Added `module.createRequireFromPath(filename)`. This new method can
    be used to create a custom require function that will resolve
    modules relative to the filename path.
    #19360
* process
  * Added a `'multipleResolves'` process event that is emitted whenever
    a `Promise` is attempted to be resolved multiple times, e.g. if the
    `resolve` and `reject` functions are both called in a `Promise`
    executor. #22218
* **url**
  * Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
    methods can be used to correctly convert between file: URLs and
    absolute paths. #22506
* **util**
  * Added the `sorted` option to `util.inspect()`. If set to `true`,
    all properties of an object and Set and Map entries will be sorted
    in the returned string. If set to a function, it is used as a
    compare function. #22788
  * The `util.instpect.custom` symbol is now defined in the global
    symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
    #20857
* **Windows**
  * The Windows msi installer now provides an option to automatically
    install the tools required to build native modules.
    #22645
* **Added new collaborators**:
  * digitalinfinity - Hitesh Kanwathirtha

PR-URL: #23313
targos added a commit that referenced this pull request Oct 10, 2018
Notable changes:

* assert
  * The diff output is now a tiny bit improved by sorting object
    properties when inspecting the values that are compared with each
    other. #22788
* cli
  * The options parser now normalizes `_` to `-` in all multi-word
    command-line flags, e.g. `--no_warnings` has the same effect as
    `--no-warnings`. #23020
  * Added bash completion for the `node` binary. To generate a bash
    completion script, run `node --completion-bash`. The output can be
    saved to a file which can be sourced to enable completion.
    #20713
* crypto
  * Added support for PEM-level encryption.
    #23151
  * Added an API asymmetric key pair generation. The new methods
    `crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
    used to generate public and private key pairs. The API supports
    RSA, DSA and EC and a variety of key encodings (both PEM and DER).
    #22660
* fs
  * Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
    this option is set to true, non-existing parent folders will be
    automatically created. #21875
* http2
  * Added a `'ping'` event to `Http2Session` that is emitted whenever a
    non-ack `PING` is received.
    #23009
  * Added support for the `ORIGIN` frame.
    #22956
  * Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
    protocol support to allow use of WebSockets over HTTP/2.
    #23284
* module
  * Added `module.createRequireFromPath(filename)`. This new method can
    be used to create a custom require function that will resolve
    modules relative to the filename path.
    #19360
* process
  * Added a `'multipleResolves'` process event that is emitted whenever
    a `Promise` is attempted to be resolved multiple times, e.g. if the
    `resolve` and `reject` functions are both called in a `Promise`
    executor. #22218
* url
  * Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
    methods can be used to correctly convert between file: URLs and
    absolute paths. #22506
* util
  * Added the `sorted` option to `util.inspect()`. If set to `true`,
    all properties of an object and Set and Map entries will be sorted
    in the returned string. If set to a function, it is used as a
    compare function. #22788
  * The `util.instpect.custom` symbol is now defined in the global
    symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
    #20857
  * Added support for `BigInt` numbers in `util.format()`.
    #22097
* V8 API
  * A number of V8 C++ APIs have been marked as deprecated since they
    have been removed in the upstream repository. Replacement APIs
    are added where necessary. #23159
* Windows
  * The Windows msi installer now provides an option to automatically
    install the tools required to build native modules.
    #22645
* Workers
  * Debugging support for Workers using the DevTools protocol has been
    implemented. #21364
  * The public `inspector` module is now enabled in Workers.
    #22769
* Added new collaborators:
  * digitalinfinity - Hitesh Kanwathirtha

PR-URL: #23313
targos added a commit that referenced this pull request Oct 10, 2018
Notable changes:

* assert
  * The diff output is now a tiny bit improved by sorting object
    properties when inspecting the values that are compared with each
    other. #22788
* cli
  * The options parser now normalizes `_` to `-` in all multi-word
    command-line flags, e.g. `--no_warnings` has the same effect as
    `--no-warnings`. #23020
  * Added bash completion for the `node` binary. To generate a bash
    completion script, run `node --completion-bash`. The output can be
    saved to a file which can be sourced to enable completion.
    #20713
* crypto
  * Added support for PEM-level encryption.
    #23151
  * Added an API asymmetric key pair generation. The new methods
    `crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
    used to generate public and private key pairs. The API supports
    RSA, DSA and EC and a variety of key encodings (both PEM and DER).
    #22660
* fs
  * Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
    this option is set to true, non-existing parent folders will be
    automatically created. #21875
* http2
  * Added a `'ping'` event to `Http2Session` that is emitted whenever a
    non-ack `PING` is received.
    #23009
  * Added support for the `ORIGIN` frame.
    #22956
  * Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
    protocol support to allow use of WebSockets over HTTP/2.
    #23284
* module
  * Added `module.createRequireFromPath(filename)`. This new method can
    be used to create a custom require function that will resolve
    modules relative to the filename path.
    #19360
* process
  * Added a `'multipleResolves'` process event that is emitted whenever
    a `Promise` is attempted to be resolved multiple times, e.g. if the
    `resolve` and `reject` functions are both called in a `Promise`
    executor. #22218
* url
  * Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
    methods can be used to correctly convert between file: URLs and
    absolute paths. #22506
* util
  * Added the `sorted` option to `util.inspect()`. If set to `true`,
    all properties of an object and Set and Map entries will be sorted
    in the returned string. If set to a function, it is used as a
    compare function. #22788
  * The `util.instpect.custom` symbol is now defined in the global
    symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
    #20857
  * Added support for `BigInt` numbers in `util.format()`.
    #22097
* V8 API
  * A number of V8 C++ APIs have been marked as deprecated since they
    have been removed in the upstream repository. Replacement APIs
    are added where necessary. #23159
* Windows
  * The Windows msi installer now provides an option to automatically
    install the tools required to build native modules.
    #22645
* Workers
  * Debugging support for Workers using the DevTools protocol has been
    implemented. #21364
  * The public `inspector` module is now enabled in Workers.
    #22769
* Added new collaborators:
  * digitalinfinity - Hitesh Kanwathirtha

PR-URL: #23313
targos added a commit that referenced this pull request Oct 10, 2018
Notable changes:

* assert
  * The diff output is now a tiny bit improved by sorting object
    properties when inspecting the values that are compared with each
    other. #22788
* cli
  * The options parser now normalizes `_` to `-` in all multi-word
    command-line flags, e.g. `--no_warnings` has the same effect as
    `--no-warnings`. #23020
  * Added bash completion for the `node` binary. To generate a bash
    completion script, run `node --completion-bash`. The output can be
    saved to a file which can be sourced to enable completion.
    #20713
* crypto
  * Added support for PEM-level encryption.
    #23151
  * Added an API asymmetric key pair generation. The new methods
    `crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
    used to generate public and private key pairs. The API supports
    RSA, DSA and EC and a variety of key encodings (both PEM and DER).
    #22660
* fs
  * Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
    this option is set to true, non-existing parent folders will be
    automatically created. #21875
* http2
  * Added a `'ping'` event to `Http2Session` that is emitted whenever a
    non-ack `PING` is received.
    #23009
  * Added support for the `ORIGIN` frame.
    #22956
  * Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
    protocol support to allow use of WebSockets over HTTP/2.
    #23284
* module
  * Added `module.createRequireFromPath(filename)`. This new method can
    be used to create a custom require function that will resolve
    modules relative to the filename path.
    #19360
* process
  * Added a `'multipleResolves'` process event that is emitted whenever
    a `Promise` is attempted to be resolved multiple times, e.g. if the
    `resolve` and `reject` functions are both called in a `Promise`
    executor. #22218
* url
  * Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
    methods can be used to correctly convert between file: URLs and
    absolute paths. #22506
* util
  * Added the `sorted` option to `util.inspect()`. If set to `true`,
    all properties of an object and Set and Map entries will be sorted
    in the returned string. If set to a function, it is used as a
    compare function. #22788
  * The `util.instpect.custom` symbol is now defined in the global
    symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
    #20857
  * Added support for `BigInt` numbers in `util.format()`.
    #22097
* V8 API
  * A number of V8 C++ APIs have been marked as deprecated since they
    have been removed in the upstream repository. Replacement APIs
    are added where necessary. #23159
* Windows
  * The Windows msi installer now provides an option to automatically
    install the tools required to build native modules.
    #22645
* Workers
  * Debugging support for Workers using the DevTools protocol has been
    implemented. #21364
  * The public `inspector` module is now enabled in Workers.
    #22769
* Added new collaborators:
  * digitalinfinity - Hitesh Kanwathirtha

PR-URL: #23313
@davidgilbertson
Copy link
Contributor

Can this be used to generate the keys required for tls.createServer?

If yes, two questions:

  1. How?
  2. Shall I add this to the documentation in the section TLS/SSL Concepts that gives examples of how to create keys?

(I know zero about cryptography and keys and all that jazz)

Thanks!

@tniessen
Copy link
Member Author

tniessen commented Oct 12, 2018

@davidgilbertson You can use it to generate cryptographic key pairs (including the private key), but you will need additional steps to create an X509 certificate for TLS. Currently, there is no API to do that within Node.js core.

(Basically, the certificate contains tons more of information than just the key.)

jasnell pushed a commit that referenced this pull request Oct 17, 2018
Notable changes:

* assert
  * The diff output is now a tiny bit improved by sorting object
    properties when inspecting the values that are compared with each
    other. #22788
* cli
  * The options parser now normalizes `_` to `-` in all multi-word
    command-line flags, e.g. `--no_warnings` has the same effect as
    `--no-warnings`. #23020
  * Added bash completion for the `node` binary. To generate a bash
    completion script, run `node --completion-bash`. The output can be
    saved to a file which can be sourced to enable completion.
    #20713
* crypto
  * Added support for PEM-level encryption.
    #23151
  * Added an API asymmetric key pair generation. The new methods
    `crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
    used to generate public and private key pairs. The API supports
    RSA, DSA and EC and a variety of key encodings (both PEM and DER).
    #22660
* fs
  * Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
    this option is set to true, non-existing parent folders will be
    automatically created. #21875
* http2
  * Added a `'ping'` event to `Http2Session` that is emitted whenever a
    non-ack `PING` is received.
    #23009
  * Added support for the `ORIGIN` frame.
    #22956
  * Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
    protocol support to allow use of WebSockets over HTTP/2.
    #23284
* module
  * Added `module.createRequireFromPath(filename)`. This new method can
    be used to create a custom require function that will resolve
    modules relative to the filename path.
    #19360
* process
  * Added a `'multipleResolves'` process event that is emitted whenever
    a `Promise` is attempted to be resolved multiple times, e.g. if the
    `resolve` and `reject` functions are both called in a `Promise`
    executor. #22218
* url
  * Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
    methods can be used to correctly convert between file: URLs and
    absolute paths. #22506
* util
  * Added the `sorted` option to `util.inspect()`. If set to `true`,
    all properties of an object and Set and Map entries will be sorted
    in the returned string. If set to a function, it is used as a
    compare function. #22788
  * The `util.instpect.custom` symbol is now defined in the global
    symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
    #20857
  * Added support for `BigInt` numbers in `util.format()`.
    #22097
* V8 API
  * A number of V8 C++ APIs have been marked as deprecated since they
    have been removed in the upstream repository. Replacement APIs
    are added where necessary. #23159
* Windows
  * The Windows msi installer now provides an option to automatically
    install the tools required to build native modules.
    #22645
* Workers
  * Debugging support for Workers using the DevTools protocol has been
    implemented. #21364
  * The public `inspector` module is now enabled in Workers.
    #22769
* Added new collaborators:
  * digitalinfinity - Hitesh Kanwathirtha

PR-URL: #23313
@tniessen tniessen mentioned this pull request Nov 9, 2018
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. notable-change PRs with changes that should be highlighted in changelogs. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet