Skip to content

Commit 2dbd3ed

Browse files
committed
feat: add OKP Key and EdDSA sign/verify support
BREAKING CHANGE: node.js minimal version is now v12.0.0 due to its added EdDSA support (crypto.sign, crypto.verify and eddsa key objects) resolves #12
1 parent d51cfb5 commit 2dbd3ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1090
-109
lines changed

.github/ISSUE_TEMPLATE/bug-report.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ A clear and concise description of what you expected to happen.
2222

2323
**Environment:**
2424
- @panva/jose version: [e.g. v1.0.0]
25-
- node version: [e.g. v11.9.0]
25+
- node version: [e.g. v12.0.0]
2626

2727
**Additional context**
2828
Add any other context about the problem here.

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ matrix:
66
language: node_js
77
node_js: stable
88
script: npm run lint
9-
- name: "Test Suite + coverage - 11.8.0" #min
9+
- name: "Test Suite + coverage - 12.0.0" #min
1010
language: node_js
11-
node_js: 11.8.0
11+
node_js: 12.0.0
1212
script: npm run coverage
1313
after_script: npx codecov
1414
- name: "Test Suite + coverage - stable"

README.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ The following specifications are implemented by @panva/jose
1515
- JSON Web Token (JWT) - [RFC7519][spec-jwt]
1616
- JSON Web Key (JWK) Thumbprint - [RFC7638][spec-thumbprint]
1717
- JWS Unencoded Payload Option - [RFC7797][spec-b64]
18+
- CFRG Elliptic Curve Signatures (EdDSA) - [RFC8037][spec-okp]
1819

1920
The test suite utilizes examples defined in [RFC7520][spec-cookbook] to confirm its JOSE
2021
implementation is correct.
@@ -31,6 +32,7 @@ Legend:
3132
| -- | -- | -- |
3233
| RSA || RSA |
3334
| Elliptic Curve || EC |
35+
| Octet Key Pair || OKP |
3436
| Octet sequence || oct |
3537

3638
| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt |
@@ -44,6 +46,7 @@ Legend:
4446
| RSASSA-PKCS1-v1_5 || RS256, RS384, RS512 |
4547
| RSASSA-PSS || PS256, PS384, PS512 |
4648
| ECDSA || ES256, ES384, ES512 |
49+
| Edwards-curve DSA || EdDSA |
4750
| HMAC with SHA-2 || HS256, HS384, HS512 |
4851

4952
| JWE Key Management Algorithms | Supported ||
@@ -64,7 +67,7 @@ Legend:
6467
---
6568

