@simplewebauthn/server 14.0.0 → 14.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/esm/authentication/verifyAuthenticationResponse.d.ts.map +1 -1
  2. package/esm/authentication/verifyAuthenticationResponse.js +12 -0
  3. package/esm/errors/index.d.ts +17 -0
  4. package/esm/errors/index.d.ts.map +1 -0
  5. package/esm/errors/index.js +24 -0
  6. package/esm/helpers/convertX509PublicKeyToCOSE.d.ts +1 -1
  7. package/esm/helpers/convertX509PublicKeyToCOSE.d.ts.map +1 -1
  8. package/esm/helpers/convertX509PublicKeyToCOSE.js +22 -6
  9. package/esm/helpers/cose.d.ts +1 -0
  10. package/esm/helpers/cose.d.ts.map +1 -1
  11. package/esm/helpers/cose.js +3 -0
  12. package/esm/helpers/isCertRevoked.d.ts +2 -1
  13. package/esm/helpers/isCertRevoked.d.ts.map +1 -1
  14. package/esm/helpers/isCertRevoked.js +91 -70
  15. package/esm/helpers/iso/isoCrypto/verifyAKP.d.ts.map +1 -1
  16. package/esm/helpers/iso/isoCrypto/verifyAKP.js +2 -1
  17. package/esm/helpers/mapX509SignatureAlgToCOSEAlg.d.ts +0 -3
  18. package/esm/helpers/mapX509SignatureAlgToCOSEAlg.d.ts.map +1 -1
  19. package/esm/helpers/mapX509SignatureAlgToCOSEAlg.js +19 -10
  20. package/esm/helpers/validateCertificatePath.d.ts +1 -0
  21. package/esm/helpers/validateCertificatePath.d.ts.map +1 -1
  22. package/esm/helpers/validateCertificatePath.js +94 -52
  23. package/esm/index.d.ts +1 -0
  24. package/esm/index.d.ts.map +1 -1
  25. package/esm/index.js +1 -0
  26. package/esm/metadata/verifyAttestationWithMetadata.d.ts.map +1 -1
  27. package/esm/metadata/verifyAttestationWithMetadata.js +1 -7
  28. package/esm/registration/verifications/verifyAttestationPacked.js +1 -1
  29. package/esm/registration/verifyRegistrationResponse.d.ts.map +1 -1
  30. package/esm/registration/verifyRegistrationResponse.js +19 -8
  31. package/package.json +4 -2
  32. package/script/authentication/verifyAuthenticationResponse.d.ts.map +1 -1
  33. package/script/authentication/verifyAuthenticationResponse.js +12 -0
  34. package/script/errors/index.d.ts +17 -0
  35. package/script/errors/index.d.ts.map +1 -0
  36. package/script/errors/index.js +29 -0
  37. package/script/helpers/convertX509PublicKeyToCOSE.d.ts +1 -1
  38. package/script/helpers/convertX509PublicKeyToCOSE.d.ts.map +1 -1
  39. package/script/helpers/convertX509PublicKeyToCOSE.js +21 -5
  40. package/script/helpers/cose.d.ts +1 -0
  41. package/script/helpers/cose.d.ts.map +1 -1
  42. package/script/helpers/cose.js +4 -0
  43. package/script/helpers/isCertRevoked.d.ts +2 -1
  44. package/script/helpers/isCertRevoked.d.ts.map +1 -1
  45. package/script/helpers/isCertRevoked.js +91 -70
  46. package/script/helpers/iso/isoCrypto/verifyAKP.d.ts.map +1 -1
  47. package/script/helpers/iso/isoCrypto/verifyAKP.js +2 -1
  48. package/script/helpers/mapX509SignatureAlgToCOSEAlg.d.ts +0 -3
  49. package/script/helpers/mapX509SignatureAlgToCOSEAlg.d.ts.map +1 -1
  50. package/script/helpers/mapX509SignatureAlgToCOSEAlg.js +19 -10
  51. package/script/helpers/validateCertificatePath.d.ts +1 -0
  52. package/script/helpers/validateCertificatePath.d.ts.map +1 -1
  53. package/script/helpers/validateCertificatePath.js +94 -52
  54. package/script/index.d.ts +1 -0
  55. package/script/index.d.ts.map +1 -1
  56. package/script/index.js +1 -0
  57. package/script/metadata/verifyAttestationWithMetadata.d.ts.map +1 -1
  58. package/script/metadata/verifyAttestationWithMetadata.js +1 -7
  59. package/script/registration/verifications/verifyAttestationPacked.js +1 -1
  60. package/script/registration/verifyRegistrationResponse.d.ts.map +1 -1
  61. package/script/registration/verifyRegistrationResponse.js +22 -11
@@ -1,5 +1,7 @@
1
+ import 'reflect-metadata';
1
2
  import { X509Certificate, X509ChainBuilder } from '@peculiar/x509';
2
3
  import { isCertRevoked } from './isCertRevoked.js';
