core-3nweb-client-lib 0.40.1 → 0.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.
- package/build/api-defs/mailerid.d.ts +51 -1
- package/build/core/asmail/key-verification.d.ts +5 -0
- package/build/core/asmail/key-verification.js +6 -4
- package/build/core/id-manager/index.d.ts +2 -2
- package/build/core/id-manager/index.js +30 -0
- package/build/core/id-manager/mailerid-cap-ipc.js +6 -2
- package/build/core-ipc/json-ipc-wrapping/json-n-binary.js +1 -1
- package/build/lib-client/asmail/sender.d.ts +2 -2
- package/build/lib-client/asmail/sender.js +1 -1
- package/build/lib-client/mailer-id/login.d.ts +2 -2
- package/build/lib-client/mailer-id/login.js +1 -1
- package/build/lib-client/mailer-id/provisioner.d.ts +2 -2
- package/build/lib-client/mailer-id/provisioner.js +6 -6
- package/build/lib-client/user-with-mid-session.d.ts +3 -3
- package/build/lib-client/user-with-mid-session.js +1 -1
- package/build/lib-common/mailerid-sigs/id-provider.d.ts +64 -0
- package/build/lib-common/mailerid-sigs/id-provider.js +174 -0
- package/build/lib-common/mailerid-sigs/index.d.ts +44 -0
- package/build/lib-common/mailerid-sigs/index.js +50 -0
- package/build/lib-common/mailerid-sigs/relying-party.d.ts +59 -0
- package/build/lib-common/mailerid-sigs/relying-party.js +237 -0
- package/build/lib-common/mailerid-sigs/user.d.ts +60 -0
- package/build/lib-common/mailerid-sigs/user.js +149 -0
- package/build/lib-common/mailerid-sigs/utils-NaCl-Ed.d.ts +8 -0
- package/build/lib-common/mailerid-sigs/utils-NaCl-Ed.js +61 -0
- package/build/raw-3nweb-clients.d.ts +2 -2
- package/build/raw-3nweb-clients.js +1 -1
- package/package.json +1 -1
- package/build/lib-common/mid-sigs-NaCl-Ed.d.ts +0 -220
- package/build/lib-common/mid-sigs-NaCl-Ed.js +0 -560
|
@@ -1,560 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
Copyright (C) 2015 - 2017, 2025 3NSoft Inc.
|
|
4
|
-
|
|
5
|
-
This program is free software: you can redistribute it and/or modify it under
|
|
6
|
-
the terms of the GNU General Public License as published by the Free Software
|
|
7
|
-
Foundation, either version 3 of the License, or (at your option) any later
|
|
8
|
-
version.
|
|
9
|
-
|
|
10
|
-
This program is distributed in the hope that it will be useful, but
|
|
11
|
-
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
13
|
-
See the GNU General Public License for more details.
|
|
14
|
-
|
|
15
|
-
You should have received a copy of the GNU General Public License along with
|
|
16
|
-
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
-
*/
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.user = exports.relyingParty = exports.idProvider = exports.exceptionType = exports.KEY_USE = void 0;
|
|
20
|
-
exports.makeMalformedCertsException = makeMalformedCertsException;
|
|
21
|
-
/**
|
|
22
|
-
* This library handles signing and verification of signatures, used
|
|
23
|
-
* in MailerId.
|
|
24
|
-
*/
|
|
25
|
-
const ecma_nacl_1 = require("ecma-nacl");
|
|
26
|
-
const jwkeys_1 = require("./jwkeys");
|
|
27
|
-
const buffer_utils_1 = require("./buffer-utils");
|
|
28
|
-
/**
|
|
29
|
-
* This enumerates MailerId's different use-roles of keys, involved in
|
|
30
|
-
* establishing a trust.
|
|
31
|
-
*/
|
|
32
|
-
exports.KEY_USE = {
|
|
33
|
-
/**
|
|
34
|
-
* This is a MailerId trust root.
|
|
35
|
-
* It signs certificate for itself, and it signs certificates for provider
|
|
36
|
-
* keys, which have shorter life span, than the root.
|
|
37
|
-
* Root may revoke itself, and may revoke provider key.
|
|
38
|
-
*/
|
|
39
|
-
ROOT: "mid-root",
|
|
40
|
-
/**
|
|
41
|
-
* This is a provider key, which is used to certify users' signing keys.
|
|
42
|
-
*/
|
|
43
|
-
PROVIDER: "mid-provider",
|
|
44
|
-
/**
|
|
45
|
-
* With this key, MailerId user signs assertions and mail keys.
|
|
46
|
-
*/
|
|
47
|
-
SIGN: "mid-sign",
|
|
48
|
-
};
|
|
49
|
-
Object.freeze(exports.KEY_USE);
|
|
50
|
-
exports.exceptionType = 'mailerid';
|
|
51
|
-
function makeAlgMismatchException(msg) {
|
|
52
|
-
return {
|
|
53
|
-
runtimeException: true,
|
|
54
|
-
type: 'mailerid',
|
|
55
|
-
msg,
|
|
56
|
-
algMismatch: true
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
function makeTimeMismatchException(msg) {
|
|
60
|
-
return {
|
|
61
|
-
runtimeException: true,
|
|
62
|
-
type: 'mailerid',
|
|
63
|
-
msg,
|
|
64
|
-
timeMismatch: true
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function makeCertsMismatchException(msg) {
|
|
68
|
-
return {
|
|
69
|
-
runtimeException: true,
|
|
70
|
-
type: 'mailerid',
|
|
71
|
-
msg,
|
|
72
|
-
certsMismatch: true
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function makeMalformedCertsException(msg, cause) {
|
|
76
|
-
return {
|
|
77
|
-
runtimeException: true,
|
|
78
|
-
type: 'mailerid',
|
|
79
|
-
msg,
|
|
80
|
-
certMalformed: true,
|
|
81
|
-
cause
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function makeSigVerifException(msg) {
|
|
85
|
-
return {
|
|
86
|
-
runtimeException: true,
|
|
87
|
-
type: 'mailerid',
|
|
88
|
-
msg,
|
|
89
|
-
sigVerificationFails: true
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function genSignKeyPair(use, kidLen, random, arrFactory) {
|
|
93
|
-
const pair = ecma_nacl_1.signing.generate_keypair(random(32), arrFactory);
|
|
94
|
-
const pkey = {
|
|
95
|
-
use: use,
|
|
96
|
-
alg: ecma_nacl_1.signing.JWK_ALG_NAME,
|
|
97
|
-
kid: buffer_utils_1.base64.pack(random(kidLen)),
|
|
98
|
-
k: buffer_utils_1.base64.pack(pair.pkey)
|
|
99
|
-
};
|
|
100
|
-
const skey = {
|
|
101
|
-
use: pkey.use,
|
|
102
|
-
alg: pkey.alg,
|
|
103
|
-
kid: pkey.kid,
|
|
104
|
-
k: pair.skey
|
|
105
|
-
};
|
|
106
|
-
return { pkey: pkey, skey: skey };
|
|
107
|
-
}
|
|
108
|
-
function makeCert(pkey, principalAddr, issuer, issuedAt, expiresAt, signKey, arrFactory) {
|
|
109
|
-
if (signKey.alg !== ecma_nacl_1.signing.JWK_ALG_NAME) {
|
|
110
|
-
throw makeAlgMismatchException(`Given signing key is used with unknown algorithm ${signKey.alg}`);
|
|
111
|
-
}
|
|
112
|
-
const cert = {
|
|
113
|
-
cert: {
|
|
114
|
-
publicKey: pkey,
|
|
115
|
-
principal: { address: principalAddr }
|
|
116
|
-
},
|
|
117
|
-
issuer: issuer,
|
|
118
|
-
issuedAt: issuedAt,
|
|
119
|
-
expiresAt: expiresAt
|
|
120
|
-
};
|
|
121
|
-
const certBytes = buffer_utils_1.utf8.pack(JSON.stringify(cert));
|
|
122
|
-
const sigBytes = ecma_nacl_1.signing.signature(certBytes, signKey.k, arrFactory);
|
|
123
|
-
return {
|
|
124
|
-
alg: signKey.alg,
|
|
125
|
-
kid: signKey.kid,
|
|
126
|
-
sig: buffer_utils_1.base64.pack(sigBytes),
|
|
127
|
-
load: buffer_utils_1.base64.pack(certBytes)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
var idProvider;
|
|
131
|
-
(function (idProvider) {
|
|
132
|
-
idProvider.KID_BYTES_LENGTH = 9;
|
|
133
|
-
idProvider.MAX_USER_CERT_VALIDITY = 24 * 60 * 60;
|
|
134
|
-
function makeSelfSignedCert(address, validityPeriod, sjkey, arrFactory) {
|
|
135
|
-
const skey = (0, jwkeys_1.keyFromJson)(sjkey, exports.KEY_USE.ROOT, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.SECRET_KEY_LENGTH);
|
|
136
|
-
const pkey = {
|
|
137
|
-
use: sjkey.use,
|
|
138
|
-
alg: sjkey.alg,
|
|
139
|
-
kid: sjkey.kid,
|
|
140
|
-
k: buffer_utils_1.base64.pack(ecma_nacl_1.signing.extract_pkey(skey.k))
|
|
141
|
-
};
|
|
142
|
-
const now = Math.floor(Date.now() / 1000);
|
|
143
|
-
return makeCert(pkey, address, address, now, now + validityPeriod, skey, arrFactory);
|
|
144
|
-
}
|
|
145
|
-
idProvider.makeSelfSignedCert = makeSelfSignedCert;
|
|
146
|
-
/**
|
|
147
|
-
* One should keep MailerId root key offline, as this key is used only to
|
|
148
|
-
* sign provider keys, which have to work online.
|
|
149
|
-
* @param address is an address of an issuer
|
|
150
|
-
* @param validityPeriod validity period of a generated self-signed
|
|
151
|
-
* certificate in milliseconds
|
|
152
|
-
* @param random
|
|
153
|
-
* @param arrFactory optional array factory
|
|
154
|
-
* @return Generated root key and a self-signed certificate for respective
|
|
155
|
-
* public key.
|
|
156
|
-
*/
|
|
157
|
-
function generateRootKey(address, validityPeriod, random, arrFactory) {
|
|
158
|
-
if (validityPeriod < 1) {
|
|
159
|
-
throw new Error(`Illegal validity period: ${validityPeriod}`);
|
|
160
|
-
}
|
|
161
|
-
const rootPair = genSignKeyPair(exports.KEY_USE.ROOT, idProvider.KID_BYTES_LENGTH, random, arrFactory);
|
|
162
|
-
const now = Math.floor(Date.now() / 1000);
|
|
163
|
-
const rootCert = makeCert(rootPair.pkey, address, address, now, now + validityPeriod, rootPair.skey, arrFactory);
|
|
164
|
-
return { cert: rootCert, skey: (0, jwkeys_1.keyToJson)(rootPair.skey) };
|
|
165
|
-
}
|
|
166
|
-
idProvider.generateRootKey = generateRootKey;
|
|
167
|
-
/**
|
|
168
|
-
* @param address is an address of an issuer
|
|
169
|
-
* @param validityPeriod validity period of a generated self-signed
|
|
170
|
-
* certificate in seconds
|
|
171
|
-
* @param rootJKey root key in json format
|
|
172
|
-
* @param random
|
|
173
|
-
* @param arrFactory optional array factory
|
|
174
|
-
* @return Generated provider's key and a certificate for a respective
|
|
175
|
-
* public key.
|
|
176
|
-
*/
|
|
177
|
-
function generateProviderKey(address, validityPeriod, rootJKey, random, arrFactory) {
|
|
178
|
-
if (validityPeriod < 1) {
|
|
179
|
-
throw new Error(`Illegal validity period: ${validityPeriod}`);
|
|
180
|
-
}
|
|
181
|
-
const rootKey = (0, jwkeys_1.keyFromJson)(rootJKey, exports.KEY_USE.ROOT, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.SECRET_KEY_LENGTH);
|
|
182
|
-
const provPair = genSignKeyPair(exports.KEY_USE.PROVIDER, idProvider.KID_BYTES_LENGTH, random, arrFactory);
|
|
183
|
-
const now = Math.floor(Date.now() / 1000);
|
|
184
|
-
const rootCert = makeCert(provPair.pkey, address, address, now, now + validityPeriod, rootKey, arrFactory);
|
|
185
|
-
return { cert: rootCert, skey: (0, jwkeys_1.keyToJson)(provPair.skey) };
|
|
186
|
-
}
|
|
187
|
-
idProvider.generateProviderKey = generateProviderKey;
|
|
188
|
-
/**
|
|
189
|
-
* @param issuer is a domain of certificate issuer, at which issuer's public
|
|
190
|
-
* key can be found to check the signature
|
|
191
|
-
* @param validityPeriod is a default validity period in seconds, for
|
|
192
|
-
* which certifier shall be making certificates
|
|
193
|
-
* @param signJKey is a certificates signing key
|
|
194
|
-
* @param arrFactory is an optional array factory
|
|
195
|
-
* @return MailerId certificates generator, which shall be used on identity
|
|
196
|
-
* provider's side
|
|
197
|
-
*/
|
|
198
|
-
function makeIdProviderCertifier(issuer, validityPeriod, signJKey, arrFactory) {
|
|
199
|
-
if (!issuer) {
|
|
200
|
-
throw new Error(`Given issuer is illegal: ${issuer}`);
|
|
201
|
-
}
|
|
202
|
-
if ((validityPeriod < 1) || (validityPeriod > idProvider.MAX_USER_CERT_VALIDITY)) {
|
|
203
|
-
throw new Error(`Given certificate validity is illegal: ${validityPeriod}`);
|
|
204
|
-
}
|
|
205
|
-
let signKey = (0, jwkeys_1.keyFromJson)(signJKey, exports.KEY_USE.PROVIDER, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.SECRET_KEY_LENGTH);
|
|
206
|
-
signJKey = undefined;
|
|
207
|
-
if (!arrFactory) {
|
|
208
|
-
arrFactory = ecma_nacl_1.arrays.makeFactory();
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
certify: (publicKey, address, validFor) => {
|
|
212
|
-
if (!signKey) {
|
|
213
|
-
throw new Error(`Certifier is already destroyed.`);
|
|
214
|
-
}
|
|
215
|
-
if (publicKey.use !== exports.KEY_USE.SIGN) {
|
|
216
|
-
throw new Error(`Given public key has use ${publicKey.use} and cannot be used for signing.`);
|
|
217
|
-
}
|
|
218
|
-
if ('number' === typeof validFor) {
|
|
219
|
-
if (validFor > validityPeriod) {
|
|
220
|
-
validFor = validityPeriod;
|
|
221
|
-
}
|
|
222
|
-
else if (validFor < 0) {
|
|
223
|
-
new Error(`Given certificate validity is illegal: ${validFor}`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
validFor = validityPeriod;
|
|
228
|
-
}
|
|
229
|
-
const now = Math.floor(Date.now() / 1000);
|
|
230
|
-
return makeCert(publicKey, address, issuer, now, now + validFor, signKey, arrFactory);
|
|
231
|
-
},
|
|
232
|
-
destroy: () => {
|
|
233
|
-
if (!signKey) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
ecma_nacl_1.arrays.wipe(signKey.k);
|
|
237
|
-
signKey = undefined;
|
|
238
|
-
arrFactory.wipeRecycled();
|
|
239
|
-
arrFactory = undefined;
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
idProvider.makeIdProviderCertifier = makeIdProviderCertifier;
|
|
244
|
-
})(idProvider || (exports.idProvider = idProvider = {}));
|
|
245
|
-
Object.freeze(idProvider);
|
|
246
|
-
var relyingParty;
|
|
247
|
-
(function (relyingParty) {
|
|
248
|
-
const minValidityPeriodForCert = 20 * 60;
|
|
249
|
-
function verifyCertAndGetPubKey(signedCert, use, validAt, arrFactory, issuer, issuerPKey) {
|
|
250
|
-
const cert = (0, jwkeys_1.getKeyCert)(signedCert);
|
|
251
|
-
if ((validAt < (cert.issuedAt - minValidityPeriodForCert))
|
|
252
|
-
|| (cert.expiresAt <= validAt)) {
|
|
253
|
-
throw makeTimeMismatchException(`Certificate is not valid at a given moment ${validAt}, cause it is issued at ${cert.issuedAt}, and expires at ${cert.expiresAt}`);
|
|
254
|
-
}
|
|
255
|
-
if (issuer) {
|
|
256
|
-
if (!issuerPKey) {
|
|
257
|
-
throw new Error(`No issuer key given.`);
|
|
258
|
-
}
|
|
259
|
-
if ((cert.issuer !== issuer) ||
|
|
260
|
-
(signedCert.kid !== issuerPKey.kid)) {
|
|
261
|
-
throw makeCertsMismatchException(`Certificate is not signed by issuer key.`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
let pkey;
|
|
265
|
-
let sig;
|
|
266
|
-
let load;
|
|
267
|
-
try {
|
|
268
|
-
pkey = (0, jwkeys_1.keyFromJson)(cert.cert.publicKey, use, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.PUBLIC_KEY_LENGTH);
|
|
269
|
-
sig = buffer_utils_1.base64.open(signedCert.sig);
|
|
270
|
-
load = buffer_utils_1.base64.open(signedCert.load);
|
|
271
|
-
}
|
|
272
|
-
catch (err) {
|
|
273
|
-
throw makeMalformedCertsException(`Cannot read certificate`, err);
|
|
274
|
-
}
|
|
275
|
-
const pk = (issuer ? issuerPKey.k : pkey.k);
|
|
276
|
-
const certOK = ecma_nacl_1.signing.verify(sig, load, pk, arrFactory);
|
|
277
|
-
if (!certOK) {
|
|
278
|
-
throw makeSigVerifException(`Certificate ${use} failed validation.`);
|
|
279
|
-
}
|
|
280
|
-
return { pkey: pkey, address: cert.cert.principal.address };
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* @param certs is a chain of certificate to be verified.
|
|
284
|
-
* @param rootAddr is MailerId service's domain.
|
|
285
|
-
* @param validAt is an epoch time moment (in second), at which user
|
|
286
|
-
* certificate must be valid. Provider certificate must be valid at
|
|
287
|
-
* creation of user's certificate. Root certificate must be valid at
|
|
288
|
-
* creation of provider's certificate.
|
|
289
|
-
* @return user's MailerId signing key with user's address.
|
|
290
|
-
*/
|
|
291
|
-
function verifyChainAndGetUserKey(certs, rootAddr, validAt, arrFactory) {
|
|
292
|
-
// root certificate must be valid when provider's certificate was issued
|
|
293
|
-
let rootValidityMoment;
|
|
294
|
-
try {
|
|
295
|
-
rootValidityMoment = (0, jwkeys_1.getKeyCert)(certs.prov).issuedAt;
|
|
296
|
-
}
|
|
297
|
-
catch (err) {
|
|
298
|
-
throw makeMalformedCertsException(`Provider's certificate is malformed`, err);
|
|
299
|
-
}
|
|
300
|
-
// check root and get the key
|
|
301
|
-
const root = verifyCertAndGetPubKey(certs.root, exports.KEY_USE.ROOT, rootValidityMoment, arrFactory);
|
|
302
|
-
if (rootAddr !== root.address) {
|
|
303
|
-
throw makeCertsMismatchException(`Root certificate address ${root.address} doesn't match expected address ${rootAddr}`);
|
|
304
|
-
}
|
|
305
|
-
// provider's certificate must be valid when user's certificate was issued
|
|
306
|
-
let provValidityMoment;
|
|
307
|
-
try {
|
|
308
|
-
provValidityMoment = (0, jwkeys_1.getKeyCert)(certs.user).issuedAt;
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
throw makeMalformedCertsException(`User's certificate is malformed`, err);
|
|
312
|
-
}
|
|
313
|
-
// check provider and get the key
|
|
314
|
-
const provider = verifyCertAndGetPubKey(certs.prov, exports.KEY_USE.PROVIDER, provValidityMoment, arrFactory, root.address, root.pkey);
|
|
315
|
-
// check that provider cert comes from the same issuer as root
|
|
316
|
-
if (root.address !== provider.address) {
|
|
317
|
-
throw makeCertsMismatchException(`Provider's certificate address ${provider.address} doesn't match expected address ${root.address}.`);
|
|
318
|
-
}
|
|
319
|
-
// check user certificate and get the key
|
|
320
|
-
return verifyCertAndGetPubKey(certs.user, exports.KEY_USE.SIGN, validAt, arrFactory, provider.address, provider.pkey);
|
|
321
|
-
}
|
|
322
|
-
relyingParty.verifyChainAndGetUserKey = verifyChainAndGetUserKey;
|
|
323
|
-
function verifyAssertion(midAssertion, certChain, rootAddr, validAt, arrFactory) {
|
|
324
|
-
const userInfo = verifyChainAndGetUserKey(certChain, rootAddr, validAt, arrFactory);
|
|
325
|
-
let loadBytes;
|
|
326
|
-
let sigBytes;
|
|
327
|
-
let assertion;
|
|
328
|
-
try {
|
|
329
|
-
loadBytes = buffer_utils_1.base64.open(midAssertion.load);
|
|
330
|
-
sigBytes = buffer_utils_1.base64.open(midAssertion.sig);
|
|
331
|
-
assertion = JSON.parse(buffer_utils_1.utf8.open(loadBytes));
|
|
332
|
-
}
|
|
333
|
-
catch (err) {
|
|
334
|
-
throw makeMalformedCertsException(`Cannot read assertion`, err);
|
|
335
|
-
}
|
|
336
|
-
if (!ecma_nacl_1.signing.verify(sigBytes, loadBytes, userInfo.pkey.k, arrFactory)) {
|
|
337
|
-
throw makeSigVerifException(`Assertion fails verification.`);
|
|
338
|
-
}
|
|
339
|
-
if (assertion.user !== userInfo.address) {
|
|
340
|
-
throw makeMalformedCertsException(`Assertion is for one user, while chain is for another.`);
|
|
341
|
-
}
|
|
342
|
-
if (!assertion.sessionId) {
|
|
343
|
-
throw makeMalformedCertsException(`Assertion doesn't have session id.`);
|
|
344
|
-
}
|
|
345
|
-
// Note that assertion can be valid before issue time, to counter
|
|
346
|
-
// some mis-synchronization of clocks.
|
|
347
|
-
// It can be some fixed value, like minimum validity period of certs.
|
|
348
|
-
if (Math.abs(validAt - assertion.issuedAt) >
|
|
349
|
-
(assertion.expiresAt - assertion.issuedAt)) {
|
|
350
|
-
throw makeTimeMismatchException(`Assertion is not valid at ${validAt}, being issued at ${assertion.expiresAt} and expiring at ${assertion.expiresAt}.`);
|
|
351
|
-
}
|
|
352
|
-
return {
|
|
353
|
-
sessionId: assertion.sessionId,
|
|
354
|
-
relyingPartyDomain: assertion.rpDomain,
|
|
355
|
-
user: userInfo.address
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
relyingParty.verifyAssertion = verifyAssertion;
|
|
359
|
-
/**
|
|
360
|
-
* This function does verification of a single certificate with known
|
|
361
|
-
* signing key.
|
|
362
|
-
* If your task requires verification starting with principal's MailerId,
|
|
363
|
-
* use verifyPubKey function that also accepts and checks MailerId
|
|
364
|
-
* certificates chain.
|
|
365
|
-
* @param keyCert is a certificate that should be checked
|
|
366
|
-
* @param principalAddress is an expected principal's address in a given
|
|
367
|
-
* certificate. Exception is thrown, if certificate does not match this
|
|
368
|
-
* expectation.
|
|
369
|
-
* @param signingKey is a public key, with which given certificate is
|
|
370
|
-
* validated cryptographically. Exception is thrown, if crypto-verification
|
|
371
|
-
* fails.
|
|
372
|
-
* @param validAt is an epoch time moment (in second), for which verification
|
|
373
|
-
* should be done.
|
|
374
|
-
* @param arrFactory is an optional array factory.
|
|
375
|
-
* @return a key from a given certificate.
|
|
376
|
-
*/
|
|
377
|
-
function verifyKeyCert(keyCert, principalAddress, signingKey, validAt, arrFactory) {
|
|
378
|
-
let sigBytes;
|
|
379
|
-
let loadBytes;
|
|
380
|
-
try {
|
|
381
|
-
sigBytes = buffer_utils_1.base64.open(keyCert.sig);
|
|
382
|
-
loadBytes = buffer_utils_1.base64.open(keyCert.load);
|
|
383
|
-
}
|
|
384
|
-
catch (err) {
|
|
385
|
-
throw makeMalformedCertsException(`Cannot read certificate`, err);
|
|
386
|
-
}
|
|
387
|
-
if (!ecma_nacl_1.signing.verify(sigBytes, loadBytes, signingKey.k, arrFactory)) {
|
|
388
|
-
throw makeSigVerifException(`Key certificate fails verification.`);
|
|
389
|
-
}
|
|
390
|
-
let cert;
|
|
391
|
-
try {
|
|
392
|
-
cert = (0, jwkeys_1.getKeyCert)(keyCert);
|
|
393
|
-
}
|
|
394
|
-
catch (err) {
|
|
395
|
-
throw makeMalformedCertsException(`Cannot read certificate`, err);
|
|
396
|
-
}
|
|
397
|
-
if (cert.cert.principal.address !== principalAddress) {
|
|
398
|
-
throw makeCertsMismatchException(`Key certificate is for user ${cert.cert.principal.address}, while expected address is ${principalAddress}`);
|
|
399
|
-
}
|
|
400
|
-
if ((cert.expiresAt - cert.issuedAt) <= minValidityPeriodForCert) {
|
|
401
|
-
if (Math.abs(cert.issuedAt - validAt) > minValidityPeriodForCert) {
|
|
402
|
-
throw makeTimeMismatchException(`Certificate is not valid at ${validAt} being issued at ${cert.issuedAt} and applying minimum validity period window of ${minValidityPeriodForCert} seconds`);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
if ((validAt < (cert.issuedAt - minValidityPeriodForCert))
|
|
407
|
-
|| (cert.expiresAt <= validAt)) {
|
|
408
|
-
throw makeTimeMismatchException(`Certificate is not valid at ${validAt} being issued at ${cert.issuedAt} and expiring at ${cert.expiresAt}`);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return cert.cert.publicKey;
|
|
412
|
-
}
|
|
413
|
-
relyingParty.verifyKeyCert = verifyKeyCert;
|
|
414
|
-
/**
|
|
415
|
-
* @param pubKeyCert certificate with a public key, that needs to be
|
|
416
|
-
* verified.
|
|
417
|
-
* @param principalAddress is an expected principal's address in both key
|
|
418
|
-
* certificate, and in MailerId certificate chain. Exception is thrown,
|
|
419
|
-
* if certificate does not match this expectation.
|
|
420
|
-
* @param certChain is MailerId certificate chain for named principal.
|
|
421
|
-
* @param rootAddr is MailerId root's domain.
|
|
422
|
-
* @param validAt is an epoch time moment (in second), for which key
|
|
423
|
-
* certificate verification should be done.
|
|
424
|
-
* @param arrFactory is an optional array factory.
|
|
425
|
-
* @return a key from a given certificate.
|
|
426
|
-
*/
|
|
427
|
-
function verifyPubKey(pubKeyCert, principalAddress, certChain, rootAddr, validAt, arrFactory) {
|
|
428
|
-
// time moment, for which user's certificate chain must be valid
|
|
429
|
-
let chainValidityMoment;
|
|
430
|
-
try {
|
|
431
|
-
chainValidityMoment = (0, jwkeys_1.getKeyCert)(pubKeyCert).issuedAt;
|
|
432
|
-
}
|
|
433
|
-
catch (err) {
|
|
434
|
-
throw makeMalformedCertsException(`Cannot read certificate`, err);
|
|
435
|
-
}
|
|
436
|
-
const principalInfo = verifyChainAndGetUserKey(certChain, rootAddr, chainValidityMoment, arrFactory);
|
|
437
|
-
if (principalInfo.address !== principalAddress) {
|
|
438
|
-
throw makeCertsMismatchException(`MailerId certificate chain is for user ${principalInfo.address}, while expected address is ${principalAddress}`);
|
|
439
|
-
}
|
|
440
|
-
return verifyKeyCert(pubKeyCert, principalAddress, principalInfo.pkey, validAt, arrFactory);
|
|
441
|
-
}
|
|
442
|
-
relyingParty.verifyPubKey = verifyPubKey;
|
|
443
|
-
})(relyingParty || (exports.relyingParty = relyingParty = {}));
|
|
444
|
-
Object.freeze(relyingParty);
|
|
445
|
-
function correlateSKeyWithItsCert(skey, cert) {
|
|
446
|
-
const pkey = (0, jwkeys_1.keyFromJson)(cert.cert.publicKey, skey.use, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.PUBLIC_KEY_LENGTH);
|
|
447
|
-
if (!((pkey.kid === skey.kid)
|
|
448
|
-
&& (pkey.use === skey.use)
|
|
449
|
-
&& (pkey.alg === skey.alg)
|
|
450
|
-
&& (0, ecma_nacl_1.compareVectors)(ecma_nacl_1.signing.extract_pkey(skey.k), pkey.k))) {
|
|
451
|
-
throw new Error("Key does not correspond to certificate.");
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
var user;
|
|
455
|
-
(function (user) {
|
|
456
|
-
user.KID_BYTES_LENGTH = 9;
|
|
457
|
-
user.MAX_SIG_VALIDITY = 30 * 60;
|
|
458
|
-
function generateSigningKeyPair(random, arrFactory) {
|
|
459
|
-
return genSignKeyPair(exports.KEY_USE.SIGN, user.KID_BYTES_LENGTH, random, arrFactory);
|
|
460
|
-
}
|
|
461
|
-
user.generateSigningKeyPair = generateSigningKeyPair;
|
|
462
|
-
/**
|
|
463
|
-
* @param signKey which will be used to sign assertions/keys. Note that
|
|
464
|
-
* this key shall be wiped, when signer is destroyed, as key is neither
|
|
465
|
-
* long-living, nor should be shared.
|
|
466
|
-
* @param cert is user's certificate, signed by identity provider.
|
|
467
|
-
* @param provCert is provider's certificate, signed by respective mid root.
|
|
468
|
-
* @param assertionValidity is an assertion validity period in seconds
|
|
469
|
-
* @param arrFactory is an optional array factory
|
|
470
|
-
* @return signer for user of MailerId to generate assertions, and to sign
|
|
471
|
-
* keys.
|
|
472
|
-
*/
|
|
473
|
-
function makeMailerIdSigner(signKey, userCert, provCert, assertionValidity = user.MAX_SIG_VALIDITY, arrFactory) {
|
|
474
|
-
const certificate = (0, jwkeys_1.getKeyCert)(userCert);
|
|
475
|
-
if (signKey.use !== exports.KEY_USE.SIGN) {
|
|
476
|
-
throw new Error(`Given key ${signKey.kid} has incorrect use: ${signKey.use}`);
|
|
477
|
-
}
|
|
478
|
-
correlateSKeyWithItsCert(signKey, certificate);
|
|
479
|
-
if (('number' !== typeof assertionValidity) || (assertionValidity < 1) ||
|
|
480
|
-
(assertionValidity > user.MAX_SIG_VALIDITY)) {
|
|
481
|
-
throw new Error(`Given assertion validity is illegal: ${assertionValidity}`);
|
|
482
|
-
}
|
|
483
|
-
if (!arrFactory) {
|
|
484
|
-
arrFactory = ecma_nacl_1.arrays.makeFactory();
|
|
485
|
-
}
|
|
486
|
-
const signer = {
|
|
487
|
-
address: certificate.cert.principal.address,
|
|
488
|
-
userCert: userCert,
|
|
489
|
-
providerCert: provCert,
|
|
490
|
-
issuer: certificate.issuer,
|
|
491
|
-
certExpiresAt: certificate.expiresAt,
|
|
492
|
-
validityPeriod: assertionValidity,
|
|
493
|
-
generateAssertionFor: (rpDomain, sessionId, validFor) => {
|
|
494
|
-
if (!signKey) {
|
|
495
|
-
throw new Error("Signer is already destroyed.");
|
|
496
|
-
}
|
|
497
|
-
if ('number' === typeof validFor) {
|
|
498
|
-
if (validFor > assertionValidity) {
|
|
499
|
-
validFor = assertionValidity;
|
|
500
|
-
}
|
|
501
|
-
else if (validFor < 0) {
|
|
502
|
-
new Error(`Given certificate validity is illegal: ${validFor}`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
validFor = assertionValidity;
|
|
507
|
-
}
|
|
508
|
-
let now = Math.floor(Date.now() / 1000);
|
|
509
|
-
if (now <= certificate.issuedAt) {
|
|
510
|
-
now = certificate.issuedAt + 1;
|
|
511
|
-
}
|
|
512
|
-
if (now >= certificate.expiresAt) {
|
|
513
|
-
throw new Error(`Signing key has already expiried at ${certificate.expiresAt} and now is ${now}`);
|
|
514
|
-
}
|
|
515
|
-
const assertion = {
|
|
516
|
-
rpDomain: rpDomain,
|
|
517
|
-
sessionId: sessionId,
|
|
518
|
-
user: certificate.cert.principal.address,
|
|
519
|
-
issuedAt: now,
|
|
520
|
-
expiresAt: now + validFor
|
|
521
|
-
};
|
|
522
|
-
const assertionBytes = buffer_utils_1.utf8.pack(JSON.stringify(assertion));
|
|
523
|
-
const sigBytes = ecma_nacl_1.signing.signature(assertionBytes, signKey.k, arrFactory);
|
|
524
|
-
return {
|
|
525
|
-
alg: signKey.alg,
|
|
526
|
-
kid: signKey.kid,
|
|
527
|
-
sig: buffer_utils_1.base64.pack(sigBytes),
|
|
528
|
-
load: buffer_utils_1.base64.pack(assertionBytes)
|
|
529
|
-
};
|
|
530
|
-
},
|
|
531
|
-
certifyPublicKey: (pkey, validFor) => {
|
|
532
|
-
if (!signKey) {
|
|
533
|
-
throw new Error("Signer is already destroyed.");
|
|
534
|
-
}
|
|
535
|
-
if (validFor < 0) {
|
|
536
|
-
new Error(`Given certificate validity is illegal: ${validFor}`);
|
|
537
|
-
}
|
|
538
|
-
const now = Math.floor(Date.now() / 1000);
|
|
539
|
-
if (now >= certificate.expiresAt) {
|
|
540
|
-
throw new Error(`Signing key has already expiried at ${certificate.expiresAt} and now is ${now}`);
|
|
541
|
-
}
|
|
542
|
-
return makeCert(pkey, certificate.cert.principal.address, certificate.cert.principal.address, now, now + validFor, signKey, arrFactory);
|
|
543
|
-
},
|
|
544
|
-
destroy: () => {
|
|
545
|
-
if (!signKey) {
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
ecma_nacl_1.arrays.wipe(signKey.k);
|
|
549
|
-
signKey = undefined;
|
|
550
|
-
arrFactory.wipeRecycled();
|
|
551
|
-
arrFactory = undefined;
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
Object.freeze(signer);
|
|
555
|
-
return signer;
|
|
556
|
-
}
|
|
557
|
-
user.makeMailerIdSigner = makeMailerIdSigner;
|
|
558
|
-
})(user || (exports.user = user = {}));
|
|
559
|
-
Object.freeze(user);
|
|
560
|
-
Object.freeze(exports);
|