6669
Pending Node.js Support 🤞:
67-
- [RFC8037][spec-cfrg] (EdDSA, OKP kty, etc). See [#12](https://github.com/panva/jose/issues/12)
70+
- ECDH-ES with X25519 and X448
6871

6972
Won't implement:
7073
- ✕ JWS embedded key / referenced verification
@@ -107,8 +110,7 @@ If you or your business use @panva/jose, please consider becoming a [Patron][sup
107110

108111
## Usage
109112

110-
⚠️ Minimal Node.js version required is **v11.8.0** ⚠️ The plan is to release v1.0.0 when Node.js
111-
v12.0.0 releases in April 2019
113+
For its improvements in the crypto module ⚠️ the minimal Node.js version required is **v12.0.0** ⚠️
112114

113115
Installing @panva/jose
114116

@@ -255,7 +257,7 @@ private API and is subject to change between any versions.
255257
#### How do I use it outside of Node.js
256258

257259
It is **only built for Node.js** environment - it builds on top of the `crypto` module and requires
258-
the KeyObject API that was added in Node.js v11.6.0.
260+
the KeyObject API that was added in Node.js v11.6.0 and one-shot sign/verify API added in v12.0.0
259261

260262
#### How is it different from [`node-jose`][node-jose]
261263

@@ -304,13 +306,13 @@ in terms of performance and API (not having well defined errors). When Node.js v
304306
[node-jose]: https://github.com/cisco/node-jose
305307
[security-vulnerability]: https://github.com/panva/jose/issues/new?template=security-vulnerability.md
306308
[spec-b64]: https://tools.ietf.org/html/rfc7797
307-
[spec-cfrg]: https://tools.ietf.org/html/rfc8037
308309
[spec-cookbook]: https://tools.ietf.org/html/rfc7520
309310
[spec-jwa]: https://tools.ietf.org/html/rfc7518
310311
[spec-jwe]: https://tools.ietf.org/html/rfc7516
311312
[spec-jwk]: https://tools.ietf.org/html/rfc7517
312313
[spec-jws]: https://tools.ietf.org/html/rfc7515
313314
[spec-jwt]: https://tools.ietf.org/html/rfc7519
315+
[spec-okp]: https://tools.ietf.org/html/rfc8037
314316
[spec-thumbprint]: https://tools.ietf.org/html/rfc7638
315317
[suggest-feature]: https://github.com/panva/jose/issues/new?labels=enhancement&template=feature-request.md&title=proposal%3A+
316318
[support-patreon]: https://www.patreon.com/panva

docs/README.md

+27-22
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ I can continue maintaining it and adding new features carefree. You may also don
2424
## JWK (JSON Web Key)
2525

2626
<!-- TOC JWK START -->
27-
- [Class: &lt;JWK.Key&gt; and &lt;JWK.RSAKey&gt; &vert; &lt;JWK.ECKey&gt; &vert; &lt;JWK.OctKey&gt;](#class-jwkkey-and-jwkrsakey--jwkeckey--jwkoctkey)
27+
- [Class: &lt;JWK.Key&gt; and &lt;JWK.RSAKey&gt; &vert; &lt;JWK.ECKey&gt; &vert; &lt;JWK.OKPKey&gt; &vert; &lt;JWK.OctKey&gt;](#class-jwkkey-and-jwkrsakey--jwkeckey--jwkokpkey--jwkoctkey)
2828
- [key.kty](#keykty)
2929
- [key.alg](#keyalg)
3030
- [key.use](#keyuse)
@@ -58,28 +58,30 @@ const { JWK } = require('@panva/jose')
5858

5959
---
6060

61-
#### Class: `<JWK.Key>` and `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>`
61+
#### Class: `<JWK.Key>` and `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>`
6262

63-
`<JWK.RSAKey>`, `<JWK.ECKey>` and `<JWK.OctKey>` represent a key usable for JWS and JWE operations.
63+
`<JWK.RSAKey>`, `<JWK.ECKey>`, `<JWK.OKPKey>` and `<JWK.OctKey>` represent a key usable for JWS and JWE operations.
6464
The `JWK.importKey()` method is used to retrieve a key representation of an existing key or secret.
6565
`JWK.generate()` method is used to generate a new random key.
6666

67-
`<JWK.RSAKey>`, `<JWK.ECKey>` and `<JWK.OctKey>` inherit methods from `<JWK.Key>` and in addition
67+
`<JWK.RSAKey>`, `<JWK.ECKey>`, `<JWK.OKPKey>` and `<JWK.OctKey>` inherit methods from `<JWK.Key>` and in addition
6868
to the properties documented below have the respective key component properties exported as
6969
`<string>` in their format defined by the specifications.
7070

7171
- `e, n` for Public RSA Keys
7272
- `e, n, d, p, q, dp, dq, qi` for Private RSA Keys
7373
- `crv, x, y` for Public EC Keys
7474
- `crv, x, y, n` for Private EC Keys
75+
- `crv, x` for Public OKP Keys
76+
- `crv, x, n` for Private OKP Keys
7577
- `k` for Symmetric keys
7678

7779
---
7880

7981
#### `key.kty`
8082

81-
Returns the key's JWK Key Type Parameter. 'EC', 'RSA' or 'oct' for the respective supported key
82-
types.
83+
Returns the key's JWK Key Type Parameter. 'EC', 'RSA', 'OKP' or 'oct' for the respective supported
84+
key types.
8385

8486
- `<string>`
8587

@@ -262,7 +264,7 @@ Private keys may also be passphrase protected.
262264
[RFC7638][spec-thumbprint]
263265
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting
264266
data or signing & verifying data. Must be 'sig' or 'enc'.
265-
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>`
267+
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>`
266268

267269
See the underlying Node.js API for details on importing private and public keys in the different
268270
formats
@@ -321,11 +323,11 @@ const key = importKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ'))
321323

322324
#### `JWK.importKey(jwk)` JWK-formatted key import
323325

324-
Imports a JWK formatted key. This supports JWK formatted EC, RSA and oct keys. Asymmetrical keys
325-
may be both private and public.
326+
Imports a JWK formatted key. This supports JWK formatted RSA, EC, OKP and oct keys. Asymmetrical
327+
keys may be both private and public.
326328

327329
- `jwk`: `<Object>`
328-
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
330+
- `kty`: `<string>` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'.
329331
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
330332
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting
331333
data or signing & verifying data. Must be 'sig' or 'enc'.
@@ -335,8 +337,10 @@ may be both private and public.
335337
- `e`, `n`, `d`, `p`, `q`, `dp`, `dq`, `qi` properties as `<string>` for RSA private keys
336338
- `crv`, `x`, `y` properties as `<string>` for EC public keys
337339
- `crv`, `x`, `y`, `d` properties as `<string>` for EC private keys
340+
- `crv`, `x`, properties as `<string>` for OKP public keys
341+
- `crv`, `x`, `d` properties as `<string>` for OKP private keys
338342
- `k` properties as `<string>` for secret oct keys
339-
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>`
343+
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>`
340344

341345
<details>
342346
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
@@ -366,10 +370,11 @@ const key = importKey(jwk)
366370

367371
#### `JWK.generate(kty[, crvOrSize[, options[, private]]])` generating new keys
368372

369-
Securely generates a new RSA, EC or oct key.
373+
Securely generates a new RSA, EC, OKP or oct key.
370374

371-
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
372-
- `crvOrSize`: `<number>` &vert; `<string>` key's bit size or in case of EC keys the curve
375+
- `kty`: `<string>` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'.
376+
- `crvOrSize`: `<number>` &vert; `<string>` key's bit size or in case of OKP and EC keys the curve
377+
**Default:** 2048 for RSA, 'P-256' for EC, 'Ed25519' for OKP and 256 for oct.
373378
- `options`: `<Object>`
374379
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
375380
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in
@@ -378,7 +383,7 @@ Securely generates a new RSA, EC or oct key.
378383
data or signing & verifying data. Must be 'sig' or 'enc'.
379384
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when
380385
asymmetrical)
381-
- Returns: `Promise<JWK.RSAKey>` &vert; `Promise<JWK.ECKey>` &vert; `Promise<JWK.OctKey>`
386+
- Returns: `Promise<JWK.RSAKey>` &vert; `Promise<JWK.ECKey>` &vert; `Promise<JWK.OKPKey>` &vert; `Promise<JWK.OctKey>`
382387

383388
<details>
384389
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
@@ -406,9 +411,9 @@ const { JWK: { generate } } = require('@panva/jose')
406411

407412
Synchronous version of `JWK.generate()`
408413

409-
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
410-
- `crvOrSize`: `<number>` &vert; `<string>` key's bit size or in case of EC keys the curve. **Default:**
411-
2048 for RSA, 'P-256' for EC and 256 for oct.
414+
- `kty`: `<string>` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'.
415+
- `crvOrSize`: `<number>` &vert; `<string>` key's bit size or in case of OKP and EC keys the curve.
416+
**Default:** 2048 for RSA, 'P-256' for EC, 'Ed25519' for OKP and 256 for oct.
412417
- `options`: `<Object>`
413418
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
414419
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting
@@ -417,7 +422,7 @@ Synchronous version of `JWK.generate()`
417422
[RFC7638][spec-thumbprint]
418423
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when
419424
asymmetrical)
420-
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>`
425+
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>`
421426

422427
<details>
423428
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
@@ -527,23 +532,23 @@ parameters is returned.
527532
- `kid`: `<string>` Key ID to filter for.
528533
- `operation`: `<string>` Further specify the operation a given alg must be valid for. Must be one
529534
of 'encrypt', 'decrypt', 'sign', 'verify', 'wrapKey', 'unwrapKey'
530-
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>` &vert; `<undefined>`
535+
- Returns: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>` &vert; `<undefined>`
531536

532537
---
533538

534539
#### `keystore.add(key)`
535540

536541
Adds a key instance to the store unless it is already included.
537542

538-
- `key`: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>`
543+
- `key`: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>`
539544

540545
---
541546

542547
#### `keystore.remove(key)`
543548

544549
Ensures a key is removed from a store.
545550

546-
- `key`: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OctKey>`
551+
- `key`: `<JWK.RSAKey>` &vert; `<JWK.ECKey>` &vert; `<JWK.OKPKey>` &vert; `<JWK.OctKey>`
547552

548553
---
549554

lib/help/asn1/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ types.set('PrivateKeyInfo', PrivateKeyInfo)
1414
const PublicKeyInfo = asn1.define('PublicKeyInfo', require('./public_key_info')(AlgorithmIdentifier))
1515
types.set('PublicKeyInfo', PublicKeyInfo)
1616

17+
const PrivateKey = asn1.define('PrivateKey', require('./private_key'))
18+
types.set('PrivateKey', PrivateKey)
19+
20+
const OneAsymmetricKey = asn1.define('OneAsymmetricKey', require('./one_asymmetric_key')(AlgorithmIdentifier, PrivateKey))
21+
types.set('OneAsymmetricKey', OneAsymmetricKey)
22+
1723
const RSAPrivateKey = asn1.define('RSAPrivateKey', require('./rsa_private_key'))
1824
types.set('RSAPrivateKey', RSAPrivateKey)
1925

lib/help/asn1/one_asymmetric_key.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = (AlgorithmIdentifier, PrivateKey) => function () {
2+
this.seq().obj(
3+
this.key('version').int(),
4+
this.key('algorithm').use(AlgorithmIdentifier),
5+
this.key('privateKey').use(PrivateKey)
6+
)
7+
}

lib/help/asn1/private_key.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = function () {
2+
this.octstr().contains().obj(
3+
this.key('privateKey').octstr()
4+
)
5+
}

lib/help/key_object.js

-8
This file was deleted.

0 commit comments

Comments
 (0)