summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src/helpers/parseAuthenticatorData.ts
blob: 919c0aa1b0187803c698470c54cbb54b5e3841aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
 * Make sense of the authData buffer contained in an Attestation
 */
export default function parseAuthenticatorData(authData: Buffer): ParsedAuthenticatorData {
  if (authData.byteLength < 37) {
    throw new Error(
      `Authenticator data was ${authData.byteLength} bytes, expected at least 37 bytes`,
    );
  }

  let intBuffer = authData;

  const rpIdHash = intBuffer.slice(0, 32);
  intBuffer = intBuffer.slice(32);

  const flagsBuf = intBuffer.slice(0, 1);
  intBuffer = intBuffer.slice(1);

  const flagsInt = flagsBuf[0];

  const flags = {
    up: !!(flagsInt & 0x01),
    uv: !!(flagsInt & 0x04),
    at: !!(flagsInt & 0x40),
    ed: !!(flagsInt & 0x80),
    flagsInt,
  };

  const counterBuf = intBuffer.slice(0, 4);
  intBuffer = intBuffer.slice(4);

  const counter = counterBuf.readUInt32BE(0);

  let aaguid: Buffer | undefined = undefined;
  let credentialID: Buffer | undefined = undefined;
  let credentialPublicKey: Buffer | undefined = undefined;

  if (flags.at) {
    aaguid = intBuffer.slice(0, 16);
    intBuffer = intBuffer.slice(16);

    const credIDLenBuf = intBuffer.slice(0, 2);
    intBuffer = intBuffer.slice(2);

    const credIDLen = credIDLenBuf.readUInt16BE(0);

    credentialID = intBuffer.slice(0, credIDLen);
    intBuffer = intBuffer.slice(credIDLen);

    credentialPublicKey = intBuffer;
  }

  return {
    rpIdHash,
    flagsBuf,
    flags,
    counter,
    counterBuf,
    aaguid,
    credentialID,
    credentialPublicKey,
  };
}

export type ParsedAuthenticatorData = {
  rpIdHash: Buffer;
  flagsBuf: Buffer;
  flags: {
    up: boolean;
    uv: boolean;
    at: boolean;
    ed: boolean;
    flagsInt: number;
  };
  counter: number;
  counterBuf: Buffer;
  aaguid?: Buffer;
  credentialID?: Buffer;
  credentialPublicKey?: Buffer;
};