4
+ import { SimpleWebAuthnError } from '../errors/index.js';
3
5
  /**
4
6
  * Traverse an array of PEM certificates and ensure they form a proper chain
5
7
  * @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)`
@@ -10,48 +12,25 @@ export async function validateCertificatePath(x5cCertsPEM, trustAnchorsPEM = [])
10
12
  // We have no trust anchors to chain back to, so skip path validation
11
13
  return true;
12
14
  }
13
- // Prepare to work with x5c certs
14
- const x5cCertsParsed = x5cCertsPEM.map((certPEM) => new X509Certificate(certPEM));
15
- // Check for any expired or temporally invalid certs in x5c
16
- for (let i = 0; i < x5cCertsParsed.length; i++) {
17
- const cert = x5cCertsParsed[i];
18
- const certPEM = x5cCertsPEM[i];
19
- try {
20
- await assertCertNotRevoked(cert);
21
- }
22
- catch (_err) {
23
- throw new Error(`Found revoked certificate in x5c:\n${certPEM}`);
24
- }
25
- try {
26
- assertCertIsWithinValidTimeWindow(cert.notBefore, cert.notAfter);
27
- }
28
- catch (_err) {
29
- throw new Error(`Found certificate out of validity period in x5c:\n${certPEM}`);
30
- }
31
- }
32
15
  // Prepare to work with trust anchor certs
33
16
  const trustAnchorsParsed = trustAnchorsPEM.map((certPEM) => {
34
17
  try {
35
18
  return new X509Certificate(certPEM);
36
19
  }
37
20
  catch (err) {
38
- const _err = err;
39
- throw new Error(`Could not parse trust anchor certificate:\n${certPEM}`, { cause: _err });
21
+ throw new SimpleWebAuthnError({
22
+ message: `Could not parse trust anchor certificate:\n${certPEM}`,
23
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
24
+ cause: err,
25
+ });
40
26
  }
41
27
  });
42
- // Filter out any expired or temporally invalid trust anchors certs
28
+ // Filter out any temporally invalid trust anchors certs
43
29
  const validTrustAnchors = [];
44
30
  for (let i = 0; i < trustAnchorsParsed.length; i++) {
45
31
  const cert = trustAnchorsParsed[i];
46
32
  try {
47
- await assertCertNotRevoked(cert);
48
- }
49
- catch (_err) {
50
- // Continue processing the other certs
51
- continue;
52
- }
53
- try {
54
- assertCertIsWithinValidTimeWindow(cert.notBefore, cert.notAfter);
33
+ assertCertIsWithinValidTimeWindow(cert);
55
34
  }
56
35
  catch (_err) {
57
36
  // Continue processing the other certs
@@ -60,22 +39,31 @@ export async function validateCertificatePath(x5cCertsPEM, trustAnchorsPEM = [])
60
39
  validTrustAnchors.push(cert);
61
40
  }
62
41
  if (validTrustAnchors.length === 0) {
63
- throw new Error('No specified trust anchor was valid for verifying x5c');
42
+ throw new SimpleWebAuthnError({
43
+ message: 'No specified trust anchor was valid for verifying x5c',
44
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
45
+ });
46
+ }
47
+ // Prepare to work with x5c certs
48
+ const x5cCertsParsed = x5cCertsPEM.map((certPEM) => new X509Certificate(certPEM));
49
+ // Break apart x5c into leaf + intermediates
50
+ const x5cLeafCert = x5cCertsParsed[0];
51
+ let x5cIntermediates = [];
52
+ if (x5cCertsParsed.length > 1) {
53
+ x5cIntermediates = x5cCertsParsed.slice(1);
64
54
  }
65
55
  // Try to verify x5c with each valid trust anchor
66
56
  let invalidCertificateChain = true;
57
+ let validatedChain = undefined;
67
58
  for (const anchor of validTrustAnchors) {
68
59
  try {
69
60
  const x5cWithTrustAnchor = x5cCertsParsed.concat([anchor]);
70
61
  const numUniqueCerts = new Set(x5cWithTrustAnchor.map((cert) => cert.toString('pem'))).size;
71
62
  if (numUniqueCerts !== x5cWithTrustAnchor.length) {
72
- throw new Error('Invalid certificate path: found duplicate certificates');
73
- }
74
- // Break apart x5c to try and build a valid cert chain
75
- const x5cLeafCert = x5cCertsParsed[0];
76
- let x5cIntermediates = [];
77
- if (x5cCertsParsed.length > 1) {
78
- x5cIntermediates = x5cCertsParsed.slice(1);
63
+ throw new SimpleWebAuthnError({
64
+ message: 'Invalid certificate path: found duplicate certificates',
65
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
66
+ });
79
67
  }
80
68
  // Order of certs doesn't matter here but for readability
81
69
  const chainBuilder = new X509ChainBuilder({ certificates: [...x5cIntermediates, anchor] });
@@ -109,27 +97,87 @@ export async function validateCertificatePath(x5cCertsPEM, trustAnchorsPEM = [])
109
97
  // Invalid cert chain, try the next trust anchor
110
98
  continue;
111
99
  }
112
- // If we successfully validated a path then there's no need to continue. Reset any existing
113
- // errors that were thrown by earlier trust anchors
100
+ if (certBeforeLastSignedByAnchor) {
101
+ /**
102
+ * Swap out the last cert in the chain with the anchor that we've already verified
103
+ * chains to the second-to-last certificate. This makes it easier to verify the chain
104
+ * as a standard certificate chain.
105
+ */
106
+ chain[chain.length - 1] = anchor;
107
+ }
108
+ // We successfully validated a chain so there's no need to continue
114
109
  invalidCertificateChain = false;
110
+ validatedChain = chain;
115
111
  break;
116
112
  }
