@microsoft/ccf-app 3.0.0-dev6 → 3.0.0-rc1
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/consensus.d.ts +3 -3
- package/consensus.js +3 -3
- package/crypto.d.ts +35 -11
- package/crypto.js +39 -15
- package/endpoints.d.ts +2 -2
- package/endpoints.js +2 -2
- package/global.d.ts +167 -43
- package/historical.d.ts +2 -2
- package/historical.js +2 -2
- package/openenclave.d.ts +1 -1
- package/openenclave.js +1 -1
- package/package.json +3 -1
- package/polyfill.js +239 -130
package/consensus.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @inheritDoc CCFConsensus.getLastCommittedTxId
|
|
2
|
+
* @inheritDoc global!CCFConsensus.getLastCommittedTxId
|
|
3
3
|
*/
|
|
4
4
|
export declare const getLastCommittedTxId: () => import("./global.js").TransactionId;
|
|
5
5
|
/**
|
|
6
|
-
* @inheritDoc CCFConsensus.getStatusForTxId
|
|
6
|
+
* @inheritDoc global!CCFConsensus.getStatusForTxId
|
|
7
7
|
*/
|
|
8
8
|
export declare const getStatusForTxId: (view: number, seqno: number) => import("./global.js").TransactionStatus;
|
|
9
9
|
/**
|
|
10
|
-
* @inheritDoc CCFConsensus.getViewForSeqno
|
|
10
|
+
* @inheritDoc global!CCFConsensus.getViewForSeqno
|
|
11
11
|
*/
|
|
12
12
|
export declare const getViewForSeqno: (seqno: number) => number | null;
|
|
13
13
|
export { TransactionStatus } from "./global";
|
package/consensus.js
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { ccf } from "./global.js";
|
|
10
10
|
/**
|
|
11
|
-
* @inheritDoc CCFConsensus.getLastCommittedTxId
|
|
11
|
+
* @inheritDoc global!CCFConsensus.getLastCommittedTxId
|
|
12
12
|
*/
|
|
13
13
|
export const getLastCommittedTxId = ccf.consensus.getLastCommittedTxId.bind(ccf.consensus);
|
|
14
14
|
/**
|
|
15
|
-
* @inheritDoc CCFConsensus.getStatusForTxId
|
|
15
|
+
* @inheritDoc global!CCFConsensus.getStatusForTxId
|
|
16
16
|
*/
|
|
17
17
|
export const getStatusForTxId = ccf.consensus.getStatusForTxId.bind(ccf.consensus);
|
|
18
18
|
/**
|
|
19
|
-
* @inheritDoc CCFConsensus.getViewForSeqno
|
|
19
|
+
* @inheritDoc global!CCFConsensus.getViewForSeqno
|
|
20
20
|
*/
|
|
21
21
|
export const getViewForSeqno = ccf.consensus.getViewForSeqno.bind(ccf.consensus);
|
package/crypto.d.ts
CHANGED
|
@@ -1,33 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @inheritDoc CCF.generateAesKey
|
|
2
|
+
* @inheritDoc global!CCF.generateAesKey
|
|
3
3
|
*/
|
|
4
4
|
export declare const generateAesKey: (size: number) => ArrayBuffer;
|
|
5
5
|
/**
|
|
6
|
-
* @inheritDoc CCF.generateRsaKeyPair
|
|
6
|
+
* @inheritDoc global!CCF.generateRsaKeyPair
|
|
7
7
|
*/
|
|
8
8
|
export declare const generateRsaKeyPair: (size: number, exponent?: number | undefined) => import("./global.js").CryptoKeyPair;
|
|
9
9
|
/**
|
|
10
|
-
* @inheritDoc CCF.generateEcdsaKeyPair
|
|
10
|
+
* @inheritDoc global!CCF.generateEcdsaKeyPair
|
|
11
11
|
*/
|
|
12
12
|
export declare const generateEcdsaKeyPair: (curve: string) => import("./global.js").CryptoKeyPair;
|
|
13
13
|
/**
|
|
14
|
-
* @inheritDoc CCF.
|
|
14
|
+
* @inheritDoc global!CCF.generateEcdsaKeyPair
|
|
15
|
+
*/
|
|
16
|
+
export declare const generateEddsaKeyPair: (curve: string) => import("./global.js").CryptoKeyPair;
|
|
17
|
+
/**
|
|
18
|
+
* @inheritDoc global!CCF.wrapKey
|
|
15
19
|
*/
|
|
16
20
|
export declare const wrapKey: (key: ArrayBuffer, wrappingKey: ArrayBuffer, wrapAlgo: import("./global.js").WrapAlgoParams) => ArrayBuffer;
|
|
17
21
|
/**
|
|
18
|
-
* @inheritDoc CCFCrypto.verifySignature
|
|
22
|
+
* @inheritDoc global!CCFCrypto.verifySignature
|
|
23
|
+
*/
|
|
24
|
+
export declare const sign: (algorithm: import("./global.js").SigningAlgorithm, key: string, plaintext: ArrayBuffer) => ArrayBuffer;
|
|
25
|
+
/**
|
|
26
|
+
* @inheritDoc global!CCFCrypto.verifySignature
|
|
19
27
|
*/
|
|
20
|
-
export declare const verifySignature: (algorithm: import("./global.js").SigningAlgorithm, key: string, signature: ArrayBuffer,
|
|
28
|
+
export declare const verifySignature: (algorithm: import("./global.js").SigningAlgorithm, key: string, signature: ArrayBuffer, plaintext: ArrayBuffer) => boolean;
|
|
21
29
|
/**
|
|
22
|
-
* @inheritDoc
|
|
30
|
+
* @inheritDoc global!CCFCrypto.digest
|
|
23
31
|
*/
|
|
24
|
-
export declare const digest: (algorithm: "SHA-256",
|
|
32
|
+
export declare const digest: (algorithm: "SHA-256", plaintext: ArrayBuffer) => ArrayBuffer;
|
|
25
33
|
/**
|
|
26
|
-
* @inheritDoc
|
|
34
|
+
* @inheritDoc global!CCFCrypto.isValidX509CertBundle
|
|
27
35
|
*/
|
|
28
36
|
export declare const isValidX509CertBundle: (pem: string) => boolean;
|
|
29
37
|
/**
|
|
30
|
-
* @inheritDoc
|
|
38
|
+
* @inheritDoc global!CCFCrypto.isValidX509CertChain
|
|
31
39
|
*/
|
|
32
40
|
export declare const isValidX509CertChain: (chain: string, trusted: string) => boolean;
|
|
33
|
-
|
|
41
|
+
/**
|
|
42
|
+
* @inheritDoc global!CCFCrypto.pubPemToJwk
|
|
43
|
+
*/
|
|
44
|
+
export declare const pubPemToJwk: (pem: string, kid?: string | undefined) => import("./global.js").JsonWebKeyECPublic;
|
|
45
|
+
/**
|
|
46
|
+
* @inheritDoc global!CCFCrypto.pemToJwk
|
|
47
|
+
*/
|
|
48
|
+
export declare const pemToJwk: (pem: string, kid?: string | undefined) => import("./global.js").JsonWebKeyECPrivate;
|
|
49
|
+
/**
|
|
50
|
+
* @inheritDoc global!CCFCrypto.pubRsaPemToJwk
|
|
51
|
+
*/
|
|
52
|
+
export declare const pubRsaPemToJwk: (pem: string, kid?: string | undefined) => import("./global.js").JsonWebKeyRSAPublic;
|
|
53
|
+
/**
|
|
54
|
+
* @inheritDoc global!CCFCrypto.rsaPemToJwk
|
|
55
|
+
*/
|
|
56
|
+
export declare const rsaPemToJwk: (pem: string, kid?: string | undefined) => import("./global.js").JsonWebKeyRSAPrivate;
|
|
57
|
+
export { WrapAlgoParams, AesKwpParams, RsaOaepParams, RsaOaepAesKwpParams, CryptoKeyPair, DigestAlgorithm, SigningAlgorithm, } from "./global";
|
package/crypto.js
CHANGED
|
@@ -15,34 +15,58 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { ccf } from "./global.js";
|
|
17
17
|
/**
|
|
18
|
-
* @inheritDoc CCF.generateAesKey
|
|
18
|
+
* @inheritDoc global!CCF.generateAesKey
|
|
19
19
|
*/
|
|
20
|
-
export const generateAesKey = ccf.generateAesKey;
|
|
20
|
+
export const generateAesKey = ccf.crypto.generateAesKey;
|
|
21
21
|
/**
|
|
22
|
-
* @inheritDoc CCF.generateRsaKeyPair
|
|
22
|
+
* @inheritDoc global!CCF.generateRsaKeyPair
|
|
23
23
|
*/
|
|
24
|
-
export const generateRsaKeyPair = ccf.generateRsaKeyPair;
|
|
24
|
+
export const generateRsaKeyPair = ccf.crypto.generateRsaKeyPair;
|
|
25
25
|
/**
|
|
26
|
-
* @inheritDoc CCF.generateEcdsaKeyPair
|
|
26
|
+
* @inheritDoc global!CCF.generateEcdsaKeyPair
|
|
27
27
|
*/
|
|
28
|
-
export const generateEcdsaKeyPair = ccf.generateEcdsaKeyPair;
|
|
28
|
+
export const generateEcdsaKeyPair = ccf.crypto.generateEcdsaKeyPair;
|
|
29
29
|
/**
|
|
30
|
-
* @inheritDoc CCF.
|
|
30
|
+
* @inheritDoc global!CCF.generateEcdsaKeyPair
|
|
31
31
|
*/
|
|
32
|
-
export const
|
|
32
|
+
export const generateEddsaKeyPair = ccf.crypto.generateEddsaKeyPair;
|
|
33
33
|
/**
|
|
34
|
-
* @inheritDoc
|
|
34
|
+
* @inheritDoc global!CCF.wrapKey
|
|
35
|
+
*/
|
|
36
|
+
export const wrapKey = ccf.crypto.wrapKey;
|
|
37
|
+
/**
|
|
38
|
+
* @inheritDoc global!CCFCrypto.verifySignature
|
|
39
|
+
*/
|
|
40
|
+
export const sign = ccf.crypto.sign;
|
|
41
|
+
/**
|
|
42
|
+
* @inheritDoc global!CCFCrypto.verifySignature
|
|
35
43
|
*/
|
|
36
44
|
export const verifySignature = ccf.crypto.verifySignature;
|
|
37
45
|
/**
|
|
38
|
-
* @inheritDoc
|
|
46
|
+
* @inheritDoc global!CCFCrypto.digest
|
|
47
|
+
*/
|
|
48
|
+
export const digest = ccf.crypto.digest;
|
|
49
|
+
/**
|
|
50
|
+
* @inheritDoc global!CCFCrypto.isValidX509CertBundle
|
|
51
|
+
*/
|
|
52
|
+
export const isValidX509CertBundle = ccf.crypto.isValidX509CertBundle;
|
|
53
|
+
/**
|
|
54
|
+
* @inheritDoc global!CCFCrypto.isValidX509CertChain
|
|
55
|
+
*/
|
|
56
|
+
export const isValidX509CertChain = ccf.crypto.isValidX509CertChain;
|
|
57
|
+
/**
|
|
58
|
+
* @inheritDoc global!CCFCrypto.pubPemToJwk
|
|
59
|
+
*/
|
|
60
|
+
export const pubPemToJwk = ccf.crypto.pubPemToJwk;
|
|
61
|
+
/**
|
|
62
|
+
* @inheritDoc global!CCFCrypto.pemToJwk
|
|
39
63
|
*/
|
|
40
|
-
export const
|
|
64
|
+
export const pemToJwk = ccf.crypto.pemToJwk;
|
|
41
65
|
/**
|
|
42
|
-
* @inheritDoc
|
|
66
|
+
* @inheritDoc global!CCFCrypto.pubRsaPemToJwk
|
|
43
67
|
*/
|
|
44
|
-
export const
|
|
68
|
+
export const pubRsaPemToJwk = ccf.crypto.pubRsaPemToJwk;
|
|
45
69
|
/**
|
|
46
|
-
* @inheritDoc
|
|
70
|
+
* @inheritDoc global!CCFCrypto.rsaPemToJwk
|
|
47
71
|
*/
|
|
48
|
-
export const
|
|
72
|
+
export const rsaPemToJwk = ccf.crypto.rsaPemToJwk;
|
package/endpoints.d.ts
CHANGED
|
@@ -221,11 +221,11 @@ export interface Response<T extends ResponseBodyType<T> = any> {
|
|
|
221
221
|
*/
|
|
222
222
|
export declare type EndpointFn<A extends JsonCompatible<A> = any, B extends ResponseBodyType<B> = any> = (request: Request<A>) => Response<B>;
|
|
223
223
|
/**
|
|
224
|
-
* @inheritDoc
|
|
224
|
+
* @inheritDoc global!CCFRpc.setApplyWrites
|
|
225
225
|
*/
|
|
226
226
|
export declare const setApplyWrites: (force: boolean) => void;
|
|
227
227
|
/**
|
|
228
|
-
* @inheritDoc
|
|
228
|
+
* @inheritDoc global!CCFRpc.setClaimsDigest
|
|
229
229
|
*/
|
|
230
230
|
export declare const setClaimsDigest: (digest: ArrayBuffer) => void;
|
|
231
231
|
export {};
|
package/endpoints.js
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { ccf } from "./global.js";
|
|
10
10
|
/**
|
|
11
|
-
* @inheritDoc
|
|
11
|
+
* @inheritDoc global!CCFRpc.setApplyWrites
|
|
12
12
|
*/
|
|
13
13
|
export const setApplyWrites = ccf.rpc.setApplyWrites.bind(ccf.rpc);
|
|
14
14
|
/**
|
|
15
|
-
* @inheritDoc
|
|
15
|
+
* @inheritDoc global!CCFRpc.setClaimsDigest
|
|
16
16
|
*/
|
|
17
17
|
export const setClaimsDigest = ccf.rpc.setClaimsDigest.bind(ccf.rpc);
|
package/global.d.ts
CHANGED
|
@@ -164,47 +164,179 @@ export interface RsaOaepAesKwpParams {
|
|
|
164
164
|
export declare type WrapAlgoParams = RsaOaepParams | AesKwpParams | RsaOaepAesKwpParams;
|
|
165
165
|
export interface CryptoKeyPair {
|
|
166
166
|
/**
|
|
167
|
-
*
|
|
167
|
+
* Private key in PEM encoding.
|
|
168
168
|
*/
|
|
169
169
|
privateKey: string;
|
|
170
170
|
/**
|
|
171
|
-
*
|
|
171
|
+
* Public key in PEM encoding.
|
|
172
172
|
*/
|
|
173
173
|
publicKey: string;
|
|
174
174
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
export declare type AlgorithmName = "RSASSA-PKCS1-v1_5" | "ECDSA" | "EdDSA";
|
|
176
|
+
export declare type DigestAlgorithm = "SHA-256";
|
|
177
|
+
export interface SigningAlgorithm {
|
|
178
|
+
name: AlgorithmName;
|
|
179
|
+
/**
|
|
180
|
+
* Digest algorithm. It's necessary for "RSASSA-PKCS1-v1_5" and "ECDSA"
|
|
181
|
+
*/
|
|
182
|
+
hash?: DigestAlgorithm;
|
|
181
183
|
}
|
|
182
184
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* Note: ECDSA signatures are assumed to be encoded according
|
|
186
|
-
* to the Web Crypto API specification, which is the same
|
|
187
|
-
* format used in JSON Web Tokens and more generally known
|
|
188
|
-
* as IEEE P1363 encoding.
|
|
185
|
+
* Interfaces for JSON Web Key objects, as per [RFC7517](https://www.rfc-editor.org/rfc/rfc751).
|
|
189
186
|
*/
|
|
190
|
-
export interface
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
export interface JsonWebKey {
|
|
188
|
+
/**
|
|
189
|
+
* Key type.
|
|
190
|
+
*/
|
|
191
|
+
kty: string;
|
|
192
|
+
/**
|
|
193
|
+
* Key ID.
|
|
194
|
+
*/
|
|
195
|
+
kid?: string;
|
|
196
|
+
}
|
|
197
|
+
export interface JsonWebKeyECPublic extends JsonWebKey {
|
|
198
|
+
/**
|
|
199
|
+
* Elliptic curve identifier.
|
|
200
|
+
*/
|
|
201
|
+
crv: string;
|
|
202
|
+
/**
|
|
203
|
+
* Base64url-encoded x coordinate.
|
|
204
|
+
*/
|
|
205
|
+
x: string;
|
|
206
|
+
/**
|
|
207
|
+
* Base64url-encoded y coordinate.
|
|
208
|
+
*/
|
|
209
|
+
y: string;
|
|
210
|
+
}
|
|
211
|
+
export interface JsonWebKeyECPrivate extends JsonWebKeyECPublic {
|
|
212
|
+
/**
|
|
213
|
+
* Base64url-encoded d coordinate.
|
|
214
|
+
*/
|
|
215
|
+
d: string;
|
|
216
|
+
}
|
|
217
|
+
export interface JsonWebKeyRSAPublic extends JsonWebKey {
|
|
218
|
+
/**
|
|
219
|
+
* Base64url-encoded modulus.
|
|
220
|
+
*/
|
|
221
|
+
n: string;
|
|
222
|
+
/**
|
|
223
|
+
* Base64url-encoded exponent.
|
|
224
|
+
*/
|
|
225
|
+
e: string;
|
|
226
|
+
}
|
|
227
|
+
export interface JsonWebKeyRSAPrivate extends JsonWebKeyRSAPublic {
|
|
228
|
+
/**
|
|
229
|
+
* Private exponent.
|
|
230
|
+
*/
|
|
231
|
+
d: string;
|
|
232
|
+
/**
|
|
233
|
+
* Additional exponents.
|
|
234
|
+
*/
|
|
235
|
+
p: string;
|
|
236
|
+
q: string;
|
|
237
|
+
dp: string;
|
|
238
|
+
dq: string;
|
|
239
|
+
qi: string;
|
|
193
240
|
}
|
|
194
|
-
export declare type SigningAlgorithm = RsaPkcsParams | EcdsaParams;
|
|
195
|
-
export declare type DigestAlgorithm = "SHA-256";
|
|
196
241
|
export interface CCFCrypto {
|
|
242
|
+
/**
|
|
243
|
+
* Generate a signature.
|
|
244
|
+
*
|
|
245
|
+
* @param algorithm Signing algorithm and parameters
|
|
246
|
+
* @param key A PEM-encoded private key
|
|
247
|
+
* @param plaintext Input data that will be signed
|
|
248
|
+
* @throws Will throw an error if the key is not compatible with the
|
|
249
|
+
* signing algorithm or if an unknown algorithm is used.
|
|
250
|
+
*/
|
|
251
|
+
sign(algorithm: SigningAlgorithm, key: string, plaintext: ArrayBuffer): ArrayBuffer;
|
|
197
252
|
/**
|
|
198
253
|
* Returns whether digital signature is valid.
|
|
199
254
|
*
|
|
200
255
|
* @param algorithm Signing algorithm and parameters
|
|
201
256
|
* @param key A PEM-encoded public key or X.509 certificate
|
|
202
257
|
* @param signature Signature to verify
|
|
203
|
-
* @param data
|
|
258
|
+
* @param plaintext Input data that was signed
|
|
204
259
|
* @throws Will throw an error if the key is not compatible with the
|
|
205
260
|
* signing algorithm or if an unknown algorithm is used.
|
|
206
261
|
*/
|
|
207
|
-
verifySignature(algorithm: SigningAlgorithm, key: string, signature: ArrayBuffer,
|
|
262
|
+
verifySignature(algorithm: SigningAlgorithm, key: string, signature: ArrayBuffer, plaintext: ArrayBuffer): boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Generate an AES key.
|
|
265
|
+
*
|
|
266
|
+
* @param size The length in bits of the key to generate. 128, 192, or 256.
|
|
267
|
+
*/
|
|
268
|
+
generateAesKey(size: number): ArrayBuffer;
|
|
269
|
+
/**
|
|
270
|
+
* Generate an RSA key pair.
|
|
271
|
+
*
|
|
272
|
+
* @param size The length in bits of the RSA modulus. Minimum: 2048.
|
|
273
|
+
* @param exponent The public exponent. Default: 65537.
|
|
274
|
+
*/
|
|
275
|
+
generateRsaKeyPair(size: number, exponent?: number): CryptoKeyPair;
|
|
276
|
+
/**
|
|
277
|
+
* Generate an ECDSA key pair.
|
|
278
|
+
*
|
|
279
|
+
* @param curve The name of the curve, one of "secp256r1", "secp256k1", "secp384r1".
|
|
280
|
+
*/
|
|
281
|
+
generateEcdsaKeyPair(curve: string): CryptoKeyPair;
|
|
282
|
+
/**
|
|
283
|
+
* Generate an EdDSA key pair.
|
|
284
|
+
*
|
|
285
|
+
* @param curve The name of the curve. Currently only "curve25519" is supported.
|
|
286
|
+
*/
|
|
287
|
+
generateEddsaKeyPair(curve: string): CryptoKeyPair;
|
|
288
|
+
/**
|
|
289
|
+
* Wraps a key using a wrapping key.
|
|
290
|
+
*
|
|
291
|
+
* Constraints on the `key` and `wrappingKey` parameters depend
|
|
292
|
+
* on the wrapping algorithm that is used (`wrapAlgo`).
|
|
293
|
+
*/
|
|
294
|
+
wrapKey(key: ArrayBuffer, wrappingKey: ArrayBuffer, wrapAlgo: WrapAlgoParams): ArrayBuffer;
|
|
295
|
+
/**
|
|
296
|
+
* Generate a digest (hash) of the given data.
|
|
297
|
+
*/
|
|
298
|
+
digest(algorithm: DigestAlgorithm, plaintext: ArrayBuffer): ArrayBuffer;
|
|
299
|
+
/**
|
|
300
|
+
* Returns whether a string is a PEM-encoded bundle of X.509 certificates.
|
|
301
|
+
*
|
|
302
|
+
* A bundle consists of one or more certificates.
|
|
303
|
+
* Certificates in the bundle do not have to be related to each other.
|
|
304
|
+
* Validation is only syntactical, properties like validity dates are not evaluated.
|
|
305
|
+
*/
|
|
306
|
+
isValidX509CertBundle(pem: string): boolean;
|
|
307
|
+
/**
|
|
308
|
+
* Returns whether a certificate chain is valid given a set of trusted certificates.
|
|
309
|
+
* The chain and trusted certificates are PEM-encoded bundles of X.509 certificates.
|
|
310
|
+
*/
|
|
311
|
+
isValidX509CertChain(chain: string, trusted: string): boolean;
|
|
312
|
+
/**
|
|
313
|
+
* Converts an elliptic curve public key as PEM to JSON Web Key (JWK) object.
|
|
314
|
+
*
|
|
315
|
+
* @param pem Elliptic curve public key as PEM
|
|
316
|
+
* @param kid Key identifier (optional)
|
|
317
|
+
*/
|
|
318
|
+
pubPemToJwk(pem: string, kid?: string): JsonWebKeyECPublic;
|
|
319
|
+
/**
|
|
320
|
+
* Converts an elliptic curve private key as PEM to JSON Web Key (JWK) object.
|
|
321
|
+
*
|
|
322
|
+
* @param pem Elliptic curve private key as PEM
|
|
323
|
+
* @param kid Key identifier (optional)
|
|
324
|
+
*/
|
|
325
|
+
pemToJwk(pem: string, kid?: string): JsonWebKeyECPrivate;
|
|
326
|
+
/**
|
|
327
|
+
* Converts an RSA public key as PEM to JSON Web Key (JWK) object.
|
|
328
|
+
*
|
|
329
|
+
* @param pem RSA public key as PEM
|
|
330
|
+
* @param kid Key identifier (optional)
|
|
331
|
+
*/
|
|
332
|
+
pubRsaPemToJwk(pem: string, kid?: string): JsonWebKeyRSAPublic;
|
|
333
|
+
/**
|
|
334
|
+
* Converts an RSA private key as PEM to JSON Web Key (JWK) object.
|
|
335
|
+
*
|
|
336
|
+
* @param pem RSA private key as PEM
|
|
337
|
+
* @param kid Key identifier (optional)
|
|
338
|
+
*/
|
|
339
|
+
rsaPemToJwk(pem: string, kid?: string): JsonWebKeyRSAPrivate;
|
|
208
340
|
}
|
|
209
341
|
export interface CCFRpc {
|
|
210
342
|
/**
|
|
@@ -309,46 +441,38 @@ export interface CCF {
|
|
|
309
441
|
*/
|
|
310
442
|
bufToJsonCompatible<T extends JsonCompatible<T>>(v: ArrayBuffer): T;
|
|
311
443
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* @param size The length in bits of the key to generate. 128, 192, or 256.
|
|
444
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
445
|
+
* @see crypto.generateAesKey
|
|
315
446
|
*/
|
|
316
447
|
generateAesKey(size: number): ArrayBuffer;
|
|
317
448
|
/**
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* @param size The length in bits of the RSA modulus. Minimum: 2048.
|
|
321
|
-
* @param exponent The public exponent. Default: 65537.
|
|
449
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
450
|
+
* @see crypto.generateRsaKeyPair
|
|
322
451
|
*/
|
|
323
452
|
generateRsaKeyPair(size: number, exponent?: number): CryptoKeyPair;
|
|
324
453
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
* @param curve The name of the curve, one of "secp256r1", "secp256k1", "secp384r1".
|
|
454
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
455
|
+
* @see crypto.generateEcdsaKeyPair
|
|
328
456
|
*/
|
|
329
457
|
generateEcdsaKeyPair(curve: string): CryptoKeyPair;
|
|
330
458
|
/**
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
* Constraints on the `key` and `wrappingKey` parameters depend
|
|
334
|
-
* on the wrapping algorithm that is used (`wrapAlgo`).
|
|
459
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
460
|
+
* @see crypto.wrapKey
|
|
335
461
|
*/
|
|
336
462
|
wrapKey(key: ArrayBuffer, wrappingKey: ArrayBuffer, wrapAlgo: WrapAlgoParams): ArrayBuffer;
|
|
337
463
|
/**
|
|
338
|
-
*
|
|
464
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
465
|
+
* @see crypto.digest
|
|
339
466
|
*/
|
|
340
467
|
digest(algorithm: DigestAlgorithm, data: ArrayBuffer): ArrayBuffer;
|
|
341
468
|
/**
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
* A bundle consists of one or more certificates.
|
|
345
|
-
* Certificates in the bundle do not have to be related to each other.
|
|
346
|
-
* Validation is only syntactical, properties like validity dates are not evaluated.
|
|
469
|
+
* @deprecated
|
|
470
|
+
* @see crypto.isValidX509CertBundle
|
|
347
471
|
*/
|
|
348
472
|
isValidX509CertBundle(pem: string): boolean;
|
|
349
473
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
474
|
+
* @deprecated This method has been moved to ccf.crypto namespace
|
|
475
|
+
* @see crypto.isValidX509CertChain
|
|
352
476
|
*/
|
|
353
477
|
isValidX509CertChain(chain: string, trusted: string): boolean;
|
|
354
478
|
crypto: CCFCrypto;
|
package/historical.d.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const historicalState: import("./global.js").HistoricalState | undefined;
|
|
5
5
|
/**
|
|
6
|
-
* @inheritDoc CCFHistorical.getStateRange
|
|
6
|
+
* @inheritDoc global!CCFHistorical.getStateRange
|
|
7
7
|
*/
|
|
8
8
|
export declare const getStateRange: (handle: number, startSeqno: number, endSeqno: number, secondsUntilExpiry: number) => import("./global.js").HistoricalState[] | null;
|
|
9
9
|
/**
|
|
10
|
-
* @inheritDoc CCFHistorical.dropCachedStates
|
|
10
|
+
* @inheritDoc global!CCFHistorical.dropCachedStates
|
|
11
11
|
*/
|
|
12
12
|
export declare const dropCachedStates: (handle: number) => boolean;
|
|
13
13
|
export { HistoricalState, Receipt, Proof, ProofElement } from "./global";
|
package/historical.js
CHANGED
|
@@ -33,10 +33,10 @@ import { ccf } from "./global.js";
|
|
|
33
33
|
*/
|
|
34
34
|
export const historicalState = ccf.historicalState;
|
|
35
35
|
/**
|
|
36
|
-
* @inheritDoc CCFHistorical.getStateRange
|
|
36
|
+
* @inheritDoc global!CCFHistorical.getStateRange
|
|
37
37
|
*/
|
|
38
38
|
export const getStateRange = ccf.historical.getStateRange.bind(ccf.historical);
|
|
39
39
|
/**
|
|
40
|
-
* @inheritDoc CCFHistorical.dropCachedStates
|
|
40
|
+
* @inheritDoc global!CCFHistorical.dropCachedStates
|
|
41
41
|
*/
|
|
42
42
|
export const dropCachedStates = ccf.historical.dropCachedStates.bind(ccf.historical);
|
package/openenclave.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @inheritDoc OpenEnclave.verifyOpenEnclaveEvidence
|
|
2
|
+
* @inheritDoc global!OpenEnclave.verifyOpenEnclaveEvidence
|
|
3
3
|
*/
|
|
4
4
|
export declare const verifyOpenEnclaveEvidence: (format: string | undefined, evidence: ArrayBuffer, endorsements?: ArrayBuffer | undefined) => import("./global").EvidenceClaims;
|
|
5
5
|
export { EvidenceClaims } from "./global";
|
package/openenclave.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/ccf-app",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-rc1",
|
|
4
4
|
"description": "CCF app support package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -19,12 +19,14 @@
|
|
|
19
19
|
"license": "Apache-2.0",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/chai": "^4.2.15",
|
|
22
|
+
"@types/jsrsasign": "^10.5.4",
|
|
22
23
|
"@types/mocha": "^10.0.0",
|
|
23
24
|
"@types/node": "^18.0.0",
|
|
24
25
|
"@types/node-forge": "^1.0.0",
|
|
25
26
|
"chai": "^4.3.4",
|
|
26
27
|
"colors": "1.4.0",
|
|
27
28
|
"cross-env": "^7.0.3",
|
|
29
|
+
"jsrsasign": "^10.5.27",
|
|
28
30
|
"mocha": "^10.0.0",
|
|
29
31
|
"node-forge": "^1.2.0",
|
|
30
32
|
"ts-node": "^10.4.0",
|
package/polyfill.js
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
|
-
import * as
|
|
17
|
+
import * as jscrypto from "crypto";
|
|
18
18
|
import { TextEncoder, TextDecoder } from "util";
|
|
19
|
+
import * as rs from "jsrsasign";
|
|
19
20
|
// JavaScript's Map uses reference equality for non-primitive types,
|
|
20
21
|
// whereas CCF compares the content of the ArrayBuffer.
|
|
21
22
|
// To achieve CCF's semantics, all keys are base64-encoded.
|
|
@@ -91,12 +92,48 @@ class CCFPolyfill {
|
|
|
91
92
|
},
|
|
92
93
|
};
|
|
93
94
|
this.crypto = {
|
|
95
|
+
sign(algorithm, key, data) {
|
|
96
|
+
let padding = undefined;
|
|
97
|
+
const privKey = jscrypto.createPrivateKey(key);
|
|
98
|
+
if (privKey.asymmetricKeyType == "rsa") {
|
|
99
|
+
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
|
|
100
|
+
padding = jscrypto.constants.RSA_PKCS1_PADDING;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error("incompatible signing algorithm for given key type");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (privKey.asymmetricKeyType == "ec") {
|
|
107
|
+
if (algorithm.name !== "ECDSA") {
|
|
108
|
+
throw new Error("incompatible signing algorithm for given key type");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (privKey.asymmetricKeyType == "ed25519") {
|
|
112
|
+
if (algorithm.name !== "EdDSA") {
|
|
113
|
+
throw new Error("incompatible signing algorithm for given key type");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
throw new Error("unrecognized signing algorithm");
|
|
118
|
+
}
|
|
119
|
+
if (algorithm.name === "EdDSA") {
|
|
120
|
+
return jscrypto.sign(null, new Uint8Array(data), privKey);
|
|
121
|
+
}
|
|
122
|
+
const hashAlg = algorithm.hash.replace("-", "").toLowerCase();
|
|
123
|
+
const signer = jscrypto.createSign(hashAlg);
|
|
124
|
+
signer.update(new Uint8Array(data));
|
|
125
|
+
return signer.sign({
|
|
126
|
+
key: privKey,
|
|
127
|
+
dsaEncoding: "ieee-p1363",
|
|
128
|
+
padding: padding,
|
|
129
|
+
});
|
|
130
|
+
},
|
|
94
131
|
verifySignature(algorithm, key, signature, data) {
|
|
95
132
|
let padding = undefined;
|
|
96
|
-
const pubKey =
|
|
133
|
+
const pubKey = jscrypto.createPublicKey(key);
|
|
97
134
|
if (pubKey.asymmetricKeyType == "rsa") {
|
|
98
135
|
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
|
|
99
|
-
padding =
|
|
136
|
+
padding = jscrypto.constants.RSA_PKCS1_PADDING;
|
|
100
137
|
}
|
|
101
138
|
else {
|
|
102
139
|
throw new Error("incompatible signing algorithm for given key type");
|
|
@@ -107,11 +144,19 @@ class CCFPolyfill {
|
|
|
107
144
|
throw new Error("incompatible signing algorithm for given key type");
|
|
108
145
|
}
|
|
109
146
|
}
|
|
147
|
+
else if (pubKey.asymmetricKeyType == "ed25519") {
|
|
148
|
+
if (algorithm.name !== "EdDSA") {
|
|
149
|
+
throw new Error("incompatible signing algorithm for given key type");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
110
152
|
else {
|
|
111
153
|
throw new Error("unrecognized signing algorithm");
|
|
112
154
|
}
|
|
155
|
+
if (algorithm.name === "EdDSA") {
|
|
156
|
+
return jscrypto.verify(null, new Uint8Array(data), pubKey, new Uint8Array(signature));
|
|
157
|
+
}
|
|
113
158
|
const hashAlg = algorithm.hash.replace("-", "").toLowerCase();
|
|
114
|
-
const verifier =
|
|
159
|
+
const verifier = jscrypto.createVerify(hashAlg);
|
|
115
160
|
verifier.update(new Uint8Array(data));
|
|
116
161
|
return verifier.verify({
|
|
117
162
|
key: pubKey,
|
|
@@ -119,6 +164,189 @@ class CCFPolyfill {
|
|
|
119
164
|
padding: padding,
|
|
120
165
|
}, new Uint8Array(signature));
|
|
121
166
|
},
|
|
167
|
+
generateAesKey(size) {
|
|
168
|
+
return nodeBufToArrBuf(jscrypto.randomBytes(size / 8));
|
|
169
|
+
},
|
|
170
|
+
generateRsaKeyPair(size, exponent) {
|
|
171
|
+
const rsaKeyPair = jscrypto.generateKeyPairSync("rsa", {
|
|
172
|
+
modulusLength: size,
|
|
173
|
+
publicExponent: exponent,
|
|
174
|
+
publicKeyEncoding: {
|
|
175
|
+
type: "spki",
|
|
176
|
+
format: "pem",
|
|
177
|
+
},
|
|
178
|
+
privateKeyEncoding: {
|
|
179
|
+
type: "pkcs8",
|
|
180
|
+
format: "pem",
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
return rsaKeyPair;
|
|
184
|
+
},
|
|
185
|
+
generateEcdsaKeyPair(curve) {
|
|
186
|
+
var curve_name = curve;
|
|
187
|
+
if (curve == "secp256r1")
|
|
188
|
+
curve_name = "prime256v1";
|
|
189
|
+
const ecdsaKeyPair = jscrypto.generateKeyPairSync("ec", {
|
|
190
|
+
namedCurve: curve_name,
|
|
191
|
+
publicKeyEncoding: {
|
|
192
|
+
type: "spki",
|
|
193
|
+
format: "pem",
|
|
194
|
+
},
|
|
195
|
+
privateKeyEncoding: {
|
|
196
|
+
type: "pkcs8",
|
|
197
|
+
format: "pem",
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
return ecdsaKeyPair;
|
|
201
|
+
},
|
|
202
|
+
generateEddsaKeyPair(curve) {
|
|
203
|
+
// `type` is always "ed25519" because currently only "curve25519" is supported for `curve`.
|
|
204
|
+
const type = "ed25519";
|
|
205
|
+
const ecdsaKeyPair = jscrypto.generateKeyPairSync(type, {
|
|
206
|
+
publicKeyEncoding: {
|
|
207
|
+
type: "spki",
|
|
208
|
+
format: "pem",
|
|
209
|
+
},
|
|
210
|
+
privateKeyEncoding: {
|
|
211
|
+
type: "pkcs8",
|
|
212
|
+
format: "pem",
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
return ecdsaKeyPair;
|
|
216
|
+
},
|
|
217
|
+
wrapKey(key, wrappingKey, parameters) {
|
|
218
|
+
if (parameters.name === "RSA-OAEP") {
|
|
219
|
+
return nodeBufToArrBuf(jscrypto.publicEncrypt({
|
|
220
|
+
key: Buffer.from(wrappingKey),
|
|
221
|
+
oaepHash: "sha256",
|
|
222
|
+
oaepLabel: parameters.label
|
|
223
|
+
? new Uint8Array(parameters.label)
|
|
224
|
+
: undefined,
|
|
225
|
+
padding: jscrypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
226
|
+
}, new Uint8Array(key)));
|
|
227
|
+
}
|
|
228
|
+
else if (parameters.name === "AES-KWP") {
|
|
229
|
+
const iv = Buffer.from("A65959A6", "hex"); // defined in RFC 5649
|
|
230
|
+
const cipher = jscrypto.createCipheriv("id-aes256-wrap-pad", new Uint8Array(wrappingKey), iv);
|
|
231
|
+
return nodeBufToArrBuf(Buffer.concat([cipher.update(new Uint8Array(key)), cipher.final()]));
|
|
232
|
+
}
|
|
233
|
+
else if (parameters.name === "RSA-OAEP-AES-KWP") {
|
|
234
|
+
const randomAesKey = this.generateAesKey(parameters.aesKeySize);
|
|
235
|
+
const wrap1 = this.wrapKey(randomAesKey, wrappingKey, {
|
|
236
|
+
name: "RSA-OAEP",
|
|
237
|
+
label: parameters.label,
|
|
238
|
+
});
|
|
239
|
+
const wrap2 = this.wrapKey(key, randomAesKey, {
|
|
240
|
+
name: "AES-KWP",
|
|
241
|
+
});
|
|
242
|
+
return nodeBufToArrBuf(Buffer.concat([Buffer.from(wrap1), Buffer.from(wrap2)]));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
throw new Error("unsupported wrapAlgo.name");
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
digest(algorithm, data) {
|
|
249
|
+
if (algorithm === "SHA-256") {
|
|
250
|
+
return nodeBufToArrBuf(jscrypto.createHash("sha256").update(new Uint8Array(data)).digest());
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
throw new Error("unsupported algorithm");
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
isValidX509CertBundle(pem) {
|
|
257
|
+
if ("X509Certificate" in jscrypto) {
|
|
258
|
+
const sep = "-----END CERTIFICATE-----";
|
|
259
|
+
const items = pem.split(sep);
|
|
260
|
+
if (items.length === 1) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
const pems = items.slice(0, -1).map((p) => p + sep);
|
|
264
|
+
for (const [i, p] of pems.entries()) {
|
|
265
|
+
try {
|
|
266
|
+
new jscrypto.X509Certificate(p);
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
console.error(`cert ${i} is not valid: ${e.message}`);
|
|
270
|
+
console.error(p);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
throw new Error("X509 validation unsupported, Node.js version too old (< 15.6.0)");
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
isValidX509CertChain(chain, trusted) {
|
|
281
|
+
if (!("X509Certificate" in jscrypto)) {
|
|
282
|
+
throw new Error("X509 validation unsupported, Node.js version too old (< 15.6.0)");
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const toX509Array = (pem) => {
|
|
286
|
+
const sep = "-----END CERTIFICATE-----";
|
|
287
|
+
const items = pem.split(sep);
|
|
288
|
+
if (items.length === 1) {
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
const pems = items.slice(0, -1).map((p) => p + sep);
|
|
292
|
+
const arr = pems.map((pem) => new jscrypto.X509Certificate(pem));
|
|
293
|
+
return arr;
|
|
294
|
+
};
|
|
295
|
+
const certsChain = toX509Array(chain);
|
|
296
|
+
const certsTrusted = toX509Array(trusted);
|
|
297
|
+
if (certsChain.length === 0) {
|
|
298
|
+
throw new Error("chain cannot be empty");
|
|
299
|
+
}
|
|
300
|
+
for (let i = 0; i < certsChain.length - 1; i++) {
|
|
301
|
+
if (!certsChain[i].checkIssued(certsChain[i + 1])) {
|
|
302
|
+
throw new Error(`chain[${i}] is not issued by chain[${i + 1}]`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (const certChain of certsChain) {
|
|
306
|
+
for (const certTrusted of certsTrusted) {
|
|
307
|
+
if (certChain.fingerprint === certTrusted.fingerprint) {
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
if (certChain.verify(certTrusted.publicKey)) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
throw new Error("none of the chain certificates are identical to or issued by a trusted certificate");
|
|
316
|
+
}
|
|
317
|
+
catch (e) {
|
|
318
|
+
console.error(`certificate chain validation failed: ${e.message}`);
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
pubPemToJwk(pem, kid) {
|
|
323
|
+
let jwk = rs.KEYUTIL.getJWK(rs.KEYUTIL.getKey(pem));
|
|
324
|
+
if (kid !== undefined) {
|
|
325
|
+
jwk.kid = kid;
|
|
326
|
+
}
|
|
327
|
+
return jwk;
|
|
328
|
+
},
|
|
329
|
+
pemToJwk(pem, kid) {
|
|
330
|
+
let jwk = rs.KEYUTIL.getJWK(rs.KEYUTIL.getKey(pem));
|
|
331
|
+
if (kid !== undefined) {
|
|
332
|
+
jwk.kid = kid;
|
|
333
|
+
}
|
|
334
|
+
return jwk;
|
|
335
|
+
},
|
|
336
|
+
pubRsaPemToJwk(pem, kid) {
|
|
337
|
+
let jwk = rs.KEYUTIL.getJWK(rs.KEYUTIL.getKey(pem));
|
|
338
|
+
if (kid !== undefined) {
|
|
339
|
+
jwk.kid = kid;
|
|
340
|
+
}
|
|
341
|
+
return jwk;
|
|
342
|
+
},
|
|
343
|
+
rsaPemToJwk(pem, kid) {
|
|
344
|
+
let jwk = rs.KEYUTIL.getJWK(rs.KEYUTIL.getKey(pem));
|
|
345
|
+
if (kid !== undefined) {
|
|
346
|
+
jwk.kid = kid;
|
|
347
|
+
}
|
|
348
|
+
return jwk;
|
|
349
|
+
},
|
|
122
350
|
};
|
|
123
351
|
}
|
|
124
352
|
strToBuf(s) {
|
|
@@ -134,144 +362,25 @@ class CCFPolyfill {
|
|
|
134
362
|
return JSON.parse(this.bufToStr(v));
|
|
135
363
|
}
|
|
136
364
|
generateAesKey(size) {
|
|
137
|
-
return
|
|
365
|
+
return this.crypto.generateAesKey(size);
|
|
138
366
|
}
|
|
139
367
|
generateRsaKeyPair(size, exponent) {
|
|
140
|
-
|
|
141
|
-
modulusLength: size,
|
|
142
|
-
publicExponent: exponent,
|
|
143
|
-
publicKeyEncoding: {
|
|
144
|
-
type: "spki",
|
|
145
|
-
format: "pem",
|
|
146
|
-
},
|
|
147
|
-
privateKeyEncoding: {
|
|
148
|
-
type: "pkcs8",
|
|
149
|
-
format: "pem",
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
return rsaKeyPair;
|
|
368
|
+
return this.crypto.generateRsaKeyPair(size, exponent);
|
|
153
369
|
}
|
|
154
370
|
generateEcdsaKeyPair(curve) {
|
|
155
|
-
|
|
156
|
-
if (curve == "secp256r1")
|
|
157
|
-
curve_name = "prime256v1";
|
|
158
|
-
const ecdsaKeyPair = crypto.generateKeyPairSync("ec", {
|
|
159
|
-
namedCurve: curve_name,
|
|
160
|
-
publicKeyEncoding: {
|
|
161
|
-
type: "spki",
|
|
162
|
-
format: "pem",
|
|
163
|
-
},
|
|
164
|
-
privateKeyEncoding: {
|
|
165
|
-
type: "pkcs8",
|
|
166
|
-
format: "pem",
|
|
167
|
-
},
|
|
168
|
-
});
|
|
169
|
-
return ecdsaKeyPair;
|
|
371
|
+
return this.crypto.generateEcdsaKeyPair(curve);
|
|
170
372
|
}
|
|
171
373
|
wrapKey(key, wrappingKey, parameters) {
|
|
172
|
-
|
|
173
|
-
return nodeBufToArrBuf(crypto.publicEncrypt({
|
|
174
|
-
key: Buffer.from(wrappingKey),
|
|
175
|
-
oaepHash: "sha256",
|
|
176
|
-
oaepLabel: parameters.label
|
|
177
|
-
? new Uint8Array(parameters.label)
|
|
178
|
-
: undefined,
|
|
179
|
-
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
180
|
-
}, new Uint8Array(key)));
|
|
181
|
-
}
|
|
182
|
-
else if (parameters.name === "AES-KWP") {
|
|
183
|
-
const iv = Buffer.from("A65959A6", "hex"); // defined in RFC 5649
|
|
184
|
-
const cipher = crypto.createCipheriv("id-aes256-wrap-pad", new Uint8Array(wrappingKey), iv);
|
|
185
|
-
return nodeBufToArrBuf(Buffer.concat([cipher.update(new Uint8Array(key)), cipher.final()]));
|
|
186
|
-
}
|
|
187
|
-
else if (parameters.name === "RSA-OAEP-AES-KWP") {
|
|
188
|
-
const randomAesKey = this.generateAesKey(parameters.aesKeySize);
|
|
189
|
-
const wrap1 = this.wrapKey(randomAesKey, wrappingKey, {
|
|
190
|
-
name: "RSA-OAEP",
|
|
191
|
-
label: parameters.label,
|
|
192
|
-
});
|
|
193
|
-
const wrap2 = this.wrapKey(key, randomAesKey, {
|
|
194
|
-
name: "AES-KWP",
|
|
195
|
-
});
|
|
196
|
-
return nodeBufToArrBuf(Buffer.concat([Buffer.from(wrap1), Buffer.from(wrap2)]));
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
throw new Error("unsupported wrapAlgo.name");
|
|
200
|
-
}
|
|
374
|
+
return this.crypto.wrapKey(key, wrappingKey, parameters);
|
|
201
375
|
}
|
|
202
376
|
digest(algorithm, data) {
|
|
203
|
-
|
|
204
|
-
return nodeBufToArrBuf(crypto.createHash("sha256").update(new Uint8Array(data)).digest());
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
throw new Error("unsupported algorithm");
|
|
208
|
-
}
|
|
377
|
+
return this.crypto.digest(algorithm, data);
|
|
209
378
|
}
|
|
210
379
|
isValidX509CertBundle(pem) {
|
|
211
|
-
|
|
212
|
-
const sep = "-----END CERTIFICATE-----";
|
|
213
|
-
const items = pem.split(sep);
|
|
214
|
-
if (items.length === 1) {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
const pems = items.slice(0, -1).map((p) => p + sep);
|
|
218
|
-
for (const [i, p] of pems.entries()) {
|
|
219
|
-
try {
|
|
220
|
-
new crypto.X509Certificate(p);
|
|
221
|
-
}
|
|
222
|
-
catch (e) {
|
|
223
|
-
console.error(`cert ${i} is not valid: ${e.message}`);
|
|
224
|
-
console.error(p);
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
throw new Error("X509 validation unsupported, Node.js version too old (< 15.6.0)");
|
|
232
|
-
}
|
|
380
|
+
return this.crypto.isValidX509CertBundle(pem);
|
|
233
381
|
}
|
|
234
382
|
isValidX509CertChain(chain, trusted) {
|
|
235
|
-
|
|
236
|
-
throw new Error("X509 validation unsupported, Node.js version too old (< 15.6.0)");
|
|
237
|
-
}
|
|
238
|
-
try {
|
|
239
|
-
const toX509Array = (pem) => {
|
|
240
|
-
const sep = "-----END CERTIFICATE-----";
|
|
241
|
-
const items = pem.split(sep);
|
|
242
|
-
if (items.length === 1) {
|
|
243
|
-
return [];
|
|
244
|
-
}
|
|
245
|
-
const pems = items.slice(0, -1).map((p) => p + sep);
|
|
246
|
-
const arr = pems.map((pem) => new crypto.X509Certificate(pem));
|
|
247
|
-
return arr;
|
|
248
|
-
};
|
|
249
|
-
const certsChain = toX509Array(chain);
|
|
250
|
-
const certsTrusted = toX509Array(trusted);
|
|
251
|
-
if (certsChain.length === 0) {
|
|
252
|
-
throw new Error("chain cannot be empty");
|
|
253
|
-
}
|
|
254
|
-
for (let i = 0; i < certsChain.length - 1; i++) {
|
|
255
|
-
if (!certsChain[i].checkIssued(certsChain[i + 1])) {
|
|
256
|
-
throw new Error(`chain[${i}] is not issued by chain[${i + 1}]`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
for (const certChain of certsChain) {
|
|
260
|
-
for (const certTrusted of certsTrusted) {
|
|
261
|
-
if (certChain.fingerprint === certTrusted.fingerprint) {
|
|
262
|
-
return true;
|
|
263
|
-
}
|
|
264
|
-
if (certChain.verify(certTrusted.publicKey)) {
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
throw new Error("none of the chain certificates are identical to or issued by a trusted certificate");
|
|
270
|
-
}
|
|
271
|
-
catch (e) {
|
|
272
|
-
console.error(`certificate chain validation failed: ${e.message}`);
|
|
273
|
-
return false;
|
|
274
|
-
}
|
|
383
|
+
return this.crypto.isValidX509CertChain(chain, trusted);
|
|
275
384
|
}
|
|
276
385
|
}
|
|
277
386
|
globalThis.ccf = new CCFPolyfill();
|