diff options
author | Matthew Miller <matthew@millerti.me> | 2020-05-17 23:20:00 -0700 |
---|---|---|
committer | Matthew Miller <matthew@millerti.me> | 2020-05-17 23:20:00 -0700 |
commit | 23e320bf7133a90ae4dfcec7c65249c1dde7e321 (patch) | |
tree | 44d4823b72f4f5c1cd6603db520077405b62dc96 /src | |
parent | 3b26d1c8322f13178377467e438884621a75e284 (diff) |
Add some helpers
Diffstat (limited to 'src')
-rw-r--r-- | src/helpers/asciiToBinary.ts | 8 | ||||
-rw-r--r-- | src/helpers/constants.ts | 64 | ||||
-rw-r--r-- | src/helpers/decodeAttestationObject.test.ts | 39 | ||||
-rw-r--r-- | src/helpers/decodeAttestationObject.ts | 23 | ||||
-rw-r--r-- | src/helpers/decodeClientDataJSON.test.ts | 16 | ||||
-rw-r--r-- | src/helpers/decodeClientDataJSON.ts | 12 |
6 files changed, 162 insertions, 0 deletions
diff --git a/src/helpers/asciiToBinary.ts b/src/helpers/asciiToBinary.ts new file mode 100644 index 0000000..b006edd --- /dev/null +++ b/src/helpers/asciiToBinary.ts @@ -0,0 +1,8 @@ +/** + * Decode a base64-encoded string to a binary string + * + * @param input Base64-encoded string + */ +export default function asciiToBinary(input: string) { + return Buffer.from(input, 'base64').toString('binary'); +} diff --git a/src/helpers/constants.ts b/src/helpers/constants.ts new file mode 100644 index 0000000..f2df278 --- /dev/null +++ b/src/helpers/constants.ts @@ -0,0 +1,64 @@ +export enum ATTESTATION_FORMATS { + FIDO_U2F = 'fido-u2f', + PACKED = 'packed', + ANDROID_SAFETYNET = 'android-safetynet', + NONE = 'none', +}; + +/** + * U2F Presence constant + */ +export const U2F_USER_PRESENTED = 0x01; + +export const COSEKEYS = { + 'kty' : 1, + 'alg' : 3, + 'crv' : -1, + 'x' : -2, + 'y' : -3, + 'n' : -1, + 'e' : -2 +} + +export const COSEKTY = { + 'OKP': 1, + 'EC2': 2, + 'RSA': 3 +} + +export const COSERSASCHEME = { + '-3': 'pss-sha256', + '-39': 'pss-sha512', + '-38': 'pss-sha384', + '-65535': 'pkcs1-sha1', + '-257': 'pkcs1-sha256', + '-258': 'pkcs1-sha384', + '-259': 'pkcs1-sha512' +} + +export const COSEALGHASH = { + '-257': 'sha256', + '-258': 'sha384', + '-259': 'sha512', + '-65535': 'sha1', + '-39': 'sha512', + '-38': 'sha384', + '-37': 'sha256', + '-7': 'sha256', + '-8': 'sha512', + '-36': 'sha512' +} + +export const COSECRV = { + 1: 'p256', + 2: 'p384', + 3: 'p521', +}; + +/** + * This "GS Root R2" root certificate was downloaded from https://pki.goog/gsr2/GSR2.crt + * on 08/10/2019 and then run through `base64url.encode()` to get this representation. + * + * The certificate is valid until Dec 15, 2021 + */ +export const GlobalSignRootCAR2 = 'MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6-Lm8omUVCxKs-IVSbC9N_hHD6ErPLv4dfxn-G07IwXNb9rfF73OX4YJYJkhD10FPe-3t-c4isUoh7SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy-0Hne_ig-1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ_gkwpRl4pazq-r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH_BAUwAwEB_zAdBgNVHQ4EFgQUm-IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0_WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP-DTKqttVCL1OmLNIG-6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavSot-3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h-u_N5GJG79G-dwfCMNYxdAfvDbbnvRG15RjF-Cv6pgsH_76tuIMRQyV-dTZsXjAzlAcmgQWpzU_qlULRuJQ_7TBj0_VLZjmmx6BEP3ojY-x1J96relc8geMJgEtslQIxq_H5COEBkEveegeGTLg'; diff --git a/src/helpers/decodeAttestationObject.test.ts b/src/helpers/decodeAttestationObject.test.ts new file mode 100644 index 0000000..d36201e --- /dev/null +++ b/src/helpers/decodeAttestationObject.test.ts @@ -0,0 +1,39 @@ +import decodeAttestationObject from './decodeAttestationObject'; + +test('should decode base64-encoded indirect attestationObject', () => { + const decoded = decodeAttestationObject( + 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEAbElFazplpnc037DORGDZNjDq86cN9vm6' + + '+APoAM20wtBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQKmPuEwByQJ3e89TccUSrCGDkNWquhevjLLn/' + + 'KNZZaxQQ0steueoG2g12dvnUNbiso8kVJDyLa+6UiA34eniujWlAQIDJiABIVggiUk8wN2j' + + '+3fkKI7KSiLBkKzs3FfhPZxHgHPnGLvOY/YiWCBv7+XyTqArnMVtQ947/8Xk8fnVCdLMRWJGM1VbNevVcQ==' + ); + + expect(decoded.fmt).toEqual('none'); + expect(decoded.attStmt).toEqual({}); + expect(decoded.authData).toBeDefined(); +}); + +test('should decode base64-encoded direct attestationObject', () => { + const decoded = decodeAttestationObject( + 'o2NmbXRoZmlkby11MmZnYXR0U3RtdKJjc2lnWEgwRgIhAK40WxA0t7py7AjEXvwGwTlmqlvrOk' + + 's5g9lf+9zXzRiVAiEA3bv60xyXveKDOusYzniD7CDSostCet9PYK7FLdnTdZNjeDVjgVkCwTCCAr0wggGloAMCAQICBCrn' + + 'YmMwDQYJKoZIhvcNAQELBQAwLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEwIBcNMT' + + 'QwODAxMDAwMDAwWhgPMjA1MDA5MDQwMDAwMDBaMG4xCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlZdWJpY28gQUIxIjAgBgNV' + + 'BAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xJzAlBgNVBAMMHll1YmljbyBVMkYgRUUgU2VyaWFsIDcxOTgwNzA3NT' + + 'BZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCoDhl5gQ9meEf8QqiVUV4S/Ca+Oax47MhcpIW9VEhqM2RDTmd3HaL3+SnvH' + + '49q8YubSRp/1Z1uP+okMynSGnj+jbDBqMCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS4xMBMGCysGAQQBgu' + + 'UcAgEBBAQDAgQwMCEGCysGAQQBguUcAQEEBBIEEG1Eupv27C5JuTAMj+kgy3MwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0B' + + 'AQsFAAOCAQEAclfQPNzD4RVphJDW+A75W1MHI3PZ5kcyYysR3Nx3iuxr1ZJtB+F7nFQweI3jL05HtFh2/4xVIgKb6Th4eV' + + 'cjMecncBaCinEbOcdP1sEli9Hk2eVm1XB5A0faUjXAPw/+QLFCjgXG6ReZ5HVUcWkB7riLsFeJNYitiKrTDXFPLy+sNtVN' + + 'utcQnFsCerDKuM81TvEAigkIbKCGlq8M/NvBg5j83wIxbCYiyV7mIr3RwApHieShzLdJo1S6XydgQjC+/64G5r8C+8AVvN' + + 'FR3zXXCpio5C3KRIj88HEEIYjf6h1fdLfqeIsq+cUUqbq5T+c4nNoZUZCysTB9v5EY4akp+GhhdXRoRGF0YVjEAbElFazp' + + 'lpnc037DORGDZNjDq86cN9vm6+APoAM20wtBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQGFYevaR71ptU5YtXOSnVzPQTsGgK+' + + 'gLiBKnqPWBmZXNRvjISqlLxiwApzlrfkTc3lEMYMatjeACCnsijOkNEGOlAQIDJiABIVggdWLG6UvGyHFw/k/bv6/k6z/L' + + 'LgSO5KXzXw2EcUxkEX8iWCBeaVLz/cbyoKvRIg/q+q7tan0VN+i3WR0BOBCcuNP7yw==' + ); + + expect(decoded.fmt).toEqual('fido-u2f'); + expect(decoded.attStmt.sig).toBeDefined(); + expect(decoded.attStmt.x5c).toBeDefined(); + expect(decoded.authData).toBeDefined(); +}); diff --git a/src/helpers/decodeAttestationObject.ts b/src/helpers/decodeAttestationObject.ts new file mode 100644 index 0000000..a03fefd --- /dev/null +++ b/src/helpers/decodeAttestationObject.ts @@ -0,0 +1,23 @@ +import base64url from 'base64url'; +import cbor from 'cbor'; + +import { ATTESTATION_FORMATS } from './constants'; + +type AttestationObject = { + fmt: ATTESTATION_FORMATS, + attStmt: { + sig?: Buffer, + x5c?: Buffer, + }, + authData: Buffer, +}; + +/** + * + * @param obj + */ +export default function decodeAttestationObject(obj: string): AttestationObject { + const toBuffer = base64url.toBuffer(obj); + const toCBOR = cbor.decodeAllSync(toBuffer)[0]; + return toCBOR; +} diff --git a/src/helpers/decodeClientDataJSON.test.ts b/src/helpers/decodeClientDataJSON.test.ts new file mode 100644 index 0000000..b9868f8 --- /dev/null +++ b/src/helpers/decodeClientDataJSON.test.ts @@ -0,0 +1,16 @@ +import decodeClientDataJSON from './decodeClientDataJSON'; + +test('should convert base64-encoded attestation clientDataJSON to JSON', () => { + expect( + decodeClientDataJSON( + 'eyJjaGFsbGVuZ2UiOiJVMmQ0TjNZME0wOU1jbGRQYjFSNVpFeG5UbG95IiwiY2xpZW50RXh0ZW5zaW9ucyI6e30' + + 'sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cHM6Ly9jbG92ZXIubWlsbGVydGltZS5kZX' + + 'Y6MzAwMCIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ==' + )).toEqual({ + challenge: 'U2d4N3Y0M09McldPb1R5ZExnTloy', + clientExtensions: {}, + hashAlgorithm: 'SHA-256', + origin: 'https://clover.millertime.dev:3000', + type: 'webauthn.create' + }); +}); diff --git a/src/helpers/decodeClientDataJSON.ts b/src/helpers/decodeClientDataJSON.ts new file mode 100644 index 0000000..b957d60 --- /dev/null +++ b/src/helpers/decodeClientDataJSON.ts @@ -0,0 +1,12 @@ +import asciiToBinary from './asciiToBinary'; + +/** + * Decode an authenticator's base64-encoded clientDataJSON to JSON + * + * @param data + * @returns {Object} - the data as JSON + */ +export default function decodeClientDataJSON(data: string) { + const toString = asciiToBinary(data); + return JSON.parse(toString); +} |