cassproject 5.0.11 → 5.0.13
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.
- package/README.md +2 -2
- package/package.json +19 -27
- package/src/com/eduworks/ec/crypto/EcAes.js +16 -2
- package/src/com/eduworks/ec/crypto/EcPk.js +25 -11
- package/src/com/eduworks/ec/crypto/EcPpk.js +34 -15
- package/src/org/cass/profile/EcAssertion.js +28 -7
- package/src/org/cassproject/schema/cass/profile/Assertion.js +2 -2
- package/src/test/1.EcCrypto.jwk.test.js +63 -0
package/README.md
CHANGED
|
@@ -46,10 +46,10 @@ Development unit tests presume you have a CaSS Repository running on `localhost:
|
|
|
46
46
|
## Publish checklist
|
|
47
47
|
|
|
48
48
|
* `npm upgrade --save` Review dependencies, autocomplete version numbers to latest versions.
|
|
49
|
-
* Increment version number using `npm version <patch|minor|major>`. This automatically updates `package.json` and `yuidoc.json`.
|
|
49
|
+
* Increment version number using `npm version --no-git-tag-version <patch|minor|major>`. This automatically updates `package.json` and `yuidoc.json`.
|
|
50
50
|
* Update changelog using `npm run changelog`, and review the changes in `CHANGELOG.md`.
|
|
51
51
|
* `npm install`
|
|
52
|
-
* `npm audit` and fix any audit issues.
|
|
52
|
+
* `npm audit` and fix any audit issues. Stop if `npm audit --omit=dev` has findings.
|
|
53
53
|
* Update CaSS server version if necessary in package.json
|
|
54
54
|
* `npm test` - Must not fail any tests.
|
|
55
55
|
* `npm run webpack:cypressFirefoxHttps` See if the firefox test case has changed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cassproject",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.13",
|
|
4
4
|
"description": "Competency and Skills Service",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"multitest": "concurrently --kill-others-on-fail \"npm run test15\" \"npm run test14\" \"npm run test13\" \"npm run test12\"",
|
|
11
11
|
"testCassTest": "npm run testkill && docker run -d --platform linux/amd64 --network cass-net --name cass-test -p80:80 -e CASS_LOOPBACK cass-test && wait-on http://localhost/api/ping && npm run testNode18 && npm run testNode18Fips && npm run testCypressEdge && npm run testCypress && npm run testkill",
|
|
12
12
|
"testDevHttps": "npm run testkill && docker run -d --platform linux/amd64 --network cass-net --name cass-test -p443:80 -e CASS_LOOPBACK -e HTTPS=true cassproject/cass:dev && wait-on https://localhost/api/ping && npm run testNode18HttpsFips && npm run testNode18Https && npm run testCypressEdgeHttps && npm run testCypressHttps",
|
|
13
|
-
"test16HttpsFips": "export CASS_LOOPBACK=https://cass-testsf16/api/|| set CASS_LOOPBACK=https://cass-testsf16/api/&& npm run testkillsf16 && docker run -d --platform linux/amd64 --network cass-net --name cass-testsf16 -p450:443 -e CASS_LOOPBACK -e HTTPS=true cassproject/cass:1.6 && wait-on https://localhost:450/api/ping && concurrently --kill-others-on-fail \"npm run testCypressHttps\" \"npm run testNode24Https\" \"npm run testNode24HttpsFips\" \"npm run testNode24HttpsForceFips\" \"npm run testNode22Https\" \"npm run testNode22HttpsFips\" \"npm run testNode22HttpsForceFips\" \"npm run testNode20Https\" \"npm run testNode20HttpsFips\" \"npm run testNode20HttpsForceFips\" \"npm run testNode18Https\" && npm run testkillsf16",
|
|
13
|
+
"test16HttpsFips": "export CASS_LOOPBACK=https://cass-testsf16/api/|| set CASS_LOOPBACK=https://cass-testsf16/api/&& npm run testkillsf16 && docker run -d --platform linux/amd64 --network cass-net --name cass-testsf16 -p450:443 -e CASS_LOOPBACK -e HTTPS=true --pull always cassproject/cass:1.6 && wait-on https://localhost:450/api/ping && concurrently --kill-others-on-fail \"npm run testCypressHttps\" \"npm run testNode24Https\" \"npm run testNode24HttpsFips\" \"npm run testNode24HttpsForceFips\" \"npm run testNode22Https\" \"npm run testNode22HttpsFips\" \"npm run testNode22HttpsForceFips\" \"npm run testNode20Https\" \"npm run testNode20HttpsFips\" \"npm run testNode20HttpsForceFips\" \"npm run testNode18Https\" && npm run testkillsf16",
|
|
14
14
|
"test16Https11Fips": "export CASS_LOOPBACK=https://cass-testsf1116/api/|| set CASS_LOOPBACK=https://cass-testsf1116/api/&& npm run testkillsf1116 && docker run -d --platform linux/amd64 --network cass-net --name cass-testsf1116 -p449:443 -e CASS_LOOPBACK -e HTTPS=true -e HTTP2=false cassproject/cass:1.6 && wait-on https://localhost:449/api/ping && concurrently --kill-others-on-fail \"npm run testCypressHttps\" \"npm run testNode24Https\" \"npm run testNode24HttpsFips\" \"npm run testNode24HttpsForceFips\" \"npm run testNode22Https\" \"npm run testNode22HttpsFips\" \"npm run testNode22HttpsForceFips\" \"npm run testNode20Https\" \"npm run testNode20HttpsFips\" \"npm run testNode20HttpsForceFips\" \"npm run testNode18Https\" && npm run testkillsf1116",
|
|
15
15
|
"test16Https": "export CASS_LOOPBACK=https://cass-tests16/api/|| set CASS_LOOPBACK=https://cass-tests16/api/&& npm run testkills16 && docker run -d --platform linux/amd64 --network cass-net --name cass-tests16 -p448:443 -e CASS_LOOPBACK -e HTTPS=true cassproject/cass:1.6 && wait-on https://localhost:448/api/ping && concurrently --kill-others-on-fail \"npm run testCypressHttps\" \"npm run testNode24Https\" \"npm run testNode24HttpsFips\" \"npm run testNode22Https\" \"npm run testNode22HttpsFips\" \"npm run testNode20Https\" \"npm run testNode20HttpsFips\" \"npm run testNode18Https\" && npm run testkills16",
|
|
16
16
|
"test16HttpsNoFips": "export CASS_LOOPBACK=https://cass-tests16/api/|| set CASS_LOOPBACK=https://cass-tests16/api/&& npm run testkills16 && docker run -d --platform linux/amd64 --network cass-net --name cass-tests16 -p448:443 -e CASS_LOOPBACK -e HTTPS=true cassproject/cass:1.6 && wait-on https://localhost:448/api/ping && concurrently --kill-others-on-fail \"npm run testCypressHttps\" \"npm run testNode24Https\" \"npm run testNode22Https\" \"npm run testNode20Https\" \"npm run testNode18Https\" && npm run testkills16",
|
|
@@ -82,18 +82,18 @@
|
|
|
82
82
|
"autoindex": "nodemon index.js",
|
|
83
83
|
"autonyc": "nodemon --exec \"npm run nyc\"",
|
|
84
84
|
"nyc": "nyc --reporter lcov npm run mocha",
|
|
85
|
-
"mocha": "mocha --timeout 60000 -b src/**/*.test.js",
|
|
86
|
-
"mochaFips": "mocha -n 'force-fips' --timeout 60000 -b src/**/*.test.js",
|
|
87
|
-
"mocha:httpsNoHttp2": "export HTTP2=false|| set HTTP2=false&& mocha --timeout 60000 -b src/**/*.test.js",
|
|
88
|
-
"mocha:https": "export CASS_LOOPBACK=https://localhost/api/|| set CASS_LOOPBACK=https://localhost/api/&& mocha --timeout 60000 -b src/**/*.test.js",
|
|
89
|
-
"mocha:clientSideCertificates": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha --timeout 60000 -b src/**/*.test.js",
|
|
90
|
-
"mochaFips:clientSideCertificates": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha -n 'force-fips' --timeout 60000 -b src/**/*.test.js",
|
|
91
|
-
"mocha:clientSideCertificatesDangerMouse": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha --timeout 60000 -b src/**/*.test.js",
|
|
92
|
-
"mocha:custom": "export CASS_LOOPBACK=https://tides.eduworks.us/api/|| set CASS_LOOPBACK=https://tides.eduworks.us/api/&& export HTTP2=false|| set HTTP2=false&& mocha --timeout 600000 -b src/**/*.test.js",
|
|
93
|
-
"mocha:dev": "export CASS_LOOPBACK=https://dev.cassproject.org/api/|| set CASS_LOOPBACK=https://dev.cassproject.org/api/&& export HTTP2=false|| set HTTP2=false&& mocha --timeout 600000 -b src/**/*.test.js",
|
|
94
|
-
"mocha:demo": "export CASS_LOOPBACK=https://demo.cassproject.org/api/|| set CASS_LOOPBACK=https://demo.cassproject.org/api/&& export HTTP2=false|| set HTTP2=false&& mocha --timeout 600000 -b src/**/*.test.js",
|
|
95
|
-
"mochaGraph": "mocha --timeout 60000 -b src/com/eduworks/ec/graph/**/*.test.js",
|
|
96
|
-
"mochaCrypto": "mocha --timeout 60000 -b src/test/*Rsa*.test.js -b src/test/*Aes*.test.js -b src/test/*Crypto*.test.js",
|
|
85
|
+
"mocha": "mocha --exit --timeout 60000 -b src/**/*.test.js",
|
|
86
|
+
"mochaFips": "mocha --exit -n 'force-fips' --timeout 60000 -b src/**/*.test.js",
|
|
87
|
+
"mocha:httpsNoHttp2": "export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 60000 -b src/**/*.test.js",
|
|
88
|
+
"mocha:https": "export CASS_LOOPBACK=https://localhost/api/|| set CASS_LOOPBACK=https://localhost/api/&& mocha --exit --timeout 60000 -b src/**/*.test.js",
|
|
89
|
+
"mocha:clientSideCertificates": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 60000 -b src/**/*.test.js",
|
|
90
|
+
"mochaFips:clientSideCertificates": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha --exit -n 'force-fips' --timeout 60000 -b src/**/*.test.js",
|
|
91
|
+
"mocha:clientSideCertificatesDangerMouse": "export NODE_EXTRA_CA_CERTS=ca.crt|| set NODE_EXTRA_CA_CERTS=ca.crt&&export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 60000 -b src/**/*.test.js",
|
|
92
|
+
"mocha:custom": "export CASS_LOOPBACK=https://tides.eduworks.us/api/|| set CASS_LOOPBACK=https://tides.eduworks.us/api/&& export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 600000 -b src/**/*.test.js",
|
|
93
|
+
"mocha:dev": "export CASS_LOOPBACK=https://dev.cassproject.org/api/|| set CASS_LOOPBACK=https://dev.cassproject.org/api/&& export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 600000 -b src/**/*.test.js",
|
|
94
|
+
"mocha:demo": "export CASS_LOOPBACK=https://demo.cassproject.org/api/|| set CASS_LOOPBACK=https://demo.cassproject.org/api/&& export HTTP2=false|| set HTTP2=false&& mocha --exit --timeout 600000 -b src/**/*.test.js",
|
|
95
|
+
"mochaGraph": "mocha --exit --timeout 60000 -b src/com/eduworks/ec/graph/**/*.test.js",
|
|
96
|
+
"mochaCrypto": "mocha --exit --timeout 60000 -b src/test/*Rsa*.test.js -b src/test/*Aes*.test.js -b src/test/*Crypto*.test.js",
|
|
97
97
|
"automocha": "nodemon --exec \"npm run mocha\"",
|
|
98
98
|
"automochaGraph": "nodemon --exec \"npm run mochaGraph\"",
|
|
99
99
|
"automochaCrypto": "nodemon --exec \"npm run mochaCrypto\"",
|
|
@@ -141,13 +141,10 @@
|
|
|
141
141
|
],
|
|
142
142
|
"dependencies": {
|
|
143
143
|
"base64-arraybuffer": "^1.0.2",
|
|
144
|
-
"forge": "^2.3.0",
|
|
145
144
|
"jsonld": "^9.0.0",
|
|
146
|
-
"node-forge": "^1.
|
|
145
|
+
"node-forge": "^1.4.0",
|
|
147
146
|
"papaparse": "^5.5.3",
|
|
148
|
-
"pem-jwk": "^2.0.0",
|
|
149
147
|
"promise-worker": "^2.0.1",
|
|
150
|
-
"rdf-canonize": "^5.0.0",
|
|
151
148
|
"web-worker": "1.3.0"
|
|
152
149
|
},
|
|
153
150
|
"files": [
|
|
@@ -172,25 +169,20 @@
|
|
|
172
169
|
},
|
|
173
170
|
"homepage": "https://github.com/cassproject/cass-npm#readme",
|
|
174
171
|
"devDependencies": {
|
|
175
|
-
"@cypress/browserify-preprocessor": "^3.0.2",
|
|
176
|
-
"@cypress/vite-dev-server": "^7.2.0",
|
|
177
172
|
"@cypress/webpack-preprocessor": "^7.0.2",
|
|
178
173
|
"chai": "^4.5.0",
|
|
179
174
|
"concurrently": "^9.2.1",
|
|
180
|
-
"
|
|
181
|
-
"cypress": "^15.10.0",
|
|
175
|
+
"cypress": "^15.13.0",
|
|
182
176
|
"cypress-fail-fast": "^7.1.1",
|
|
183
|
-
"eslint": "^
|
|
177
|
+
"eslint": "^10.1.0",
|
|
184
178
|
"fake-indexeddb": "^6.2.5",
|
|
185
179
|
"mocha": "^11.7.5",
|
|
186
180
|
"node-polyfill-webpack-plugin": "^4.1.0",
|
|
187
181
|
"nodemon": "^3.1.14",
|
|
188
182
|
"nyc": "^17.1.0",
|
|
189
|
-
"sinon": "^21.0.
|
|
190
|
-
"url-polyfill": "^1.1.14",
|
|
183
|
+
"sinon": "^21.0.3",
|
|
191
184
|
"wait-on": "^9.0.4",
|
|
192
|
-
"webpack": "^5.105.
|
|
193
|
-
"webpack-cli": "^6.0.1"
|
|
185
|
+
"webpack": "^5.105.4"
|
|
194
186
|
},
|
|
195
187
|
"packageManager": "npm@11.3.0+sha512.96eb611483f49c55f7fa74df61b588de9e213f80a256728e6798ddc67176c7b07e4a1cfc7de8922422cbce02543714367037536955221fa451b0c4fefaf20c66"
|
|
196
188
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const forge = require("node-forge");
|
|
2
2
|
const realCrypto = require('crypto');
|
|
3
|
+
const base64 = require("base64-arraybuffer");
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* AES encryption tasks common across all variants of AES.
|
|
5
7
|
* @class EcAes
|
|
@@ -16,7 +18,13 @@ module.exports = class EcAes {
|
|
|
16
18
|
*/
|
|
17
19
|
static newSecret = function(i) {
|
|
18
20
|
if (i == null) throw new Error("Undefined secret length.");
|
|
19
|
-
|
|
21
|
+
let array = new Uint8Array(i);
|
|
22
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
23
|
+
crypto.getRandomValues(array);
|
|
24
|
+
} else {
|
|
25
|
+
realCrypto.webcrypto.getRandomValues(array);
|
|
26
|
+
}
|
|
27
|
+
return base64.encode(array.buffer);
|
|
20
28
|
};
|
|
21
29
|
/**
|
|
22
30
|
* Generates a random Initialization Vector of length @i
|
|
@@ -27,6 +35,12 @@ module.exports = class EcAes {
|
|
|
27
35
|
*/
|
|
28
36
|
static newIv = function(i) {
|
|
29
37
|
if (i == null) throw new Error("Undefined iv length.");
|
|
30
|
-
|
|
38
|
+
let array = new Uint8Array(i);
|
|
39
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
40
|
+
crypto.getRandomValues(array);
|
|
41
|
+
} else {
|
|
42
|
+
realCrypto.webcrypto.getRandomValues(array);
|
|
43
|
+
}
|
|
44
|
+
return base64.encode(array.buffer);
|
|
31
45
|
};
|
|
32
46
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
let forge = require("node-forge");
|
|
3
3
|
/**
|
|
4
4
|
* Helper classes for dealing with RSA Public Keys.
|
|
@@ -25,7 +25,7 @@ module.exports = class EcPk {
|
|
|
25
25
|
*/
|
|
26
26
|
static fromPem(pem) {
|
|
27
27
|
let pk = EcPk.cache[pem];
|
|
28
|
-
if (pk != null)
|
|
28
|
+
if (pk != null)
|
|
29
29
|
return pk;
|
|
30
30
|
pk = new EcPk();
|
|
31
31
|
try {
|
|
@@ -69,11 +69,11 @@ module.exports = class EcPk {
|
|
|
69
69
|
* @return {string} PEM encoded public key without whitespace.
|
|
70
70
|
* @method toPkcs1Pem
|
|
71
71
|
*/
|
|
72
|
-
toPkcs1Pem = function() {
|
|
72
|
+
toPkcs1Pem = function () {
|
|
73
73
|
return forge.pki
|
|
74
74
|
.publicKeyToRSAPublicKeyPem(this.pk)
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
.replace(/\r/g, "")
|
|
76
|
+
.replace(/\n/g, "");
|
|
77
77
|
};
|
|
78
78
|
/**
|
|
79
79
|
* Encodes the public key into a PEM encoded SubjectPublicKeyInfo (PKCS#8) formatted RSA Public Key.
|
|
@@ -82,16 +82,30 @@ module.exports = class EcPk {
|
|
|
82
82
|
* @return {string} PEM encoded public key without whitespace.
|
|
83
83
|
* @method toPkcs8Pem
|
|
84
84
|
*/
|
|
85
|
-
toPkcs8Pem = function() {
|
|
85
|
+
toPkcs8Pem = function () {
|
|
86
86
|
return forge.pki
|
|
87
87
|
.publicKeyToPem(this.pk)
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
.replace(/\r/g, "")
|
|
89
|
+
.replace(/\n/g, "");
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
toJwk() {
|
|
93
|
-
if (this.jwk == null)
|
|
94
|
-
|
|
93
|
+
if (this.jwk == null) {
|
|
94
|
+
const bnToBase64Url = (bn) => {
|
|
95
|
+
let hex = bn.toString(16);
|
|
96
|
+
if (hex.length % 2 !== 0) {
|
|
97
|
+
hex = '0' + hex;
|
|
98
|
+
}
|
|
99
|
+
const bytes = forge.util.hexToBytes(hex);
|
|
100
|
+
const b64 = forge.util.encode64(bytes);
|
|
101
|
+
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
102
|
+
};
|
|
103
|
+
this.jwk = {
|
|
104
|
+
kty: "RSA",
|
|
105
|
+
n: bnToBase64Url(this.pk.n),
|
|
106
|
+
e: bnToBase64Url(this.pk.e)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
95
109
|
return this.jwk;
|
|
96
110
|
}
|
|
97
111
|
/**
|
|
@@ -101,7 +115,7 @@ module.exports = class EcPk {
|
|
|
101
115
|
* @method fingerprint
|
|
102
116
|
*/
|
|
103
117
|
fingerprint() {
|
|
104
|
-
return forge.ssh.getPublicKeyFingerprint(this.pk, {encoding:"hex"});
|
|
118
|
+
return forge.ssh.getPublicKeyFingerprint(this.pk, { encoding: "hex" });
|
|
105
119
|
}
|
|
106
120
|
verify(bytes, decode64) {
|
|
107
121
|
return this.pk.verify(bytes, decode64);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
let forge = require("node-forge");
|
|
3
3
|
let EcPk = require("./EcPk.js");
|
|
4
4
|
require("../../../../org/cassproject/general/AuditLogger.js");
|
|
@@ -48,8 +48,8 @@ module.exports = class EcPpk {
|
|
|
48
48
|
* @static
|
|
49
49
|
*/
|
|
50
50
|
static generateKeyAsync(callback) {
|
|
51
|
-
return new Promise((resolve,reject)=>{
|
|
52
|
-
forge.pki.rsa.generateKeyPair({workers
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
forge.pki.rsa.generateKeyPair({ workers: -1 }, function (err, keypair) {
|
|
53
53
|
let ppk = new EcPpk();
|
|
54
54
|
ppk.ppk = keypair.privateKey;
|
|
55
55
|
if (callback != null)
|
|
@@ -66,7 +66,7 @@ module.exports = class EcPpk {
|
|
|
66
66
|
* @static
|
|
67
67
|
*/
|
|
68
68
|
static generateKey() {
|
|
69
|
-
let keypair = forge.pki.rsa.generateKeyPair({workers
|
|
69
|
+
let keypair = forge.pki.rsa.generateKeyPair({ workers: -1 }, null);
|
|
70
70
|
let ppk = new EcPpk();
|
|
71
71
|
ppk.ppk = keypair.privateKey;
|
|
72
72
|
return ppk;
|
|
@@ -108,11 +108,11 @@ module.exports = class EcPpk {
|
|
|
108
108
|
* @return {string} PEM encoded public key without whitespace.
|
|
109
109
|
* @method toPkcs1Pem
|
|
110
110
|
*/
|
|
111
|
-
toPkcs1Pem = function() {
|
|
111
|
+
toPkcs1Pem = function () {
|
|
112
112
|
return forge.pki
|
|
113
113
|
.privateKeyToPem(this.ppk)
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
.replace(/\r/g, "")
|
|
115
|
+
.replace(/\n/g, "");
|
|
116
116
|
};
|
|
117
117
|
/**
|
|
118
118
|
* Encodes the private key into a PEM encoded PrivateKeyInfo (PKCS#8) formatted RSA Public Key.
|
|
@@ -121,22 +121,42 @@ module.exports = class EcPpk {
|
|
|
121
121
|
* @return {string} PEM encoded public key without whitespace.
|
|
122
122
|
* @method toPkcs8Pem
|
|
123
123
|
*/
|
|
124
|
-
toPkcs8Pem = function() {
|
|
124
|
+
toPkcs8Pem = function () {
|
|
125
125
|
return forge.pki
|
|
126
126
|
.privateKeyInfoToPem(
|
|
127
127
|
forge.pki.wrapRsaPrivateKey(
|
|
128
128
|
forge.pki.privateKeyToAsn1(this.ppk)
|
|
129
129
|
)
|
|
130
130
|
)
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
.replace(/\r/g, "")
|
|
132
|
+
.replace(/\n/g, "");
|
|
133
133
|
};
|
|
134
134
|
toJwk() {
|
|
135
|
-
if (this.jwk == null)
|
|
136
|
-
|
|
135
|
+
if (this.jwk == null) {
|
|
136
|
+
const bnToBase64Url = (bn) => {
|
|
137
|
+
let hex = bn.toString(16);
|
|
138
|
+
if (hex.length % 2 !== 0) {
|
|
139
|
+
hex = '0' + hex;
|
|
140
|
+
}
|
|
141
|
+
const bytes = forge.util.hexToBytes(hex);
|
|
142
|
+
const b64 = forge.util.encode64(bytes);
|
|
143
|
+
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
144
|
+
};
|
|
145
|
+
this.jwk = {
|
|
146
|
+
kty: "RSA",
|
|
147
|
+
n: bnToBase64Url(this.ppk.n),
|
|
148
|
+
e: bnToBase64Url(this.ppk.e),
|
|
149
|
+
d: bnToBase64Url(this.ppk.d),
|
|
150
|
+
p: bnToBase64Url(this.ppk.p),
|
|
151
|
+
q: bnToBase64Url(this.ppk.q),
|
|
152
|
+
dp: bnToBase64Url(this.ppk.dP),
|
|
153
|
+
dq: bnToBase64Url(this.ppk.dQ),
|
|
154
|
+
qi: bnToBase64Url(this.ppk.qInv)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
137
157
|
return this.jwk;
|
|
138
158
|
}
|
|
139
|
-
toPkcs8 = function() {
|
|
159
|
+
toPkcs8 = function () {
|
|
140
160
|
return forge.pki.wrapRsaPrivateKey(
|
|
141
161
|
forge.pki.privateKeyToAsn1(this.ppk)
|
|
142
162
|
);
|
|
@@ -162,8 +182,7 @@ module.exports = class EcPpk {
|
|
|
162
182
|
*/
|
|
163
183
|
inArray(ppks) {
|
|
164
184
|
for (let ppk of ppks) {
|
|
165
|
-
if (ppk.equals(this))
|
|
166
|
-
{
|
|
185
|
+
if (ppk.equals(this)) {
|
|
167
186
|
return true;
|
|
168
187
|
}
|
|
169
188
|
}
|
|
@@ -19,13 +19,34 @@ module.exports = class EcAssertion extends Assertion {
|
|
|
19
19
|
async decrypt(eim) {
|
|
20
20
|
eim = eim || EcIdentityManager.default;
|
|
21
21
|
let a = new Assertion().copyFrom(this);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
let subject = this.getSubject(eim);
|
|
23
|
+
let agent = this.getAgent(eim);
|
|
24
|
+
let assertionDate = this.getAssertionDate(eim);
|
|
25
|
+
let expirationDate = this.getExpirationDate(eim);
|
|
26
|
+
let evidences = this.getEvidences(eim);
|
|
27
|
+
let negative = this.getNegative(eim);
|
|
28
|
+
let decayFunction = this.getDecayFunction(eim);
|
|
29
|
+
subject = await subject;
|
|
30
|
+
agent = await agent;
|
|
31
|
+
assertionDate = await assertionDate;
|
|
32
|
+
expirationDate = await expirationDate;
|
|
33
|
+
evidences = await evidences;
|
|
34
|
+
negative = await negative;
|
|
35
|
+
decayFunction = await decayFunction;
|
|
36
|
+
if (subject)
|
|
37
|
+
a.setSubject(subject);
|
|
38
|
+
if (agent)
|
|
39
|
+
a.setAgent(agent);
|
|
40
|
+
if (assertionDate)
|
|
41
|
+
a.setAssertionDate(assertionDate);
|
|
42
|
+
if (expirationDate)
|
|
43
|
+
a.setExpirationDate(expirationDate);
|
|
44
|
+
if (evidences)
|
|
45
|
+
a.setEvidence(evidences);
|
|
46
|
+
if (negative)
|
|
47
|
+
a.setNegative(negative);
|
|
48
|
+
if (decayFunction)
|
|
49
|
+
a.setDecayFunction(decayFunction);
|
|
29
50
|
a.setCompetency(this.competency);
|
|
30
51
|
a.setLevel(this.level);
|
|
31
52
|
a.setConfidence(this.confidence);
|
|
@@ -246,13 +246,13 @@ module.exports = class Assertion extends schema.CreativeWork {
|
|
|
246
246
|
success(this.decayFunction);
|
|
247
247
|
}
|
|
248
248
|
getNegative() {
|
|
249
|
-
return "true".equals(this.negative);
|
|
249
|
+
return "true".equals(this.negative) | this.negative === true;
|
|
250
250
|
}
|
|
251
251
|
setNegative(negativeB) {
|
|
252
252
|
this.negative = negativeB;
|
|
253
253
|
}
|
|
254
254
|
getNegativeAsync(success, failure) {
|
|
255
|
-
success("true".equals(this.negative));
|
|
255
|
+
success("true".equals(this.negative) | this.negative === true);
|
|
256
256
|
}
|
|
257
257
|
setCompetency(competencyUrl) {
|
|
258
258
|
this.competency = competencyUrl;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
let EcPpk = require("../com/eduworks/ec/crypto/EcPpk.js");
|
|
2
|
+
let EcRsaOaepAsync = require("../com/eduworks/ec/crypto/EcRsaOaepAsync.js");
|
|
3
|
+
let EcRsaOaep = require("../com/eduworks/ec/crypto/EcRsaOaep.js");
|
|
4
|
+
let EcAes = require("../com/eduworks/ec/crypto/EcAes.js");
|
|
5
|
+
let chai = require("chai");
|
|
6
|
+
|
|
7
|
+
let assert = chai.assert;
|
|
8
|
+
|
|
9
|
+
describe("EcCrypto JWK", () => {
|
|
10
|
+
let ppk = null;
|
|
11
|
+
let pk = null;
|
|
12
|
+
|
|
13
|
+
before(async function () {
|
|
14
|
+
this.timeout(10000);
|
|
15
|
+
ppk = await EcPpk.generateKeyAsync();
|
|
16
|
+
pk = ppk.toPk();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('EcPpk.toJwk is valid', () => {
|
|
20
|
+
let jwk = ppk.toJwk();
|
|
21
|
+
assert.isNotNull(jwk);
|
|
22
|
+
assert.isObject(jwk);
|
|
23
|
+
assert.equal(jwk.kty, "RSA");
|
|
24
|
+
assert.isString(jwk.n);
|
|
25
|
+
assert.isString(jwk.e);
|
|
26
|
+
assert.isString(jwk.d);
|
|
27
|
+
assert.isString(jwk.p);
|
|
28
|
+
assert.isString(jwk.q);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('EcPk.toJwk is valid', () => {
|
|
32
|
+
let jwk = pk.toJwk();
|
|
33
|
+
assert.isNotNull(jwk);
|
|
34
|
+
assert.isObject(jwk);
|
|
35
|
+
assert.equal(jwk.kty, "RSA");
|
|
36
|
+
assert.isString(jwk.n);
|
|
37
|
+
assert.isString(jwk.e);
|
|
38
|
+
assert.isUndefined(jwk.d);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('EcRsaOaepAsync.encrypt/decrypt works with generated JWK', async () => {
|
|
42
|
+
let randomString = EcAes.newIv(256).substring(0, 190);
|
|
43
|
+
|
|
44
|
+
// The verify functions in EcRsaOaepAsync automatically use toJwk()
|
|
45
|
+
// behind the scenes when ppk.key is null, so by passing our newly
|
|
46
|
+
// generated keys, we are implicitly testing that the JWK format generated
|
|
47
|
+
// by `.toJwk()` is perfectly valid for use with crypto.subtle.
|
|
48
|
+
|
|
49
|
+
let encrypted = await EcRsaOaepAsync.encrypt(pk, randomString);
|
|
50
|
+
let decrypted = await EcRsaOaep.decrypt(ppk, encrypted);
|
|
51
|
+
|
|
52
|
+
assert.isTrue(randomString === decrypted, "Decrypted string should match original");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('EcRsaOaepAsync.signSha256/verifySha256 works with generated JWK', async () => {
|
|
56
|
+
let randomString = EcAes.newIv(256 * 4);
|
|
57
|
+
|
|
58
|
+
let signature = await EcRsaOaepAsync.signSha256(ppk, randomString);
|
|
59
|
+
let verified = await EcRsaOaep.verifySha256(pk, randomString, signature);
|
|
60
|
+
|
|
61
|
+
assert.isTrue(verified, "Signature should be successfully verified");
|
|
62
|
+
});
|
|
63
|
+
});
|