summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMatthew Miller <matthew@millerti.me>2020-05-17 23:20:00 -0700
committerMatthew Miller <matthew@millerti.me>2020-05-17 23:20:00 -0700
commit23e320bf7133a90ae4dfcec7c65249c1dde7e321 (patch)
tree44d4823b72f4f5c1cd6603db520077405b62dc96 /src
parent3b26d1c8322f13178377467e438884621a75e284 (diff)
Add some helpers
Diffstat (limited to 'src')
-rw-r--r--src/helpers/asciiToBinary.ts8
-rw-r--r--src/helpers/constants.ts64
-rw-r--r--src/helpers/decodeAttestationObject.test.ts39
-rw-r--r--src/helpers/decodeAttestationObject.ts23
-rw-r--r--src/helpers/decodeClientDataJSON.test.ts16
-rw-r--r--src/helpers/decodeClientDataJSON.ts12
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);
+}