117
113
  catch (err) {
118
- throw new Error('Unexpected error while validating certificate path', { cause: err });
114
+ throw new SimpleWebAuthnError({
115
+ message: 'Unexpected error while validating certificate path',
116
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
117
+ cause: err,
118
+ });
119
119
  }
120
120
  }
121
+ if (validatedChain) {
122
+ // Check for any temporally invalid or expired certs in the chain
123
+ for (let i = 0; i < validatedChain.length; i++) {
124
+ const cert = validatedChain[i];
125
+ try {
126
+ assertCertIsWithinValidTimeWindow(cert);
127
+ }
128
+ catch (_err) {
129
+ throw new SimpleWebAuthnError({
130
+ message: `Found certificate out of validity period:\n${cert.toString()}`,
131
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
132
+ });
133
+ }
134
+ /**
135
+ * Checking revocation is very expensive so do it only at the end when we're certain a cert
136
+ * is otherwise valid
137
+ */
138
+ let issuerCert = undefined;
139
+ if (i < validatedChain.length - 1) {
140
+ // Issuer cert is simply the next cert in the chain
141
+ issuerCert = validatedChain[i + 1];
142
+ }
143
+ else {
144
+ // `cert` is the anchor. Only try to verify its revocation status if it's a root certificate
145
+ if (await cert.isSelfSigned()) {
146
+ issuerCert = cert;
147
+ }
148
+ }
149
+ try {
150
+ await assertCertNotRevoked(cert, issuerCert);
151
+ }
152
+ catch (err) {
153
+ throw new SimpleWebAuthnError({
154
+ message: `The following certificate failed revocation status check\n${cert.toString()}`,
155
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
156
+ cause: err,
157
+ });
158
+ }
159
+ }
160
+ }
161
+ else {
162
+ invalidCertificateChain = true;
163
+ }
121
164
  // We tried multiple trust anchors and none of them worked
122
165
  if (invalidCertificateChain) {
123
- throw new InvalidCertificatePath();
166
+ throw new SimpleWebAuthnError({
167
+ message: 'x5c could not be chained to any specified trust anchor',
168
+ code: 'CERTIFICATE_PATH_VERIFICATION_FAILED',
169
+ });
124
170
  }
125
171
  return true;
126
172
  }
127
173
  /**
128
174
  * Check if the certificate is revoked or not. If it is, raise an error
175
+ *
176
+ * @throws Error - Wrap this in a SimpleWebAuthnError so RPs can identify issues here
129
177
  */
