Skip to content

Commit

Permalink
feat: add CustomKey for a customized signing and verifying
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-zeronsoftn committed Oct 19, 2019
1 parent c11a9d3 commit b7efe59
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 5 deletions.
2 changes: 2 additions & 0 deletions lib/jwk/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const Key = require('./key/base')
const CustomKey = require('./key/custom')
const importKey = require('./import')
const { generate, generateSync } = require('./generate')

module.exports.asKey = importKey
module.exports.generate = generate
module.exports.generateSync = generateSync
module.exports.isKey = input => input instanceof Key
module.exports.CustomKey = CustomKey

/* deprecated */
Object.defineProperty(module.exports, 'importKey', {
Expand Down
9 changes: 7 additions & 2 deletions lib/jwk/key/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const thumbprint = require('../thumbprint')
const errors = require('../../errors')

class Key {
constructor (keyObject, { alg, use, kid, key_ops: ops, x5c, x5t, 'x5t#S256': x5t256 } = {}) {
constructor (keyObject, { alg, use, kid, key_ops: ops, x5c, x5t, 'x5t#S256': x5t256, custom } = {}) {
if (use !== undefined) {
if (typeof use !== 'string' || !USES.has(use)) {
throw new TypeError('`use` must be either "sig" or "enc" string when provided')
Expand Down Expand Up @@ -76,6 +76,10 @@ class Key {
})
}

if (custom === undefined) {
custom = false
}

Object.defineProperties(this, {
[KEYOBJECT]: { value: isObject(keyObject) ? undefined : keyObject },
type: { value: keyObject.type },
Expand Down Expand Up @@ -129,7 +133,8 @@ class Key {
return this.thumbprint
},
configurable: true
}
},
custom: { value: custom }
})
}

Expand Down
50 changes: 50 additions & 0 deletions lib/jwk/key/custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const {
JWK_MEMBERS, PUBLIC_MEMBERS, PRIVATE_MEMBERS
} = require('../../help/consts')

const Key = require('./base')

const CUSTOM_PUBLIC = new Set([])
Object.freeze(CUSTOM_PUBLIC)
const CUSTOM_PRIVATE = new Set([...CUSTOM_PUBLIC])
Object.freeze(CUSTOM_PRIVATE)

class CustomKeyObject {
constructor (params) {
params = params || {}

this._type = params.keyType
this._symmetricKeySize = params.symmetricKeySize || 0
}

get type () {
return this._type
}

get symmetricKeySize () {
return this._symmetricKeySize
}
}

// Custom Key Type
class CustomKey extends Key {
constructor (params) {
// { alg, use, kid, key_ops: ops, x5c, x5t, 'x5t#S256', keyType, symmetricKeySize } = {}
super(new CustomKeyObject(params), Object.assign(params || {}, { custom: true }))
this[JWK_MEMBERS]()
}

static get [PUBLIC_MEMBERS] () {
return CUSTOM_PUBLIC
}

static get [PRIVATE_MEMBERS] () {
return CUSTOM_PRIVATE
}

algorithms (operation, /* second argument is private API */ { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = {}) {
// Should override
}
}

module.exports = CustomKey
7 changes: 6 additions & 1 deletion lib/jws/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ class Sign {

recipient.header = unprotectedHeader
recipient.protected = Object.keys(joseHeader.protected).length ? base64url.JSON.encode(joseHeader.protected) : ''
recipient.signature = base64url.encodeBuffer(sign(alg, key, Buffer.from(`${recipient.protected}.${i(this).payload}`)))

if (key.custom) {
recipient.signature = base64url.encodeBuffer(key.sign(alg, Buffer.from(`${recipient.protected}.${i(this).payload}`)))
} else {
recipient.signature = base64url.encodeBuffer(sign(alg, key, Buffer.from(`${recipient.protected}.${i(this).payload}`)))
}
}

/*
Expand Down
10 changes: 8 additions & 2 deletions lib/jws/verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,14 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp

check(key, 'verify', alg)

if (!verify(alg, key, Buffer.from([prot, payload].join('.')), base64url.decodeToBuffer(signature))) {
throw new errors.JWSVerificationFailed()
if (key.custom) {
if (!key.verify(alg, Buffer.from([prot, payload].join('.')), base64url.decodeToBuffer(signature))) {
throw new errors.JWSVerificationFailed()
}
} else {
if (!verify(alg, key, Buffer.from([prot, payload].join('.')), base64url.decodeToBuffer(signature))) {
throw new errors.JWSVerificationFailed()
}
}

if (!combinedHeader.crit || !combinedHeader.crit.includes('b64') || combinedHeader.b64) {
Expand Down
7 changes: 7 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export namespace JWK {
x5t?: string;
'x5t#S256'?: string;

custom: boolean;

toPEM(private?: boolean, encoding?: pemEncodingOptions): string;

algorithms(operation?: keyOperation): Set<string>;
Expand Down Expand Up @@ -144,6 +146,11 @@ export namespace JWK {
toJWK(private?: boolean): JWKOctKey;
}

class CustomKey extends Key {
sign (alg: string, buffer: Buffer): Buffer;
verify (alg: string, buffer: Buffer): boolean;
}

type KeyInput = PrivateKeyInput | PublicKeyInput | string | Buffer;

function isKey(object: any): boolean;
Expand Down

0 comments on commit b7efe59

Please sign in to comment.