@breakside/jskit 2024.34.0 → 2024.41.0

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 (94) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/Foundation+HTML.js +3 -1
  7. package/Frameworks/Foundation.jsframework/JS/JSClass.js +4 -1
  8. package/Frameworks/Foundation.jsframework/JS/JSHTMLUserAgent.js +130 -0
  9. package/Frameworks/Foundation.jsframework/JS/JSNodeURLSessionStreamTask.js +1 -1
  10. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  11. package/Frameworks/Foundation.jsframework/sources.json +3 -1
  12. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  13. package/Frameworks/SecurityKit.jsframework/JS/SECCBOR.js +4 -0
  14. package/Frameworks/SecurityKit.jsframework/JS/SECCOSE.js +135 -0
  15. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+HTML.js +231 -70
  16. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+Node.js +155 -60
  17. package/Frameworks/SecurityKit.jsframework/JS/SECCipher.js +125 -54
  18. package/Frameworks/SecurityKit.jsframework/JS/SECDataKey.js +5 -4
  19. package/Frameworks/SecurityKit.jsframework/JS/SECHMAC+HTML.js +15 -11
  20. package/Frameworks/SecurityKit.jsframework/JS/SECHMAC+Node.js +17 -3
  21. package/Frameworks/SecurityKit.jsframework/JS/SECHTMLDeviceAuthentication.js +206 -120
  22. package/Frameworks/SecurityKit.jsframework/JS/SECHTMLKey.js +17 -0
  23. package/Frameworks/SecurityKit.jsframework/JS/SECHash.js +1 -0
  24. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebAlgorithms.js +9 -1
  25. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebEncryption.js +391 -0
  26. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebToken.js +1 -1
  27. package/Frameworks/SecurityKit.jsframework/JS/SECKey.js +14 -1
  28. package/Frameworks/SecurityKit.jsframework/JS/SECNodeKey.js +66 -1
  29. package/Frameworks/SecurityKit.jsframework/JS/SECSign+HTML.js +2 -27
  30. package/Frameworks/SecurityKit.jsframework/JS/SECSign+Node.js +103 -278
  31. package/Frameworks/SecurityKit.jsframework/JS/SECSign.js +27 -0
  32. package/Frameworks/SecurityKit.jsframework/JS/SECVerify+Node.js +60 -57
  33. package/Frameworks/SecurityKit.jsframework/JS/SecurityKit.js +1 -0
  34. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  35. package/Frameworks/SecurityKit.jsframework/sources.json +6 -0
  36. package/Info.json +2 -2
  37. package/Node/KeyCommand.js +8 -1
  38. package/Node/io.breakside.jskit-bundle.js +2 -2
  39. package/Node/jskit +1 -0
  40. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  41. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  42. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  43. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  44. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  45. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  46. package/Root/Frameworks/DBKit/DBEncryptedObject.js +2 -2
  47. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  48. package/Root/Frameworks/DOM/Info.yaml +1 -1
  49. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  50. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  51. package/Root/Frameworks/Foundation/Foundation+HTML.js +3 -1
  52. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  53. package/Root/Frameworks/Foundation/JSClass.js +4 -1
  54. package/Root/Frameworks/Foundation/JSHTMLUserAgent.js +130 -0
  55. package/Root/Frameworks/Foundation/JSNodeURLSessionStreamTask.js +1 -1
  56. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  57. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  58. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  59. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  60. package/Root/Frameworks/NotificationKit/NKWebPushService.js +2 -2
  61. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  62. package/Root/Frameworks/PDFKit/PDFEncryption.js +1 -1
  63. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  64. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  65. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  66. package/Root/Frameworks/SecurityKit/SECCBOR.js +4 -0
  67. package/Root/Frameworks/SecurityKit/SECCOSE.js +135 -0
  68. package/Root/Frameworks/SecurityKit/SECCipher+HTML.js +231 -70
  69. package/Root/Frameworks/SecurityKit/SECCipher+Node.js +155 -60
  70. package/Root/Frameworks/SecurityKit/SECCipher.js +125 -54
  71. package/Root/Frameworks/SecurityKit/SECDataKey.js +5 -4
  72. package/Root/Frameworks/SecurityKit/SECHMAC+HTML.js +15 -11
  73. package/Root/Frameworks/SecurityKit/SECHMAC+Node.js +17 -3
  74. package/Root/Frameworks/SecurityKit/SECHTMLDeviceAuthentication.js +206 -120
  75. package/Root/Frameworks/SecurityKit/SECHTMLKey.js +17 -0
  76. package/Root/Frameworks/SecurityKit/SECHash.js +1 -0
  77. package/Root/Frameworks/SecurityKit/SECJSONWebAlgorithms.js +9 -1
  78. package/Root/Frameworks/SecurityKit/SECJSONWebEncryption.js +391 -0
  79. package/Root/Frameworks/SecurityKit/SECJSONWebToken.js +1 -1
  80. package/Root/Frameworks/SecurityKit/SECKey.js +14 -1
  81. package/Root/Frameworks/SecurityKit/SECNodeKey.js +66 -1
  82. package/Root/Frameworks/SecurityKit/SECSign+HTML.js +2 -27
  83. package/Root/Frameworks/SecurityKit/SECSign+Node.js +103 -278
  84. package/Root/Frameworks/SecurityKit/SECSign.js +27 -0
  85. package/Root/Frameworks/SecurityKit/SECVerify+Node.js +60 -57
  86. package/Root/Frameworks/SecurityKit/SecurityKit.js +1 -0
  87. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  88. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  89. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  90. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  91. package/Root/Frameworks/UIKit/UIPlatform+HTML.js +2 -1
  92. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  93. package/package.json +1 -1
  94. package/Root/Templates/workspace/.gitignore +0 -4