130
- async function assertCertNotRevoked(certificate) {
178
+ async function assertCertNotRevoked(certificate, issuerCert) {
131
179
  // Check for certificate revocation
132
- const subjectCertRevoked = await isCertRevoked(certificate);
180
+ const subjectCertRevoked = await isCertRevoked(certificate, issuerCert);
133
181
  if (subjectCertRevoked) {
134
182
  throw new Error('Found revoked certificate in certificate path');
135
183
  }
@@ -137,16 +185,10 @@ async function assertCertNotRevoked(certificate) {
137
185
  /**
138
186
  * Require the cert to be within its notBefore and notAfter time window
139
187
  */
140
- function assertCertIsWithinValidTimeWindow(certNotBefore, certNotAfter) {
188
+ function assertCertIsWithinValidTimeWindow(certificate) {
189
+ const { notBefore: certNotBefore, notAfter: certNotAfter } = certificate;
141
190
  const now = new Date(Date.now());
142
191
  if (certNotBefore > now || certNotAfter < now) {
143
192
  throw new Error('Certificate is not yet valid or expired');
144
193
  }
145
194
  }
146
- class InvalidCertificatePath extends Error {
147
- constructor() {
148
- const message = 'x5c could not be chained to any specified trust anchor';
149
- super(message);
150
- this.name = 'InvalidX5CChain';
151
- }
152
- }
package/esm/index.d.ts CHANGED
@@ -6,4 +6,5 @@ export * from './services/metadataService.js';
6
6
  export * from './services/settingsService.js';
7
7
  export * from './metadata/mdsTypes.js';
8
8
  export * from './types/index.js';
9
+ export * from './errors/index.js';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+CAA+C,CAAC;AAC9D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mDAAmD,CAAC;AAClE,cAAc,kDAAkD,CAAC;AACjE,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+CAA+C,CAAC;AAC9D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mDAAmD,CAAC;AAClE,cAAc,kDAAkD,CAAC;AACjE,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
package/esm/index.js CHANGED
@@ -6,3 +6,4 @@ export * from './services/metadataService.js';
6
6
  export * from './services/settingsService.js';
7
7
  export * from './metadata/mdsTypes.js';
8
8
  export * from './types/index.js';
9
+ export * from './errors/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"verifyAttestationWithMetadata.d.ts","sourceRoot":"","sources":["../../src/metadata/verifyAttestationWithMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIhE,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EAEZ,OAAO,EAER,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;GAGG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,SAAS,EACT,mBAAmB,EACnB,GAAG,EACH,uBAAuB,GACxB,EAAE;IACD,SAAS,EAAE,iBAAiB,CAAC;IAC7B,mBAAmB,EAAE,WAAW,CAAC;IACjC,GAAG,EAAE,WAAW,EAAE,GAAG,eAAe,EAAE,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,OAAO,CAAC,CAoJnB;AAED,KAAK,QAAQ,GAAG;IACd,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE;KAAG,GAAG,IAAI,OAAO,GAAG,QAAQ;CAe9D,CAAC"}
1
+ {"version":3,"file":"verifyAttestationWithMetadata.d.ts","sourceRoot":"","sources":["../../src/metadata/verifyAttestationWithMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIhE,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EAEZ,OAAO,EAER,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;GAGG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,SAAS,EACT,mBAAmB,EACnB,GAAG,EACH,uBAAuB,GACxB,EAAE;IACD,SAAS,EAAE,iBAAiB,CAAC;IAC7B,mBAAmB,EAAE,WAAW,CAAC;IACjC,GAAG,EAAE,WAAW,EAAE,GAAG,eAAe,EAAE,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,OAAO,CAAC,CA6InB;AAED,KAAK,QAAQ,GAAG;IACd,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE;KAAG,GAAG,IAAI,OAAO,GAAG,QAAQ;CAe9D,CAAC"}
@@ -106,13 +106,7 @@ export async function verifyAttestationWithMetadata({ statement, credentialPubli
106
106
  authenticatorIsSelfReferencing = true;
107
107
  }
108
108
  if (!authenticatorIsSelfReferencing) {
109
- try {
110
- await validateCertificatePath(authenticatorCerts, statementRootCerts);
111
- }
112
- catch (err) {
113
- const _err = err;
114
- throw new Error(`Could not validate certificate path with any metadata root certificates: ${_err.message}`);
115
- }
109
+ await validateCertificatePath(authenticatorCerts, statementRootCerts);
116
110
  }
117
111
  return true;
118
112
  }
@@ -91,7 +91,7 @@ export async function verifyAttestationPacked(options) {
91
91
  }
92
92
  catch (err) {
93
93
  const _err = err;
94
- throw new Error(`${_err.message} (Packed|Full)`);
94
+ throw new Error(`${_err.message} (Packed|Full)`, { cause: _err });
95
95
  }
96
96
  }
97
97
  verified = await verifySignature({
@@ -1 +1 @@
1
- {"version":3,"file":"verifyRegistrationResponse.d.ts","sourceRoot":"","sources":["../../src/registration/verifyRegistrationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAE1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,4CAA4C,EAAE,MAAM,6CAA6C,CAAC;AAoBhH;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9F;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE;IACP,QAAQ,EAAE,wBAAwB,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,mCAAmC,CAAC,EAAE,OAAO,CAAC;CAC/C,GACA,OAAO,CAAC,4BAA4B,CAAC,CAqPvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,KAAK,CAAC;IAChB,gBAAgB,CAAC,EAAE,KAAK,CAAC;CAC1B,GAAG;IACF,QAAQ,EAAE,IAAI,CAAC;IACf,gBAAgB,EAAE;QAChB,GAAG,EAAE,iBAAiB,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,kBAAkB,CAAC;QAC/B,cAAc,EAAE,YAAY,CAAC;QAC7B,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,OAAO,CAAC;QACtB,oBAAoB,EAAE,oBAAoB,CAAC;QAC3C,kBAAkB,EAAE,OAAO,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,6BAA6B,CAAC,EAAE,4CAA4C,CAAC;KAC9E,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,EAAE,WAAW,CAAC;IACtB,cAAc,EAAE,WAAW,CAAC;IAC5B,YAAY,EAAE,WAAW,CAAC;IAC1B,mBAAmB,EAAE,WAAW,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mCAAmC,CAAC,EAAE,OAAO,CAAC;CAC/C,CAAC"}
1
+ {"version":3,"file":"verifyRegistrationResponse.d.ts","sourceRoot":"","sources":["../../src/registration/verifyRegistrationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAE1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,4CAA4C,EAAE,MAAM,6CAA6C,CAAC;AAoBhH;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9F;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE;IACP,QAAQ,EAAE,wBAAwB,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,mCAAmC,CAAC,EAAE,OAAO,CAAC;CAC/C,GACA,OAAO,CAAC,4BAA4B,CAAC,CA8PvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,KAAK,CAAC;IAChB,gBAAgB,CAAC,EAAE,KAAK,CAAC;CAC1B,GAAG;IACF,QAAQ,EAAE,IAAI,CAAC;IACf,gBAAgB,EAAE;QAChB,GAAG,EAAE,iBAAiB,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,kBAAkB,CAAC;QAC/B,cAAc,EAAE,YAAY,CAAC;QAC7B,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,OAAO,CAAC;QACtB,oBAAoB,EAAE,oBAAoB,CAAC;QAC3C,kBAAkB,EAAE,OAAO,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,6BAA6B,CAAC,EAAE,4CAA4C,CAAC;KAC9E,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,EAAE,WAAW,CAAC;IACtB,cAAc,EAAE,WAAW,CAAC;IAC5B,YAAY,EAAE,WAAW,CAAC;IAC1B,mBAAmB,EAAE,WAAW,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mCAAmC,CAAC,EAAE,OAAO,CAAC;CAC/C,CAAC"}
@@ -1,9 +1,10 @@
1
+ import { PQCNotSupportedError } from '../errors/index.js';
1
2
  import { decodeAttestationObject, } from '../helpers/decodeAttestationObject.js';
2
3
  import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON.js';
3
4
  import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData.js';
4
5
  import { toHash } from '../helpers/toHash.js';
5
6
  import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey.js';
6
- import { COSEKEYS } from '../helpers/cose.js';
7
+ import { COSEKEYS, isPQCCOSEAlg } from '../helpers/cose.js';
7
8
  import { convertAAGUIDToString } from '../helpers/convertAAGUIDToString.js';
8
9
  import { parseBackupFlags } from '../helpers/parseBackupFlags.js';
9
10
  import { matchExpectedRPID } from '../helpers/matchExpectedRPID.js';
@@ -128,19 +129,29 @@ export async function verifyRegistrationResponse(options) {
128
129
  throw new Error('No AAGUID was present during registration');
129
130
  }
130
131
  const decodedPublicKey = decodeCredentialPublicKey(credentialPublicKey);
131
- const alg = decodedPublicKey.get(COSEKEYS.alg);
132
- if (typeof alg !== 'number') {
132
+ const pubKeyAlg = decodedPublicKey.get(COSEKEYS.alg);
133
+ if (typeof pubKeyAlg !== 'number') {
133
134
  throw new Error('Credential public key was missing numeric alg');
134
135
  }
135
136
  // Make sure the key algorithm is one we specified within the registration options
136
- if (!supportedAlgorithmIDs.includes(alg)) {
137
+ if (!supportedAlgorithmIDs.includes(pubKeyAlg)) {
137
138
  const supported = supportedAlgorithmIDs.join(', ');
138
- throw new Error(`Unexpected public key alg "${alg}", expected one of "${supported}"`);
139
+ throw new Error(`Unexpected public key alg "${pubKeyAlg}", expected one of "${supported}"`);
140
+ }
141
+ /**
142
+ * If the runtime doesn't support PQC passkeys then terminate here at the first sign of a PQC
143
+ * algorithm so that downstream issues that arise due to lack of PQC support won't get masked as
144
+ * unexpected behavior.
145
+ *
146
+ * I'm choosing to raise here even if attestation is "none" because it feels weird to allow an RP
147
+ * to parse a registration response w/o attestation only to encounter failure when trying to auth
148
+ * with the PQC passkey and the runtime doesn't support PQC.
149
+ */
150
+ if (isPQCCOSEAlg(pubKeyAlg) && !SettingsService.runtimeSupportsPQC()) {
151
+ throw new PQCNotSupportedError(pubKeyAlg);
139
152
  }
140
153
  const clientDataHash = await toHash(isoBase64URL.toBuffer(attestationResponse.clientDataJSON));
141
- const rootCertificates = SettingsService.getRootCertificates({
142
- identifier: fmt,
143
- });
154
+ const rootCertificates = SettingsService.getRootCertificates({ identifier: fmt });
144
155
  // Prepare arguments to pass to the relevant verification method
145
156
  const verifierOpts = {
146
157
  aaguid,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplewebauthn/server",
3
- "version": "14.0.0",
3
+ "version": "14.0.2",
4
4
  "description": "SimpleWebAuthn for Servers",
5
5
  "keywords": [
6
6
  "typescript",
@@ -56,7 +56,9 @@
56
56
  "@peculiar/asn1-rsa": "^2.6.1",
57
57
  "@peculiar/asn1-schema": "^2.6.0",
58
58
  "@peculiar/asn1-x509": "^2.6.1",
59
- "@peculiar/x509": "^1.14.3"
59
+ "@peculiar/asn1-x509-post-quantum": "^2.9.4",
60
+ "@peculiar/x509": "^2.1.0",
61
+ "reflect-metadata": "^0.2.2"
60
62
  },
61
63
  "devDependencies": {
62
64
  "@types/node": "^20.9.0"
@@ -1 +1 @@
1
- {"version":3,"file":"verifyAuthenticationResponse.d.ts","sourceRoot":"","sources":["../../src/authentication/verifyAuthenticationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EAAE,4CAA4C,EAAE,MAAM,6CAA6C,CAAC;AAIhH;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC;AAElG;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE;IACP,QAAQ,EAAE,0BAA0B,CAAC;IACrC,iBAAiB,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE;QACnB,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;KAChD,CAAC;CACH,GACA,OAAO,CAAC,8BAA8B,CAAC,CAgQzC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE;QAClB,YAAY,EAAE,eAAe,CAAC;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;QACtB,oBAAoB,EAAE,oBAAoB,CAAC;QAC3C,kBAAkB,EAAE,OAAO,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,6BAA6B,CAAC,EAAE,4CAA4C,CAAC;KAC9E,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"verifyAuthenticationResponse.d.ts","sourceRoot":"","sources":["../../src/authentication/verifyAuthenticationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EAAE,4CAA4C,EAAE,MAAM,6CAA6C,CAAC;AAQhH;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC;AAElG;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE;IACP,QAAQ,EAAE,0BAA0B,CAAC;IACrC,iBAAiB,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE;QACnB,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;KAChD,CAAC;CACH,GACA,OAAO,CAAC,8BAA8B,CAAC,CA6QzC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE;QAClB,YAAY,EAAE,eAAe,CAAC;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;QACtB,oBAAoB,EAAE,oBAAoB,CAAC;QAC3C,kBAAkB,EAAE,OAAO,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,6BAA6B,CAAC,EAAE,4CAA4C,CAAC;KAC9E,CAAC;CACH,CAAC"}
@@ -8,6 +8,10 @@ const parseAuthenticatorData_js_1 = require("../helpers/parseAuthenticatorData.j
8
8
  const parseBackupFlags_js_1 = require("../helpers/parseBackupFlags.js");
9
9
  const matchExpectedRPID_js_1 = require("../helpers/matchExpectedRPID.js");
10
10
  const index_js_1 = require("../helpers/iso/index.js");
11
+ const decodeCredentialPublicKey_js_1 = require("../helpers/decodeCredentialPublicKey.js");
12
+ const cose_js_1 = require("../helpers/cose.js");
13
+ const settingsService_js_1 = require("../services/settingsService.js");
14
+ const index_js_2 = require("../errors/index.js");
11
15
  /**
12
16
  * Verify that the user has legitimately completed the authentication process
13
17
  *
@@ -190,6 +194,14 @@ async function verifyAuthenticationResponse(options) {
190
194
  // on the device without going through this site
191
195
  throw new Error(`Response counter value ${counter} was lower than expected ${credential.counter}`);
192
196
  }
197
+ const decodedPublicKey = (0, decodeCredentialPublicKey_js_1.decodeCredentialPublicKey)(credential.publicKey);
198
+ const pubKeyAlg = decodedPublicKey.get(cose_js_1.COSEKEYS.alg);
199
+ if (typeof pubKeyAlg !== 'number') {
200
+ throw new Error('Credential public key was missing numeric alg');
201
+ }
202
+ if ((0, cose_js_1.isPQCCOSEAlg)(pubKeyAlg) && !settingsService_js_1.SettingsService.runtimeSupportsPQC()) {
203
+ throw new index_js_2.PQCNotSupportedError(pubKeyAlg);
204
+ }
193
205
  const { credentialDeviceType, credentialBackedUp } = (0, parseBackupFlags_js_1.parseBackupFlags)(flags);
194
206
  const toReturn = {
195
207
  verified: await (0, verifySignature_js_1.verifySignature)({
@@ -0,0 +1,17 @@
1
+ import type { COSEALG } from '../helpers/cose.js';
2
+ /**
3
+ * Base error class that helps disambiguate SimpleWebAuthn library errors from other library errors
4
+ */
5
+ export declare class SimpleWebAuthnError extends Error {
6
+ code: SimpleWebAuthnErrorCode;
7
+ constructor({ message, code, cause }: {
8
+ message: string;
9
+ code: SimpleWebAuthnErrorCode;
10
+ cause?: Error;
11
+ });
12
+ }
13
+ export declare class PQCNotSupportedError extends SimpleWebAuthnError {
14
+ constructor(alg: COSEALG);
15
+ }
16
+ export type SimpleWebAuthnErrorCode = 'RUNTIME_NO_PQC_SUPPORT' | 'CERTIFICATE_PATH_VERIFICATION_FAILED';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,IAAI,EAAE,uBAAuB,CAAC;gBAElB,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpC,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,uBAAuB,CAAC;QAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;KACf;CAKF;AAED,qBAAa,oBAAqB,SAAQ,mBAAmB;gBAC/C,GAAG,EAAE,OAAO;CAKzB;AAED,MAAM,MAAM,uBAAuB,GAC/B,wBAAwB,GACxB,sCAAsC,CAAC"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PQCNotSupportedError = exports.SimpleWebAuthnError = void 0;
4
+ const mapCoseAlgToWebCryptoKeyAlgName_js_1 = require("../helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js");
5
+ /**
6
+ * Base error class that helps disambiguate SimpleWebAuthn library errors from other library errors
7
+ */
8
+ class SimpleWebAuthnError extends Error {
9
+ constructor({ message, code, cause }) {
10
+ super(message, { cause });
11
+ Object.defineProperty(this, "code", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ this.name = 'SimpleWebAuthnError';
18
+ this.code = code;
19
+ }
20
+ }
21
+ exports.SimpleWebAuthnError = SimpleWebAuthnError;
22
+ class PQCNotSupportedError extends SimpleWebAuthnError {
23
+ constructor(alg) {
24
+ const webCryptoAlg = (0, mapCoseAlgToWebCryptoKeyAlgName_js_1.mapCoseAlgToWebCryptoKeyAlgName)(alg);
25
+ const message = `This runtime's WebCrypto.subtle does not support use of ${webCryptoAlg}`;
26
+ super({ message, code: 'RUNTIME_NO_PQC_SUPPORT' });
27
+ }
28
+ }
29
+ exports.PQCNotSupportedError = PQCNotSupportedError;
@@ -1,4 +1,4 @@
1
- import { COSEPublicKey } from './cose.js';
1
+ import { type COSEPublicKey } from './cose.js';
2
2
  import type { Uint8Array_ } from '../types/index.js';
3
3
  export declare function convertX509PublicKeyToCOSE(x509Certificate: Uint8Array_): COSEPublicKey;
4
4
  //# sourceMappingURL=convertX509PublicKeyToCOSE.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convertX509PublicKeyToCOSE.d.ts","sourceRoot":"","sources":["../../src/helpers/convertX509PublicKeyToCOSE.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,aAAa,EAGd,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,WAAW,GAC3B,aAAa,CA+Ff"}
1
+ {"version":3,"file":"convertX509PublicKeyToCOSE.d.ts","sourceRoot":"","sources":["../../src/helpers/convertX509PublicKeyToCOSE.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,aAAa,EAInB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,WAAW,GAC3B,aAAa,CAsGf"}
@@ -4,6 +4,7 @@ exports.convertX509PublicKeyToCOSE = convertX509PublicKeyToCOSE;
4
4
  const asn1_schema_1 = require("@peculiar/asn1-schema");
5
5
  const asn1_x509_1 = require("@peculiar/asn1-x509");
6
6
  const asn1_ecc_1 = require("@peculiar/asn1-ecc");
7
+ const asn1_x509_post_quantum_1 = require("@peculiar/asn1-x509-post-quantum");
7
8
  const asn1_rsa_1 = require("@peculiar/asn1-rsa");
8
9
  const cose_js_1 = require("./cose.js");
9
10
  const mapX509SignatureAlgToCOSEAlg_js_1 = require("./mapX509SignatureAlgToCOSEAlg.js");
@@ -14,8 +15,7 @@ function convertX509PublicKeyToCOSE(x509Certificate) {
14
15
  */
15
16
  const x509 = asn1_schema_1.AsnParser.parse(x509Certificate, asn1_x509_1.Certificate);
16
17
  const { tbsCertificate } = x509;
17
- const { subjectPublicKeyInfo, signature: _tbsSignature } = tbsCertificate;
18
- const signatureAlgorithm = _tbsSignature.algorithm;
18
+ const { subjectPublicKeyInfo } = tbsCertificate;
19
19
  const publicKeyAlgorithmID = subjectPublicKeyInfo.algorithm.algorithm;
20
20
  if (publicKeyAlgorithmID === asn1_ecc_1.id_ecPublicKey) {
21
21
  /**
@@ -25,12 +25,15 @@ function convertX509PublicKeyToCOSE(x509Certificate) {
25
25
  throw new Error('Certificate public key was missing parameters (EC2)');
26
26
  }
27
27
  const ecParameters = asn1_schema_1.AsnParser.parse(new Uint8Array(subjectPublicKeyInfo.algorithm.parameters), asn1_ecc_1.ECParameters);
28
- let crv = -999;
28
+ let alg;
29
+ let crv;
29
30
  const { namedCurve } = ecParameters;
30
31
  if (namedCurve === asn1_ecc_1.id_secp256r1) {
32
+ alg = cose_js_1.COSEALG.ES256;
31
33
  crv = cose_js_1.COSECRV.P256;
32
34
  }
33
35
  else if (namedCurve === asn1_ecc_1.id_secp384r1) {
36
+ alg = cose_js_1.COSEALG.ES384;
34
37
  crv = cose_js_1.COSECRV.P384;
35
38
  }
36
39
  else {
@@ -51,7 +54,7 @@ function convertX509PublicKeyToCOSE(x509Certificate) {
51
54
  }
52
55
  const coseEC2PubKey = new Map();
53
56
  coseEC2PubKey.set(cose_js_1.COSEKEYS.kty, cose_js_1.COSEKTY.EC2);
54
- coseEC2PubKey.set(cose_js_1.COSEKEYS.alg, (0, mapX509SignatureAlgToCOSEAlg_js_1.mapX509SignatureAlgToCOSEAlg)(signatureAlgorithm));
57
+ coseEC2PubKey.set(cose_js_1.COSEKEYS.alg, alg);
55
58
  coseEC2PubKey.set(cose_js_1.COSEKEYS.crv, crv);
56
59
  coseEC2PubKey.set(cose_js_1.COSEKEYS.x, x);
57
60
  coseEC2PubKey.set(cose_js_1.COSEKEYS.y, y);
@@ -64,11 +67,24 @@ function convertX509PublicKeyToCOSE(x509Certificate) {
64
67
  const rsaPublicKey = asn1_schema_1.AsnParser.parse(subjectPublicKeyInfo.subjectPublicKey, asn1_rsa_1.RSAPublicKey);
65
68
  const coseRSAPubKey = new Map();
66
69
  coseRSAPubKey.set(cose_js_1.COSEKEYS.kty, cose_js_1.COSEKTY.RSA);
67
- coseRSAPubKey.set(cose_js_1.COSEKEYS.alg, (0, mapX509SignatureAlgToCOSEAlg_js_1.mapX509SignatureAlgToCOSEAlg)(signatureAlgorithm));
70
+ /**
71
+ * The algorithm ID is too ambiguous to know what this alg should really be. But practically
72
+ * speaking `shaHashOverride` is always specified when verifying signatures with RSA public keys
73
+ * which ultimately overrides this sensible default. Using RS256 also gets the correct WebCrypto
74
+ * alg name later on in verifyRSA.ts
75
+ */
76
+ coseRSAPubKey.set(cose_js_1.COSEKEYS.alg, cose_js_1.COSEALG.RS256);
68
77
  coseRSAPubKey.set(cose_js_1.COSEKEYS.n, new Uint8Array(rsaPublicKey.modulus));
69
78
  coseRSAPubKey.set(cose_js_1.COSEKEYS.e, new Uint8Array(rsaPublicKey.publicExponent));
70
79
  cosePublicKey = coseRSAPubKey;
71
80
  }
81
+ else if ([asn1_x509_post_quantum_1.id_ml_dsa_44, asn1_x509_post_quantum_1.id_ml_dsa_65, asn1_x509_post_quantum_1.id_ml_dsa_87].indexOf(publicKeyAlgorithmID) >= 0) {
82
+ const coseAKPPubKey = new Map();
83
+ coseAKPPubKey.set(cose_js_1.COSEKEYS.kty, cose_js_1.COSEKTY.AKP);
84
+ coseAKPPubKey.set(cose_js_1.COSEKEYS.alg, (0, mapX509SignatureAlgToCOSEAlg_js_1.mapX509SignatureAlgToCOSEAlg)(publicKeyAlgorithmID));
85
+ coseAKPPubKey.set(cose_js_1.COSEKEYS.pub, new Uint8Array(subjectPublicKeyInfo.subjectPublicKey));
86
+ cosePublicKey = coseAKPPubKey;
87
+ }
72
88
  else {
73
89
  throw new Error(`Certificate public key contained unexpected algorithm ID ${publicKeyAlgorithmID}`);
74
90
  }
@@ -135,4 +135,5 @@ export declare enum COSEALG {
135
135
  RS1 = -65535
136
136
  }
137
137
  export declare function isCOSEAlg(alg: number | undefined): alg is COSEALG;
138
+ export declare function isPQCCOSEAlg(alg: COSEALG): boolean;
138
139
  //# sourceMappingURL=cose.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cose.d.ts","sourceRoot":"","sources":["../../src/helpers/cose.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cose.d.ts","sourceRoot":"","sources":["../../src/helpers/cose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAE1B,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAG,OAAO,GAAG,SAAS,CAAC;IAC5C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAG,OAAO,GAAG,SAAS,CAAC;IAE5C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAE7C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC;IAE9C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAE7C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC;IAE9C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAE7C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC;IAE9C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAE7C,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAG,WAAW,GAAG,SAAS,CAAC;IAEhD,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,aAAa,GAC3B,aAAa,IAAI,gBAAgB,CAGnC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,aAAa,GAC3B,aAAa,IAAI,gBAAgB,CAGnC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,aAAa,GAC3B,aAAa,IAAI,gBAAgB,CAGnC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,aAAa,GAC3B,aAAa,IAAI,gBAAgB,CAGnC;AAED;;;;;GAKG;AACH,oBAAY,QAAQ;IAClB,GAAG,IAAI;IACP,GAAG,IAAI;IACP,GAAG,KAAK;IACR,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,GAAG,KAAK;CACT;AAED;;;;GAIG;AACH,oBAAY,OAAO;IACjB,GAAG,IAAI;IACP,GAAG,IAAI;IACP,GAAG,IAAI;IACP,GAAG,IAAI;CACR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,IAAI,OAAO,CAEjE;AAED;;;;GAIG;AACH,oBAAY,OAAO;IACjB,IAAI,IAAI;IACR,IAAI,IAAI;IACR,IAAI,IAAI;IACR,OAAO,IAAI;IACX,SAAS,IAAI;CACd;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,IAAI,OAAO,CAEjE;AAED;;;;GAIG;AACH,oBAAY,OAAO;IACjB,KAAK,KAAK;IACV,KAAK,KAAK;IACV,KAAK,MAAM;IACX,KAAK,MAAM;IACX,KAAK,MAAM;IACX,KAAK,MAAM;IACX,KAAK,MAAM;IACX,MAAM,MAAM;IACZ,SAAS,MAAM;IACf,SAAS,MAAM;IACf,SAAS,MAAM;IACf,KAAK,OAAO;IACZ,KAAK,OAAO;IACZ,KAAK,OAAO;IACZ,GAAG,SAAS;CACb;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,IAAI,OAAO,CAEjE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAElD"}
@@ -8,6 +8,7 @@ exports.isCOSEPublicKeyAKP = isCOSEPublicKeyAKP;
8
8
  exports.isCOSEKty = isCOSEKty;
9
9
  exports.isCOSECrv = isCOSECrv;
10
10
  exports.isCOSEAlg = isCOSEAlg;
11
+ exports.isPQCCOSEAlg = isPQCCOSEAlg;
11
12
  /**
12
13
  * A type guard for determining if a COSE public key is an OKP key pair
13
14
  */
@@ -110,3 +111,6 @@ var COSEALG;
110
111
  function isCOSEAlg(alg) {
111
112
  return Object.values(COSEALG).indexOf(alg) >= 0;
112
113
  }
114
+ function isPQCCOSEAlg(alg) {
115
+ return [COSEALG.ML_DSA_44, COSEALG.ML_DSA_65, COSEALG.ML_DSA_87].indexOf(alg) >= 0;
116
+ }
@@ -1,3 +1,4 @@
1
+ import 'reflect-metadata';
1
2
  import { type X509Certificate } from '@peculiar/x509';
2
3
  /**
3
4
  * A method to pull a CRL from a certificate and compare its serial number to the list of revoked
@@ -5,5 +6,5 @@ import { type X509Certificate } from '@peculiar/x509';
5
6
  *
6
7
  * CRL certificate structure referenced from https://tools.ietf.org/html/rfc5280#page-117
7
8
  */
8
- export declare function isCertRevoked(cert: X509Certificate): Promise<boolean>;
9
+ export declare function isCertRevoked(certificate: X509Certificate, issuer?: X509Certificate): Promise<boolean>;
9
10
  //# sourceMappingURL=isCertRevoked.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"isCertRevoked.d.ts","sourceRoot":"","sources":["../../src/helpers/isCertRevoked.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAC;AAexB;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAkG3E"}
1
+ {"version":3,"file":"isCertRevoked.d.ts","sourceRoot":"","sources":["../../src/helpers/isCertRevoked.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAC;AAexB;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,eAAe,EAC5B,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,OAAO,CAAC,CA0HlB"}