This repository has been archived by the owner on Dec 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
208 lines (180 loc) · 8.1 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/**
* Conversion to and from [Multikey format](https://www.w3.org/TR/controller-document/#multikey) from
* JWK or WebCrypto for the three EC curves that are defined for Verifiable Credentials: [ECDSA with P-256 and P-384](https://www.w3.org/TR/vc-di-ecdsa/#multikey)
* and [EDDSA](https://www.w3.org/TR/vc-di-eddsa/#multikey).
*
* @package
*/
import * as convert from './lib/convert';
import { JWKKeyPair, Multikey, Multibase } from './lib/common';
export type { JWKKeyPair, Multikey, Multibase} from './lib/common';
// This type guard function is reused at two different places, better factor it out...
function isMultikeyPair(obj: any): obj is Multikey {
return (obj as Multikey).publicKeyMultibase !== undefined;
}
/* =========================================================================================
Converting multikeys to JWK
========================================================================================= */
/**
* Convert a multikey pair to JWK. This function decodes the multikey data
* into a binary buffer, checks the preambles and invokes the crypto specific converter functions
* (depending on the preamble values) that do the final conversion from the binary data to JWK.
*
* Works for `ecdsa` (both `P-384` and `P-256`), and `eddsa`.
*
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export function multikeyToJWK(keys: Multikey): JWKKeyPair;
/**
* Overloaded version of the conversion function for a single (public) key in Multikey, returning the generated JWK.
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export function multikeyToJWK(keys: Multibase): JsonWebKey;
export function multikeyToJWK(keys: Multikey | Multibase): JWKKeyPair | JsonWebKey {
const input: Multikey = isMultikeyPair(keys) ? keys as Multikey : { publicKeyMultibase: keys };
const jwk_keys = convert.multikeyToJWK(input);
if (isMultikeyPair(keys)) {
return jwk_keys;
} else {
return jwk_keys.publicKey;
}
}
/* =========================================================================================
Converting multikeys to WebCrypto
========================================================================================= */
/**
* Convert a multikey pair to Web Crypto. This function decodes the multikey data into JWK using the
* `multikeyToJWK` function, and imports the resulting keys into Web Crypto.
*
* Works for `ecdsa` (both `P-384` and `P-256`), and `eddsa`.
*
* Note that, because WebCrypto methods are asynchronous, so is this function.
*
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
* @async
*/
export async function multikeyToCrypto(keys: Multikey): Promise<CryptoKeyPair>;
/**
* Overloaded version of the conversion function for a single (public) key in Multikey, returning the generated Crypto Key.
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export async function multikeyToCrypto(keys: Multibase): Promise<CryptoKey>;
// Implementation of the overloaded functions
export async function multikeyToCrypto(keys: Multikey | Multibase): Promise<CryptoKeyPair | CryptoKey> {
const input: Multikey = isMultikeyPair(keys) ? keys as Multikey : { publicKeyMultibase: keys };
const jwkPair: JWKKeyPair = multikeyToJWK(input);
const algorithm: { name: string, namedCurve ?: string } = { name : "" };
// We have to establish what the algorithm type is from the public jwk
switch (jwkPair.publicKey.kty) {
case 'EC':
algorithm.name = "ECDSA";
algorithm.namedCurve = jwkPair.publicKey.crv;
break;
case 'OKP':
algorithm.name = "Ed25519";
break;
default:
// In fact, this does not happen; the JWK comes from our own
// generation, that raises an error earlier in this case.
// But this keeps the typescript code checker happy...
throw new Error("Unknown kty value for the JWK key");
}
const output: CryptoKeyPair = {
publicKey : await crypto.subtle.importKey("jwk", jwkPair.publicKey, algorithm, true, ["verify"]),
privateKey : undefined,
}
if (jwkPair.privateKey != undefined) {
output.privateKey = await crypto.subtle.importKey("jwk", jwkPair.privateKey, algorithm, true, ["sign"])
}
// Got the return, the type depends on the overloaded input type
if (isMultikeyPair(keys)) {
return output;
} else {
return output.publicKey;
}
}
/* =========================================================================================
Converting JWK to multikeys
========================================================================================= */
/**
* Convert a JWK Key pair to Multikeys. This function decodes the JWK keys, finds out which binary key it encodes
* and, converts the key to the multikey versions depending on the exact curve.
*
* Note that the code does not check (yet?) all combination of JWK pairs and fields for possible errors, only
* those that would lead to error in this package. E.g., it does not check whether the x (and possibly y) values
* are identical in the secret and private JWK keys.
*
* Works for `ecdsa` (both `P-384` and `P-256`), and `eddsa`.
*
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export function JWKToMultikey(keys: JWKKeyPair): Multikey;
/**
* Overloaded version of the conversion function for a single (public) key in JWK, returning the generated Multikey.
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export function JWKToMultikey(keys: JsonWebKey): Multibase;
// Implementation of the overloaded functions
export function JWKToMultikey(keys: JWKKeyPair | JsonWebKey): Multikey | Multibase {
function isJWKKeyPair(obj: any): obj is JWKKeyPair {
return (obj as JWKKeyPair).publicKey !== undefined;
}
const input: JWKKeyPair = isJWKKeyPair(keys) ? keys : {publicKey: keys};
const m_keys = convert.JWKToMultikey(input);
if (isJWKKeyPair(keys)) {
return m_keys;
} else {
return m_keys.publicKeyMultibase;
}
}
/* =========================================================================================
Converting WebCrypto to multikeys
========================================================================================= */
/**
* Convert a Crypto Key pair to Multikeys. This function exports the Cryptokeys into a JWK Key pair,
* and uses the `JWKToMultikey` function.
*
* Works for `ecdsa` (both `P-384` and `P-256`), and `eddsa`.
*
* Note that, because WebCrypto methods are asynchronous, so is this function.
*
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
* @async
*/
export async function cryptoToMultikey(keys: CryptoKeyPair): Promise<Multikey>;
/**
* Overloaded version of the conversion function for a single (public) key in JWK, returning the generated Multikey.
* @param keys
* @throws - exceptions if something is incorrect in the incoming data
*/
export async function cryptoToMultikey(keys: CryptoKey): Promise<Multibase>;
// Implementation of the overloaded functions
export async function cryptoToMultikey(keys: CryptoKeyPair | CryptoKey): Promise<Multikey | Multibase> {
function isCryptoKeyPair(obj: any): obj is CryptoKeyPair {
return (obj as CryptoKeyPair).publicKey !== undefined;
}
const isPair = isCryptoKeyPair(keys);
const input: CryptoKeyPair = isPair ? keys : { publicKey: keys, privateKey: undefined };
// Generate the JWK version of the cryptokeys:
const jwkKeyPair: JWKKeyPair = {
publicKey: await crypto.subtle.exportKey("jwk", input.publicKey),
}
if (isPair && input.privateKey !== undefined) {
jwkKeyPair.privateKey = await crypto.subtle.exportKey("jwk", input.privateKey);
}
// Ready for conversion
const output: Multikey = JWKToMultikey(jwkKeyPair);
// Return the right version
if (isPair) {
return output;
} else {
return output.publicKeyMultibase;
}
}