@@ -38,14 +38,12 @@ SECHMAC.definePropertiesFromExtensions({
38
38
  if (!completion){
39
39
  completion = Promise.completion(Promise.resolveNonNull);
40
40
  }
41
- var algorithm = {
42
- name: this.htmlAlgorithm.name,
43
- hash: this.htmlAlgorithm.hash,
44
- length: 256
45
- };
41
+ var algorithm = this.htmlAlgorithm;
46
42
  var extractable = true;
47
43
  crypto.subtle.generateKey(algorithm, extractable, ["sign"]).then(function(htmlKey){
48
- completion.call(target, SECHTMLKey.initWithKey(htmlKey));
44
+ var key = SECHTMLKey.initWithKey(htmlKey);
45
+ key.id = JSSHA1Hash(UUID.init().bytes).base64URLStringRepresentation();
46
+ completion.call(target, key);
49
47
  }, function(e){
50
48
  completion.call(target, null);
51
49
  });
@@ -57,7 +55,10 @@ SECHMAC.definePropertiesFromExtensions({
57
55
  completion = Promise.completion(Promise.resolveNonNull);
58
56
  }
59
57
  var extractable = true;
60
- var algorithm = this.htmlAlgorithm;
58
+ var algorithm = {
59
+ name: this.htmlAlgorithm.name,
60
+ hash: this.htmlAlgorithm.hash
61
+ };
61
62
  crypto.subtle.importKey("raw", data, algorithm, extractable, ["sign"]).then(function(htmlKey){
62
63
  completion.call(target, SECHTMLKey.initWithKey(htmlKey));
63
64
  }, function(e){
@@ -77,7 +78,10 @@ SECHMAC.definePropertiesFromExtensions({
77
78
  if (!completion){
78
79
  completion = Promise.completion(Promise.resolveNonNull);
79
80
  }
80
- var algorithm = this.htmlAlgorithm;
81
+ var algorithm = {
82
+ name: this.htmlAlgorithm.name,
83
+ hash: this.htmlAlgorithm.hash
84
+ };
81
85
  var data = JSData.initWithChunks(this.chunks);
82
86
  crypto.subtle.sign(algorithm, this.key.htmlKey, data).then(function(computed){
83
87
  completion.call(target, JSData.initWithBuffer(computed));
@@ -91,9 +95,9 @@ SECHMAC.definePropertiesFromExtensions({
91
95
 
92
96
  var htmlAlgorithms = {};
93
97
  htmlAlgorithms[SECHMAC.Algorithm.sha1] = { name: 'HMAC', hash: 'SHA-1'};
94
- htmlAlgorithms[SECHMAC.Algorithm.sha256] = { name: 'HMAC', hash: 'SHA-256'};
95
- htmlAlgorithms[SECHMAC.Algorithm.sha384] = { name: 'HMAC', hash: 'SHA-384'};
96
- htmlAlgorithms[SECHMAC.Algorithm.sha512] = { name: 'HMAC', hash: 'SHA-512'};
98
+ htmlAlgorithms[SECHMAC.Algorithm.sha256] = { name: 'HMAC', hash: 'SHA-256', length: 256};
99
+ htmlAlgorithms[SECHMAC.Algorithm.sha384] = { name: 'HMAC', hash: 'SHA-384', length: 384};
100
+ htmlAlgorithms[SECHMAC.Algorithm.sha512] = { name: 'HMAC', hash: 'SHA-512', length: 512};
97
101
 
98
102
 
99
103
  })();
@@ -36,11 +36,25 @@ SECHMAC.definePropertiesFromExtensions({
36
36
  if (!completion){
37
37
  completion = Promise.completion(Promise.resolveNonNull);
38
38
  }
39
- crypto.randomBytes(32, function(error, keyBytes){
39
+ var length;
40
+ switch (this.nodeAlgorithm){
41
+ case "sha512":
42
+ length = 512;
43
+ break;
44
+ case "sha384":
45
+ length = 384;
46
+ break;
47
+ default:
48
+ length = 256;
49
+ break;
50
+ }
51
+ crypto.generateKey("hmac", {length: length}, function(error, nodeKeyObject){
40
52
  if (error){
41
53
  completion.call(target, null);
42
54
  }else{
43
- completion.call(target, SECNodeKey.initWithData(JSData.initWithNodeBuffer(keyBytes)));
55
+ var key = SECNodeKey.initWithNodeKeyObject(nodeKeyObject);
56
+ key.id = JSSHA1Hash(UUID.init().bytes).base64URLStringRepresentation();
57
+ completion.call(target, key);
44
58
  }
45
59
  });
46
60
  return completion.promise;
@@ -60,7 +74,7 @@ SECHMAC.definePropertiesFromExtensions({
60
74
  throw new Error("SECHMAC must have a key before calling update()");
61
75
  }
62
76
  if (this.nodeHash === null){
63
- this.nodeHash = crypto.createHmac(this.nodeAlgorithm, this.key.keyData);
77
+ this.nodeHash = crypto.createHmac(this.nodeAlgorithm, this.key.nodeKeyObject);
64
78
  }
65
79
  this.nodeHash.update(data);
66
80
  },
@@ -13,12 +13,13 @@
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
15
 
16
+ // #import Foundation
16
17
  // #import "SECDeviceAuthentication.js"
17
18
  // #import "SECCipher.js"
18
19
  // #import "SECSign.js"
19
20
  // #import "SECCBOR.js"
20
21
  // #import "SECHash.js"
21
- // #import "SECJSONWebAlgorithms.js"
22
+ // #import "SECCOSE.js"
22
23
  // jshint browser: true
23
24
  /* global AuthenticatorAttestationResponse */
24
25
  'use strict';
@@ -66,12 +67,13 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
66
67
  // challengeData
67
68
  // supportedAlgorithms
68
69
  // platform
70
+ // conditional
69
71
  if (!completion){
70
72
  completion = Promise.completion();
71
73
  }
72
74
  if (this.credentialStore === null){
73
75
  JSRunLoop.main.schedule(completion, target, null);
74
- return;
76
+ return completion.promise;
75
77
  }
76
78
  registration = JSCopy(registration);
77
79
  if (!registration.providerName){
@@ -98,21 +100,19 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
98
100
  challenge: registration.challengeData,
99
101
  pubKeyCredParams: [],
100
102
  authenticatorSelection: {
101
- // Browser support for resident keys is spotty:
102
- // - Chrome works, requiring the user to set a PIN, but can't share with others
103
- // - Safari works, no PIN required, but can't share with others
104
- // - Safari will get PIN support in Safari 14
105
- // - Firefox doesn't work on macOS, but supposedly works on windows with a PIN
106
- // Without a resident key, we need something like a username that the user can
107
- // provide so we can lookup allowed key IDs on a server and send them back to
108
- // the client before authenticating
109
- requireResidentKey: false,
110
- residentKey: "discouraged",
111
- userVerification: registration.platform ? "required" : "discouraged",
103
+ // requiring a resident key is necessary for Android to
104
+ // actually save a passkey. Apple OSes will save a passkey
105
+ // regardless of resident key settings
106
+ requireResidentKey: registration.platform ? true : false,
107
+ residentKey: registration.platform ? "required" : "discouraged",
108
+ userVerification: registration.platform && !registration.conditional ? "required" : "discouraged",
112
109
  authenticatorAttachment: registration.platform ? "platform" : "cross-platform"
113
110
  },
114
111
  attestation: "none",
115
- timeout: 10000
112
+ timeout: 60000,
113
+ extensions: {
114
+ credProps: true
115
+ }
116
116
  };
117
117
  if (registration.domain !== undefined){
118
118
  info.rp.id = registration.domain;
@@ -132,34 +132,43 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
132
132
  ];
133
133
  }
134
134
  var credentials = this.credentialStore;
135
- this.credentialStore.create({publicKey: info}).then(function(credential){
135
+ var handleCredential = function(credential){
136
136
  if (!credential || credential.type != "public-key"){
137
137
  completion.call(target, null);
138
138
  return;
139
139
  }
140
- var clientData = JSData.initWithBuffer(credential.response.clientDataJSON);
141
- var attestationCBOR = JSData.initWithBuffer(credential.response.attestationObject);
142
- var attestationParser = SECCBORParser.initWithData(attestationCBOR);
143
- attestationParser.encodeDataAsBase64URL = true;
144
- var attestation = attestationParser.parse();
145
- var authData = attestation.authData.dataByDecodingBase64URL();
146
- var length = (authData[53] << 8) | authData[54];
147
- var keyParser = SECCBORParser.initWithData(authData);
148
- keyParser.offset = 55 + length;
149
- var coseKey = keyParser.readNext();
150
- var jwk = jwkForCoseKey(coseKey, credential.id);
140
+ var jwk = credential.response.getPublicJWK();
141
+ var webauthn = credential.toJSON();
151
142
  var result = {
143
+ name: credential.jskitName,
152
144
  jwk: jwk,
153
- webauthn: {
154
- attestation: attestation,
155
- clientData: clientData.base64URLStringRepresentation()
156
- },
157
- challenge: registration.challengeData
145
+ challenge: registration.challengeData,
146
+ webauthn: webauthn
158
147
  };
159
148
  completion.call(target, result);
160
- }, function(error){
161
- completion.call(target, null);
162
- });
149
+ };
150
+ if (registration.conditional){
151
+ if (!window.PublicKeyCredential || !window.PublicKeyCredential.getClientCapabilities){
152
+ JSRunLoop.main.schedule(completion, target, null);
153
+ return completion.promise;
154
+ }
155
+ window.PublicKeyCredential.getClientCapabilities().then(function(capabilities){
156
+ if (!capabilities || !capabilities.conditionalCreate){
157
+ completion.call(target, null);
158
+ return;
159
+ }
160
+ credentials.create({publicKey: info, mediation: "conditional"}).then(handleCredential,function(error){
161
+ completion.call(target, null);
162
+ });
163
+ }, function(e){
164
+ logger.error("failed to getClientCapabilities(): %{error}", e);
165
+ completion.call(target, null);
166
+ });
167
+ }else{
168
+ credentials.create({publicKey: info}).then(handleCredential, function(error){
169
+ completion.call(target, null);
170
+ });
171
+ }
163
172
  return completion.promise;
164
173
  },
165
174
 
@@ -178,9 +187,9 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
178
187
  }
179
188
  var info = {
180
189
  challenge: request.challengeData,
181
- userVerification: "discouraged",
182
- timeout: 10000,
183
- allowCredentials: []
190
+ userVerification: request.platform ? "required" : "discouraged",
191
+ timeout: 60000,
192
+ allowCredentials: [],
184
193
  };
185
194
  if (request.domain){
186
195
  info.rpId = request.domain;
@@ -198,7 +207,7 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
198
207
  id: request.allowedKeyIDs[i].dataByDecodingBase64URL()
199
208
  };
200
209
  if (request.platform){
201
- allowedCredential.transports = ["internal"];
210
+ allowedCredential.transports = ["internal", "hybrid"];
202
211
  }
203
212
  info.allowCredentials.push(allowedCredential);
204
213
  }catch (e){
@@ -212,15 +221,10 @@ JSClass("SECHTMLDeviceAuthentication", JSObject, {
212
221
  completion.call(target, null);
213
222
  return;
214
223
  }
215
- var clientData = JSData.initWithBuffer(credential.response.clientDataJSON);
216
- var authData = JSData.initWithBuffer(credential.response.authenticatorData);
217
- var hash = SECHash.initWithAlgorithm(SECHash.Algorithm.sha256);
224
+ var webauthn = credential.toJSON();
218
225
  var result = {
219
226
  kid: credential.id,
220
- webauthn: {
221
- authData: authData.base64URLStringRepresentation(),
222
- clientData: clientData.base64URLStringRepresentation()
223
- },
227
+ webauthn: webauthn,
224
228
  challenge: request.challengeData,
225
229
  signature: JSData.initWithBuffer(credential.response.signature)
226
230
  };
@@ -245,86 +249,168 @@ Object.defineProperties(SECDeviceAuthentication, {
245
249
  });
246
250
 
247
251
  var coseAlgorithmsBySignAlgorithm = {};
248
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA256] = -257;
249
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA384] = -258;
250
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA512] = -259;
251
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA256] = -7;
252
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA384] = -35;
253
- coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA512] = -36;
252
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA256] = SECCOSE.Algorithm.rsaSHA256;
253
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA384] = SECCOSE.Algorithm.rsaSHA384;
254
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.rsaSHA512] = SECCOSE.Algorithm.rsaSHA512;
255
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA256] = SECCOSE.Algorithm.ellipticCurveSHA256;
256
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA384] = SECCOSE.Algorithm.ellipticCurveSHA384;
257
+ coseAlgorithmsBySignAlgorithm[SECSign.Algorithm.ellipticCurveSHA512] = SECCOSE.Algorithm.ellipticCurveSHA512;
258
+
259
+ if (window.PublicKeyCredential){
254
260
 
255
- var remap = function(dictionary, keyMap){
256
- var copy = {};
257
- for (var k in dictionary){
258
- copy[keyMap[k] || k] = dictionary[k];
261
+ if (!window.PublicKeyCredential.prototype.toJSON){
262
+ window.PublicKeyCredential.prototype.toJSON = function PublicKeyCredential_toJSON(){
263
+ var dictionary = {};
264
+ dictionary.id = this.id;
265
+ dictionary.rawId = JSData.initWithBuffer(this.rawId).base64URLStringRepresentation();
266
+ dictionary.authenticatorAttachment = this.authenticatorAttachment || "";
267
+ dictionary.type = this.type || "public-key";
268
+ dictionary.clientExtensionResults = this.getClientExtensionResults();
269
+ dictionary.response = this.response.toJSON ? this.response.toJSON() : {};
270
+ return dictionary;
271
+ };
259
272
  }
260
- return copy;
261
- };
262
273
 
263
- var jwkForCoseKey = function(coseKey, kid){
264
- coseKey = remap(coseKey, {
265
- "1": "kty",
266
- "2": "kid",
267
- "3": "alg",
268
- "-1": "crv",
269
- "-2": "x",
270
- "-3": "y",
271
- "-4": "d"
272
- });
273
- var jwk = {
274
- kid: kid,
275
- key_ops: ["verify"]
276
- };
277
- if (coseKey.kty == 2){
278
- jwk.kty = SECJSONWebAlgorithms.KeyType.ellipticCurve;
279
- switch (coseKey.alg){
280
- case -7:
281
- jwk.alg = SECJSONWebAlgorithms.Algorithm.ellipticCurveSHA256;
282
- break;
283
- case -35:
284
- jwk.alg = SECJSONWebAlgorithms.Algorithm.ellipticCurveSHA384;
285
- break;
286
- case -36:
287
- jwk.alg = SECJSONWebAlgorithms.Algorithm.ellipticCurveSHA512;
288
- break;
289
- default:
290
- return null;
291
- }
292
- switch (coseKey.crv){
293
- case 1:
294
- jwk.crv = "P-256";
295
- break;
296
- case 2:
297
- jwk.crv = "P-384";
298
- break;
299
- case 3:
300
- jwk.crv = "P-512";
301
- break;
302
- default:
303
- return null;
304
- }
305
- jwk.x = coseKey.x.base64URLStringRepresentation();
306
- jwk.y = coseKey.y.base64URLStringRepresentation();
307
- return jwk;
274
+ if (!window.PublicKeyCredential.prototype.getClientExtensionResults){
275
+ window.PublicKeyCredential.prototype.getClientExtensionResults = function PublicKeyCredential_getClientExtensionResults(){
276
+ if (this._clientExtensionResults === undefined){
277
+ var authData = JSData.initWithBuffer(this.getAuthenticatorData());
278
+ var idLength = (authData[53] << 8) | authData[54];
279
+ var offset = 55 + idLength;
280
+ var cbor = SECCBORParser.initWithData(authData.subdataInRange(JSRange(offset, authData.length - offset)));
281
+ var coseKey = cbor.readNext(); // ingored, only reading to arrive at the extensions start location
282
+ this._clientExtensionResults = cbor.readNext() || {};
283
+ }
284
+ return this._clientExtensionResults;
285
+ };
308
286
  }
309
- if (coseKey.kty == 0){ // RSA
310
- jwk.kty = SECJSONWebAlgorithms.KeyType.rsa;
311
- switch (coseKey.alg){
312
- case -257:
313
- jwk.alg = SECJSONWebAlgorithms.Algorithm.rsaSHA256;
314
- break;
315
- case -258:
316
- jwk.alg = SECJSONWebAlgorithms.Algorithm.rsaSHA384;
317
- break;
318
- case -259:
319
- jwk.alg = SECJSONWebAlgorithms.Algorithm.rsaSHA512;
320
- break;
321
- default:
322
- return null;
287
+
288
+ Object.defineProperties(window.PublicKeyCredential.prototype, {
289
+ jskitName: {
290
+ enumerable: false,
291
+ configurable: false,
292
+ get: function PublicKeyCredential_getJSKitName(){
293
+ var extensions = this.getClientExtensionResults();
294
+ if (extensions.credProps){
295
+ if (extensions.credProps.authenticatorDisplayName){
296
+ return extensions.credProps.authenticatorDisplayName;
297
+ }
298
+ }
299
+ var ua = JSHTMLUserAgent.initWithString(navigator.userAgent);
300
+ var apple = ua.containsComment("Macintosh") || ua.containsComment("iPhone") || ua.containsComment("iPad");
301
+ var windows = ua.containsComment("Win64") || ua.containsComment("Windows NT 10.0");
302
+ var linux = ua.containsComment("Linux");
303
+ var android = false;
304
+ if (linux){
305
+ var i, l;
306
+ for (i = 0, l = ua.comments.length; i < l; ++i){
307
+ if (ua.comments[i].startsWith("Android")){
308
+ android = true;
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ if (apple){
314
+ return "iCloud Keychain";
315
+ }
316
+ if (android){
317
+ return "Google Password Manager";
318
+ }
319
+ if (windows){
320
+ return "Windows Hello";
321
+ }
322
+ return "";
323
+ }
323
324
  }
324
- // TODO: jwk.n, jwk.e
325
- return jwk;
325
+ });
326
+
327
+ }
328
+
329
+ if (window.AuthenticatorAttestationResponse){
330
+
331
+ if (!window.AuthenticatorAttestationResponse.prototype.getAuthenticatorData){
332
+ window.AuthenticatorAttestationResponse.prototype.getAuthenticatorData = function AuthenticatorAttestationResponse_getAuthenticatorData(){
333
+ if (this._jskitAuthDataBuffer === undefined){
334
+ var attestationCBOR = JSData.initWithBuffer(this.attestationObject);
335
+ var attestationParser = SECCBORParser.initWithData(attestationCBOR);
336
+ var attestation = attestationParser.parse();
337
+ var data = attestation.authData;
338
+ this._authDataBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.length);
339
+ }
340
+ return this._authDataBuffer;
341
+ };
342
+ }
343
+
344
+ if (!window.AuthenticatorAttestationResponse.prototype.jskitGetCOSE){
345
+ window.AuthenticatorAttestationResponse.prototype.jskitGetCOSE = function jskitGuthenticatorAttestationResponse_getCOSEDictionary(){
346
+ if (this._jskitCOSE === undefined){
347
+ var authData = JSData.initWithBuffer(this.getAuthenticatorData());
348
+ var idLength = (authData[53] << 8) | authData[54];
349
+ var offset = 55 + idLength;
350
+ this._jskitCOSE = SECCOSE.initWithData(authData.subdataInRange(JSRange(offset, authData.length - offset)));
351
+ }
352
+ return this._jskitCOSE;
353
+ };
354
+ }
355
+
356
+ if (!window.AuthenticatorAttestationResponse.prototype.getPublicKeyAlgorithm){
357
+ window.AuthenticatorAttestationResponse.prototype.getPublicKeyAlgorithm = function AuthenticatorAttestationResponse_getPublicKeyAlgorithm(){
358
+ var cose = this.jskitGetCOSE();
359
+ return cose[SECCOSE.Attribute.alg];
360
+ };
361
+ }
362
+
363
+ if (!window.AuthenticatorAttestationResponse.prototype.getPublicKey){
364
+ window.AuthenticatorAttestationResponse.prototype.getPublicKey = function AuthenticatorAttestationResponse_getPublicKey(){
365
+ var cose = this.jskitGetCOSE();
366
+ var derData = cose.derRepresentation();
367
+ return derData.buffer.slice(derData.byteOffset, derData.byteOffset + derData.length);
368
+ };
369
+ }
370
+
371
+ if (!window.AuthenticatorAttestationResponse.prototype.getPublicJWK){
372
+ window.AuthenticatorAttestationResponse.prototype.getPublicJWK = function AuthenticatorAttestationResponse_getPublicJWK(){
373
+ var cose = this.jskitGetCOSE();
374
+ var jwk = cose.jwkRepresentation();
375
+ var authData = JSData.initWithBuffer(this.getAuthenticatorData());
376
+ var idLength = (authData[53] << 8) | authData[54];
377
+ var idData = authData.subdataInRange(JSRange(55, idLength));
378
+ jwk.kid = idData.base64URLStringRepresentation();
379
+ jwk.key_ops = ["verify"];
380
+ return jwk;
381
+ };
382
+ }
383
+
384
+ if (!window.AuthenticatorAttestationResponse.prototype.toJSON){
385
+ window.AuthenticatorAttestationResponse.prototype.toJSON = function AuthenticatorAttestationResponse_toJSON(){
386
+ var attestationObjectData = JSData.initWithBuffer(this.attestationObject);
387
+ var authData = JSData.initWithBuffer(this.getAuthenticatorData());
388
+ var dictionary = {};
389
+ dictionary.clientDataJSON = JSData.initWithBuffer(this.clientDataJSON).base64URLStringRepresentation();
390
+ dictionary.authenticatorData = authData.base64URLStringRepresentation();
391
+ dictionary.transports = this.getTransports ? this.getTransports() : [];
392
+ dictionary.publicKey = JSData.initWithBuffer(this.getPublicKey()).base64URLStringRepresentation();
393
+ dictionary.publicKeyAlgorithm = this.getPublicKeyAlgorithm();
394
+ dictionary.attestationObject = attestationObjectData.base64URLStringRepresentation();
395
+ return dictionary;
396
+ };
326
397
  }
327
- return null;
328
- };
398
+
399
+ }
400
+
401
+ if (window.AuthenticatorAssertionResponse){
402
+
403
+ if (!window.AuthenticatorAssertionResponse.prototype.toJSON){
404
+ window.AuthenticatorAssertionResponse.prototype.toJSON = function AuthenticatorAssertionResponse_toJSON(){
405
+ var dictionary = {};
406
+ dictionary.clientDataJSON = JSData.initWithBuffer(this.clientDataJSON).base64URLStringRepresentation();
407
+ dictionary.authenticatorData = JSData.initWithBuffer(this.authenticatorData).base64URLStringRepresentation();
408
+ dictionary.signature = JSData.initWithBuffer(this.signature).base64URLStringRepresentation();
409
+ dictionary.userHandle = this.userHandle ? JSData.initWithBuffer(this.userHandle).base64URLStringRepresentation() : null;
410
+ return dictionary;
411
+ };
412
+ }
413
+
414
+ }
329
415
 
330
416
  })();
@@ -24,6 +24,7 @@ JSClass("SECHTMLKey", SECKey, {
24
24
 
25
25
  initWithKey: function(htmlKey){
26
26
  this.htmlKey = htmlKey;
27
+ this.type = htmlKey.type;
27
28
  },
28
29
 
29
30
  getData: function(completion, target){
@@ -36,6 +37,22 @@ JSClass("SECHTMLKey", SECKey, {
36
37
  completion.call(target, null);
37
38
  });
38
39
  return completion.promise;
40
+ },
41
+
42
+ getJWK: function(completion, target){
43
+ if (!completion){
44
+ completion = Promise.completion(Promise.resolveNonNull);
45
+ }
46
+ var kid = this.id;
47
+ crypto.subtle.exportKey("jwk", this.htmlKey).then(function(jwk){
48
+ if (kid !== null){
49
+ jwk.kid = kid;
50
+ }
51
+ completion.call(target, jwk);
52
+ }, function(){
53
+ completion.call(target, null);
54
+ });
55
+ return completion.promise;
39
56
  }
40
57
 
41
58
  });
@@ -30,6 +30,7 @@ JSClass("SECHash", JSObject, {
30
30
  });
31
31
 
32
32
  SECHash.Algorithm = {
33
+ sha1: "sha1",
33
34
  sha256: "sha256",
34
35
  sha384: "sha384",
35
36
  sha512: "sha512",
@@ -23,6 +23,7 @@ JSClass("SECJSONWebAlgorithms", JSObject, {
23
23
  SECJSONWebAlgorithms.Algorithm = {
24
24
 
25
25
  none: 'none',
26
+ direct: "dir",
26
27
  hmacSHA256: "HS256",
27
28
  hmacSHA384: "HS384",
28
29
  hmacSHA512: "HS512",
@@ -32,7 +33,14 @@ SECJSONWebAlgorithms.Algorithm = {
32
33
  ellipticCurveSHA256: "ES256",
33
34
  ellipticCurveSHA384: "ES384",
34
35
  ellipticCurveSHA512: "ES512",
35
-
36
+ aesGCM128: "A128GCM",
37
+ aesGCM192: "A192GCM",
38
+ aesGCM256: "A256GCM",
39
+ aesCBC128HS256: "A128CBC-HS256",
40
+ aesCBC192HS384: "A192CBC-HS384",
41
+ aesCBC256HS512: "A256CBC-HS512",
42
+ rsaOAEP: "RSA-OAEP",
43
+ ecdhES: "ECDH-ES"
36
44
  };
37
45
 
38
46
  SECJSONWebAlgorithms.KeyType = {