core-3nweb-client-lib 0.40.1 → 0.41.1
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/files.d.ts +1 -0
- 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-client/xsp-fs/folder-node.js +3 -0
- 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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
type JsonKey = web3n.keys.JsonKey;
|
|
2
|
+
type Key = web3n.keys.Key;
|
|
3
|
+
type SignedLoad = web3n.keys.SignedLoad;
|
|
4
|
+
type MailerIdException = web3n.mailerid.MailerIdException;
|
|
5
|
+
/**
|
|
6
|
+
* This enumerates MailerId's different use-roles of keys, involved in
|
|
7
|
+
* establishing a trust.
|
|
8
|
+
*/
|
|
9
|
+
export declare const KEY_USE: {
|
|
10
|
+
/**
|
|
11
|
+
* This is a MailerId trust root.
|
|
12
|
+
* It signs certificate for itself, and it signs certificates for provider
|
|
13
|
+
* keys, which have shorter life span, than the root.
|
|
14
|
+
* Root may revoke itself, and may revoke provider key.
|
|
15
|
+
*/
|
|
16
|
+
ROOT: string;
|
|
17
|
+
/**
|
|
18
|
+
* This is a provider key, which is used to certify users' signing keys.
|
|
19
|
+
*/
|
|
20
|
+
PROVIDER: string;
|
|
21
|
+
/**
|
|
22
|
+
* With this key, MailerId user signs assertions and mail keys.
|
|
23
|
+
*/
|
|
24
|
+
SIGN: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function makeMailerIdException(flags: Partial<MailerIdException>, params: Partial<MailerIdException>): MailerIdException;
|
|
27
|
+
export declare function makeMalformedCertsException(message: string, cause?: any): MailerIdException;
|
|
28
|
+
export interface Keypair {
|
|
29
|
+
pkey: JsonKey;
|
|
30
|
+
skey: Key;
|
|
31
|
+
}
|
|
32
|
+
export interface AssertionLoad {
|
|
33
|
+
user: string;
|
|
34
|
+
rpDomain: string;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
issuedAt: number;
|
|
37
|
+
expiresAt: number;
|
|
38
|
+
}
|
|
39
|
+
export interface CertsChain {
|
|
40
|
+
user: SignedLoad;
|
|
41
|
+
prov: SignedLoad;
|
|
42
|
+
root: SignedLoad;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
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.KEY_USE = void 0;
|
|
20
|
+
exports.makeMailerIdException = makeMailerIdException;
|
|
21
|
+
exports.makeMalformedCertsException = makeMalformedCertsException;
|
|
22
|
+
const runtime_1 = require("../exceptions/runtime");
|
|
23
|
+
/**
|
|
24
|
+
* This enumerates MailerId's different use-roles of keys, involved in
|
|
25
|
+
* establishing a trust.
|
|
26
|
+
*/
|
|
27
|
+
exports.KEY_USE = {
|
|
28
|
+
/**
|
|
29
|
+
* This is a MailerId trust root.
|
|
30
|
+
* It signs certificate for itself, and it signs certificates for provider
|
|
31
|
+
* keys, which have shorter life span, than the root.
|
|
32
|
+
* Root may revoke itself, and may revoke provider key.
|
|
33
|
+
*/
|
|
34
|
+
ROOT: "mid-root",
|
|
35
|
+
/**
|
|
36
|
+
* This is a provider key, which is used to certify users' signing keys.
|
|
37
|
+
*/
|
|
38
|
+
PROVIDER: "mid-provider",
|
|
39
|
+
/**
|
|
40
|
+
* With this key, MailerId user signs assertions and mail keys.
|
|
41
|
+
*/
|
|
42
|
+
SIGN: "mid-sign",
|
|
43
|
+
};
|
|
44
|
+
Object.freeze(exports.KEY_USE);
|
|
45
|
+
function makeMailerIdException(flags, params) {
|
|
46
|
+
return (0, runtime_1.makeRuntimeException)('mailerid', params, flags);
|
|
47
|
+
}
|
|
48
|
+
function makeMalformedCertsException(message, cause) {
|
|
49
|
+
return makeMailerIdException({ certMalformed: true }, { message, cause });
|
|
50
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { arrays } from "ecma-nacl";
|
|
2
|
+
import { CertsChain } from "./index";
|
|
3
|
+
type JsonKey = web3n.keys.JsonKey;
|
|
4
|
+
type Key = web3n.keys.Key;
|
|
5
|
+
type SignedLoad = web3n.keys.SignedLoad;
|
|
6
|
+
/**
|
|
7
|
+
* @param certs is a chain of certificate to be verified.
|
|
8
|
+
* @param rootAddr is MailerId service's domain.
|
|
9
|
+
* @param validAt is an epoch time moment (in second), at which user
|
|
10
|
+
* certificate must be valid. Provider certificate must be valid at
|
|
11
|
+
* creation of user's certificate. Root certificate must be valid at
|
|
12
|
+
* creation of provider's certificate.
|
|
13
|
+
* @return user's MailerId signing key with user's address.
|
|
14
|
+
*/
|
|
15
|
+
export declare function verifyChainAndGetUserKey(certs: CertsChain, rootAddr: string, validAt: number, arrFactory?: arrays.Factory): {
|
|
16
|
+
pkey: Key;
|
|
17
|
+
address: string;
|
|
18
|
+
};
|
|
19
|
+
export interface AssertionInfo {
|
|
20
|
+
relyingPartyDomain: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
user: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function verifyAssertion(midAssertion: SignedLoad, certChain: CertsChain, rootAddr: string, validAt: number, arrFactory?: arrays.Factory): AssertionInfo;
|
|
25
|
+
/**
|
|
26
|
+
* This function does verification of a single certificate with known
|
|
27
|
+
* signing key.
|
|
28
|
+
* If your task requires verification starting with principal's MailerId,
|
|
29
|
+
* use verifyPubKey function that also accepts and checks MailerId
|
|
30
|
+
* certificates chain.
|
|
31
|
+
* @param keyCert is a certificate that should be checked
|
|
32
|
+
* @param principalAddress is an expected principal's address in a given
|
|
33
|
+
* certificate. Exception is thrown, if certificate does not match this
|
|
34
|
+
* expectation.
|
|
35
|
+
* @param signingKey is a public key, with which given certificate is
|
|
36
|
+
* validated cryptographically. Exception is thrown, if crypto-verification
|
|
37
|
+
* fails.
|
|
38
|
+
* @param validAt is an epoch time moment (in second), for which verification
|
|
39
|
+
* should be done.
|
|
40
|
+
* @param arrFactory is an optional array factory.
|
|
41
|
+
* @return a key from a given certificate.
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyKeyCert(keyCert: SignedLoad, principalAddress: string, signingKey: Key, validAt: number, arrFactory?: arrays.Factory): JsonKey;
|
|
44
|
+
/**
|
|
45
|
+
* @param pubKeyCert certificate with a public key, that needs to be
|
|
46
|
+
* verified.
|
|
47
|
+
* @param principalAddress is an expected principal's address in both key
|
|
48
|
+
* certificate, and in MailerId certificate chain. Exception is thrown,
|
|
49
|
+
* if certificate does not match this expectation.
|
|
50
|
+
* @param certChain is MailerId certificate chain for named principal.
|
|
51
|
+
* @param rootAddr is MailerId root's domain.
|
|
52
|
+
* @param validAt is an epoch time moment (in second), for which key
|
|
53
|
+
* certificate verification should be done.
|
|
54
|
+
* @param arrFactory is an optional array factory.
|
|
55
|
+
* @return a key from a given certificate.
|
|
56
|
+
*/
|
|
57
|
+
export declare function verifyPubKey(pubKeyCert: SignedLoad, principalAddress: string, certChain: CertsChain, rootAddr: string, validAt: number, arrFactory?: arrays.Factory): JsonKey;
|
|
58
|
+
export declare function verifySignature(root: SignedLoad, prov: SignedLoad, user: SignedLoad, signature: SignedLoad, arrFactory?: arrays.Factory): boolean;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,237 @@
|
|
|
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.verifyChainAndGetUserKey = verifyChainAndGetUserKey;
|
|
20
|
+
exports.verifyAssertion = verifyAssertion;
|
|
21
|
+
exports.verifyKeyCert = verifyKeyCert;
|
|
22
|
+
exports.verifyPubKey = verifyPubKey;
|
|
23
|
+
exports.verifySignature = verifySignature;
|
|
24
|
+
const ecma_nacl_1 = require("ecma-nacl");
|
|
25
|
+
const jwkeys_1 = require("../jwkeys");
|
|
26
|
+
const buffer_utils_1 = require("../buffer-utils");
|
|
27
|
+
const index_1 = require("./index");
|
|
28
|
+
function makeTimeMismatchException(message) {
|
|
29
|
+
return (0, index_1.makeMailerIdException)({ timeMismatch: true }, { message });
|
|
30
|
+
}
|
|
31
|
+
function makeCertsMismatchException(message) {
|
|
32
|
+
return (0, index_1.makeMailerIdException)({ certsMismatch: true }, { message });
|
|
33
|
+
}
|
|
34
|
+
function makeSigVerifException(message) {
|
|
35
|
+
return (0, index_1.makeMailerIdException)({ sigVerificationFails: true }, { message });
|
|
36
|
+
}
|
|
37
|
+
const minValidityPeriodForCert = 20 * 60;
|
|
38
|
+
function verifyCertAndGetPubKey(signedCert, use, validAt, arrFactory, issuer, issuerPKey) {
|
|
39
|
+
const cert = (0, jwkeys_1.getKeyCert)(signedCert);
|
|
40
|
+
if ((validAt < (cert.issuedAt - minValidityPeriodForCert))
|
|
41
|
+
|| (cert.expiresAt <= validAt)) {
|
|
42
|
+
throw (0, index_1.makeMailerIdException)({ timeMismatch: true }, { message: `Certificate is not valid at a given moment ${validAt}, cause it is issued at ${cert.issuedAt}, and expires at ${cert.expiresAt}` });
|
|
43
|
+
}
|
|
44
|
+
if (issuer) {
|
|
45
|
+
if (!issuerPKey) {
|
|
46
|
+
throw new Error(`No issuer key given.`);
|
|
47
|
+
}
|
|
48
|
+
if ((cert.issuer !== issuer) || (signedCert.kid !== issuerPKey.kid)) {
|
|
49
|
+
throw makeCertsMismatchException(`Certificate is not signed by issuer key.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let pkey;
|
|
53
|
+
let sig;
|
|
54
|
+
let load;
|
|
55
|
+
try {
|
|
56
|
+
pkey = (0, jwkeys_1.keyFromJson)(cert.cert.publicKey, use, ecma_nacl_1.signing.JWK_ALG_NAME, ecma_nacl_1.signing.PUBLIC_KEY_LENGTH);
|
|
57
|
+
sig = buffer_utils_1.base64.open(signedCert.sig);
|
|
58
|
+
load = buffer_utils_1.base64.open(signedCert.load);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw (0, index_1.makeMalformedCertsException)(`Cannot read certificate`, err);
|
|
62
|
+
}
|
|
63
|
+
const pk = (issuer ? issuerPKey.k : pkey.k);
|
|
64
|
+
const certOK = ecma_nacl_1.signing.verify(sig, load, pk, arrFactory);
|
|
65
|
+
if (!certOK) {
|
|
66
|
+
throw makeSigVerifException(`Certificate ${use} failed validation.`);
|
|
67
|
+
}
|
|
68
|
+
return { pkey: pkey, address: cert.cert.principal.address };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @param certs is a chain of certificate to be verified.
|
|
72
|
+
* @param rootAddr is MailerId service's domain.
|
|
73
|
+
* @param validAt is an epoch time moment (in second), at which user
|
|
74
|
+
* certificate must be valid. Provider certificate must be valid at
|
|
75
|
+
* creation of user's certificate. Root certificate must be valid at
|
|
76
|
+
* creation of provider's certificate.
|
|
77
|
+
* @return user's MailerId signing key with user's address.
|
|
78
|
+
*/
|
|
79
|
+
function verifyChainAndGetUserKey(certs, rootAddr, validAt, arrFactory) {
|
|
80
|
+
// root certificate must be valid when provider's certificate was issued
|
|
81
|
+
let rootValidityMoment;
|
|
82
|
+
try {
|
|
83
|
+
rootValidityMoment = (0, jwkeys_1.getKeyCert)(certs.prov).issuedAt;
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
throw (0, index_1.makeMalformedCertsException)(`Provider's certificate is malformed`, err);
|
|
87
|
+
}
|
|
88
|
+
// check root and get the key
|
|
89
|
+
const root = verifyCertAndGetPubKey(certs.root, index_1.KEY_USE.ROOT, rootValidityMoment, arrFactory);
|
|
90
|
+
if (rootAddr !== root.address) {
|
|
91
|
+
throw makeCertsMismatchException(`Root certificate address ${root.address} doesn't match expected address ${rootAddr}`);
|
|
92
|
+
}
|
|
93
|
+
// provider's certificate must be valid when user's certificate was issued
|
|
94
|
+
let provValidityMoment;
|
|
95
|
+
try {
|
|
96
|
+
provValidityMoment = (0, jwkeys_1.getKeyCert)(certs.user).issuedAt;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
throw (0, index_1.makeMalformedCertsException)(`User's certificate is malformed`, err);
|
|
100
|
+
}
|
|
101
|
+
// check provider and get the key
|
|
102
|
+
const provider = verifyCertAndGetPubKey(certs.prov, index_1.KEY_USE.PROVIDER, provValidityMoment, arrFactory, root.address, root.pkey);
|
|
103
|
+
// check that provider cert comes from the same issuer as root
|
|
104
|
+
if (root.address !== provider.address) {
|
|
105
|
+
throw makeCertsMismatchException(`Provider's certificate address ${provider.address} doesn't match expected address ${root.address}.`);
|
|
106
|
+
}
|
|
107
|
+
// check user certificate and get the key
|
|
108
|
+
return verifyCertAndGetPubKey(certs.user, index_1.KEY_USE.SIGN, validAt, arrFactory, provider.address, provider.pkey);
|
|
109
|
+
}
|
|
110
|
+
function verifyAssertion(midAssertion, certChain, rootAddr, validAt, arrFactory) {
|
|
111
|
+
const userInfo = verifyChainAndGetUserKey(certChain, rootAddr, validAt, arrFactory);
|
|
112
|
+
let loadBytes;
|
|
113
|
+
let sigBytes;
|
|
114
|
+
let assertion;
|
|
115
|
+
try {
|
|
116
|
+
loadBytes = buffer_utils_1.base64.open(midAssertion.load);
|
|
117
|
+
sigBytes = buffer_utils_1.base64.open(midAssertion.sig);
|
|
118
|
+
assertion = JSON.parse(buffer_utils_1.utf8.open(loadBytes));
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
throw (0, index_1.makeMalformedCertsException)(`Cannot read assertion`, err);
|
|
122
|
+
}
|
|
123
|
+
if (!ecma_nacl_1.signing.verify(sigBytes, loadBytes, userInfo.pkey.k, arrFactory)) {
|
|
124
|
+
throw makeSigVerifException(`Assertion fails verification.`);
|
|
125
|
+
}
|
|
126
|
+
if (assertion.user !== userInfo.address) {
|
|
127
|
+
throw (0, index_1.makeMalformedCertsException)(`Assertion is for one user, while chain is for another.`);
|
|
128
|
+
}
|
|
129
|
+
if (!assertion.sessionId) {
|
|
130
|
+
throw (0, index_1.makeMalformedCertsException)(`Assertion doesn't have session id.`);
|
|
131
|
+
}
|
|
132
|
+
// Note that assertion can be valid before issue time, to counter
|
|
133
|
+
// some mis-synchronization of clocks.
|
|
134
|
+
// It can be some fixed value, like minimum validity period of certs.
|
|
135
|
+
if (Math.abs(validAt - assertion.issuedAt) > (assertion.expiresAt - assertion.issuedAt)) {
|
|
136
|
+
throw makeTimeMismatchException(`Assertion is not valid at ${validAt}, being issued at ${assertion.expiresAt} and expiring at ${assertion.expiresAt}.`);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
sessionId: assertion.sessionId,
|
|
140
|
+
relyingPartyDomain: assertion.rpDomain,
|
|
141
|
+
user: userInfo.address
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* This function does verification of a single certificate with known
|
|
146
|
+
* signing key.
|
|
147
|
+
* If your task requires verification starting with principal's MailerId,
|
|
148
|
+
* use verifyPubKey function that also accepts and checks MailerId
|
|
149
|
+
* certificates chain.
|
|
150
|
+
* @param keyCert is a certificate that should be checked
|
|
151
|
+
* @param principalAddress is an expected principal's address in a given
|
|
152
|
+
* certificate. Exception is thrown, if certificate does not match this
|
|
153
|
+
* expectation.
|
|
154
|
+
* @param signingKey is a public key, with which given certificate is
|
|
155
|
+
* validated cryptographically. Exception is thrown, if crypto-verification
|
|
156
|
+
* fails.
|
|
157
|
+
* @param validAt is an epoch time moment (in second), for which verification
|
|
158
|
+
* should be done.
|
|
159
|
+
* @param arrFactory is an optional array factory.
|
|
160
|
+
* @return a key from a given certificate.
|
|
161
|
+
*/
|
|
162
|
+
function verifyKeyCert(keyCert, principalAddress, signingKey, validAt, arrFactory) {
|
|
163
|
+
let sigBytes;
|
|
164
|
+
let loadBytes;
|
|
165
|
+
try {
|
|
166
|
+
sigBytes = buffer_utils_1.base64.open(keyCert.sig);
|
|
167
|
+
loadBytes = buffer_utils_1.base64.open(keyCert.load);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
throw (0, index_1.makeMalformedCertsException)(`Cannot read certificate`, err);
|
|
171
|
+
}
|
|
172
|
+
if (!ecma_nacl_1.signing.verify(sigBytes, loadBytes, signingKey.k, arrFactory)) {
|
|
173
|
+
throw makeSigVerifException(`Key certificate fails verification.`);
|
|
174
|
+
}
|
|
175
|
+
let cert;
|
|
176
|
+
try {
|
|
177
|
+
cert = (0, jwkeys_1.getKeyCert)(keyCert);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
throw (0, index_1.makeMalformedCertsException)(`Cannot read certificate`, err);
|
|
181
|
+
}
|
|
182
|
+
if (cert.cert.principal.address !== principalAddress) {
|
|
183
|
+
throw makeCertsMismatchException(`Key certificate is for user ${cert.cert.principal.address}, while expected address is ${principalAddress}`);
|
|
184
|
+
}
|
|
185
|
+
if ((cert.expiresAt - cert.issuedAt) <= minValidityPeriodForCert) {
|
|
186
|
+
if (Math.abs(cert.issuedAt - validAt) > minValidityPeriodForCert) {
|
|
187
|
+
throw makeTimeMismatchException(`Certificate is not valid at ${validAt} being issued at ${cert.issuedAt} and applying minimum validity period window of ${minValidityPeriodForCert} seconds`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
if ((validAt < (cert.issuedAt - minValidityPeriodForCert)) || (cert.expiresAt <= validAt)) {
|
|
192
|
+
throw makeTimeMismatchException(`Certificate is not valid at ${validAt} being issued at ${cert.issuedAt} and expiring at ${cert.expiresAt}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return cert.cert.publicKey;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* @param pubKeyCert certificate with a public key, that needs to be
|
|
199
|
+
* verified.
|
|
200
|
+
* @param principalAddress is an expected principal's address in both key
|
|
201
|
+
* certificate, and in MailerId certificate chain. Exception is thrown,
|
|
202
|
+
* if certificate does not match this expectation.
|
|
203
|
+
* @param certChain is MailerId certificate chain for named principal.
|
|
204
|
+
* @param rootAddr is MailerId root's domain.
|
|
205
|
+
* @param validAt is an epoch time moment (in second), for which key
|
|
206
|
+
* certificate verification should be done.
|
|
207
|
+
* @param arrFactory is an optional array factory.
|
|
208
|
+
* @return a key from a given certificate.
|
|
209
|
+
*/
|
|
210
|
+
function verifyPubKey(pubKeyCert, principalAddress, certChain, rootAddr, validAt, arrFactory) {
|
|
211
|
+
// time moment, for which user's certificate chain must be valid
|
|
212
|
+
let chainValidityMoment;
|
|
213
|
+
try {
|
|
214
|
+
chainValidityMoment = (0, jwkeys_1.getKeyCert)(pubKeyCert).issuedAt;
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
throw (0, index_1.makeMalformedCertsException)(`Cannot read certificate`, err);
|
|
218
|
+
}
|
|
219
|
+
const principalInfo = verifyChainAndGetUserKey(certChain, rootAddr, chainValidityMoment, arrFactory);
|
|
220
|
+
if (principalInfo.address !== principalAddress) {
|
|
221
|
+
throw makeCertsMismatchException(`MailerId certificate chain is for user ${principalInfo.address}, while expected address is ${principalAddress}`);
|
|
222
|
+
}
|
|
223
|
+
return verifyKeyCert(pubKeyCert, principalAddress, principalInfo.pkey, validAt, arrFactory);
|
|
224
|
+
}
|
|
225
|
+
function verifySignature(root, prov, user, signature, arrFactory) {
|
|
226
|
+
try {
|
|
227
|
+
const rootAddr = (0, jwkeys_1.getKeyCert)(root).cert.principal.address;
|
|
228
|
+
const validAt = (0, jwkeys_1.getKeyCert)(user).issuedAt + 60;
|
|
229
|
+
const signee = verifyChainAndGetUserKey({ prov, root, user }, rootAddr, validAt, arrFactory);
|
|
230
|
+
const sigBytes = buffer_utils_1.base64.open(signature.sig);
|
|
231
|
+
const loadBytes = buffer_utils_1.base64.open(signature.load);
|
|
232
|
+
return ecma_nacl_1.signing.verify(sigBytes, loadBytes, signee.pkey.k, arrFactory);
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { GetRandom, arrays } from "ecma-nacl";
|
|
2
|
+
import { Keypair } from "./index";
|
|
3
|
+
type JsonKey = web3n.keys.JsonKey;
|
|
4
|
+
type Key = web3n.keys.Key;
|
|
5
|
+
type SignedLoad = web3n.keys.SignedLoad;
|
|
6
|
+
/**
|
|
7
|
+
* This is used by user of MailerId to create assertion that prove user's
|
|
8
|
+
* identity.
|
|
9
|
+
*/
|
|
10
|
+
export interface MailerIdSigner {
|
|
11
|
+
address: string;
|
|
12
|
+
userCert: SignedLoad;
|
|
13
|
+
providerCert: SignedLoad;
|
|
14
|
+
issuer: string;
|
|
15
|
+
certExpiresAt: number;
|
|
16
|
+
validityPeriod: number;
|
|
17
|
+
/**
|
|
18
|
+
* @param rpDomain relying party domain. If there is an explicit port,
|
|
19
|
+
* this should domain:port, which is a hostname part of url parsing.
|
|
20
|
+
* @param sessionId
|
|
21
|
+
* @param validFor (optional)
|
|
22
|
+
* @returns signed assertion with a given sessionId string.
|
|
23
|
+
*/
|
|
24
|
+
generateAssertionFor(rpDomain: string, sessionId: string, validFor?: number): SignedLoad;
|
|
25
|
+
/**
|
|
26
|
+
* @param pkey
|
|
27
|
+
* @param validFor
|
|
28
|
+
* @returns signed certificate with a given public key.
|
|
29
|
+
*/
|
|
30
|
+
certifyPublicKey(pkey: JsonKey, validFor: number): SignedLoad;
|
|
31
|
+
/**
|
|
32
|
+
* Makes this AssertionSigner not usable by wiping its secret key.
|
|
33
|
+
*/
|
|
34
|
+
destroy(): void;
|
|
35
|
+
/**
|
|
36
|
+
* @param payload
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
sign(payload: Uint8Array): {
|
|
40
|
+
provCert: SignedLoad;
|
|
41
|
+
signeeCert: SignedLoad;
|
|
42
|
+
signature: SignedLoad;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare const KID_BYTES_LENGTH = 9;
|
|
46
|
+
export declare const MAX_SIG_VALIDITY: number;
|
|
47
|
+
export declare function generateSigningKeyPair(random: GetRandom, arrFactory?: arrays.Factory): Keypair;
|
|
48
|
+
/**
|
|
49
|
+
* @param signKey which will be used to sign assertions/keys. Note that
|
|
50
|
+
* this key shall be wiped, when signer is destroyed, as key is neither
|
|
51
|
+
* long-living, nor should be shared.
|
|
52
|
+
* @param cert is user's certificate, signed by identity provider.
|
|
53
|
+
* @param provCert is provider's certificate, signed by respective mid root.
|
|
54
|
+
* @param assertionValidity is an assertion validity period in seconds
|
|
55
|
+
* @param arrFactory is an optional array factory
|
|
56
|
+
* @return signer for user of MailerId to generate assertions, and to sign
|
|
57
|
+
* keys.
|
|
58
|
+
*/
|
|
59
|
+
export declare function makeMailerIdSigner(signKey: Key, userCert: SignedLoad, provCert: SignedLoad, assertionValidity?: number, arrFactory?: arrays.Factory): MailerIdSigner;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
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.MAX_SIG_VALIDITY = exports.KID_BYTES_LENGTH = void 0;
|
|
20
|
+
exports.generateSigningKeyPair = generateSigningKeyPair;
|
|
21
|
+
exports.makeMailerIdSigner = makeMailerIdSigner;
|
|
22
|
+
const ecma_nacl_1 = require("ecma-nacl");
|
|
23
|
+
const jwkeys_1 = require("../jwkeys");
|
|
24
|
+
const buffer_utils_1 = require("../buffer-utils");
|
|
25
|
+
const json_utils_1 = require("../json-utils");
|
|
26
|
+
const utils_NaCl_Ed_1 = require("./utils-NaCl-Ed");
|
|
27
|
+
const index_1 = require("./index");
|
|
28
|
+
function correlateSKeyWithItsCert(skey, cert) {
|
|
29
|
+
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);
|
|
30
|
+
if ((pkey.kid !== skey.kid) || (pkey.use !== skey.use) || (pkey.alg !== skey.alg)
|
|
31
|
+
|| !(0, ecma_nacl_1.compareVectors)(ecma_nacl_1.signing.extract_pkey(skey.k), pkey.k)) {
|
|
32
|
+
throw new Error("Key does not correspond to certificate.");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.KID_BYTES_LENGTH = 9;
|
|
36
|
+
exports.MAX_SIG_VALIDITY = 30 * 60;
|
|
37
|
+
function generateSigningKeyPair(random, arrFactory) {
|
|
38
|
+
return (0, utils_NaCl_Ed_1.genSignKeyPair)(index_1.KEY_USE.SIGN, exports.KID_BYTES_LENGTH, random, arrFactory);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @param signKey which will be used to sign assertions/keys. Note that
|
|
42
|
+
* this key shall be wiped, when signer is destroyed, as key is neither
|
|
43
|
+
* long-living, nor should be shared.
|
|
44
|
+
* @param cert is user's certificate, signed by identity provider.
|
|
45
|
+
* @param provCert is provider's certificate, signed by respective mid root.
|
|
46
|
+
* @param assertionValidity is an assertion validity period in seconds
|
|
47
|
+
* @param arrFactory is an optional array factory
|
|
48
|
+
* @return signer for user of MailerId to generate assertions, and to sign
|
|
49
|
+
* keys.
|
|
50
|
+
*/
|
|
51
|
+
function makeMailerIdSigner(signKey, userCert, provCert, assertionValidity = exports.MAX_SIG_VALIDITY, arrFactory) {
|
|
52
|
+
const certificate = (0, jwkeys_1.getKeyCert)(userCert);
|
|
53
|
+
if (signKey.use !== index_1.KEY_USE.SIGN) {
|
|
54
|
+
throw new Error(`Given key ${signKey.kid} has incorrect use: ${signKey.use}`);
|
|
55
|
+
}
|
|
56
|
+
correlateSKeyWithItsCert(signKey, certificate);
|
|
57
|
+
if ((typeof assertionValidity !== 'number') || (assertionValidity < 1)
|
|
58
|
+
|| (assertionValidity > exports.MAX_SIG_VALIDITY)) {
|
|
59
|
+
throw new Error(`Given assertion validity is illegal: ${assertionValidity}`);
|
|
60
|
+
}
|
|
61
|
+
if (!arrFactory) {
|
|
62
|
+
arrFactory = ecma_nacl_1.arrays.makeFactory();
|
|
63
|
+
}
|
|
64
|
+
function ensureSignerCanBeUsed() {
|
|
65
|
+
if (!signKey) {
|
|
66
|
+
throw new Error("Signer is already destroyed.");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const signer = {
|
|
70
|
+
address: certificate.cert.principal.address,
|
|
71
|
+
userCert: userCert,
|
|
72
|
+
providerCert: provCert,
|
|
73
|
+
issuer: certificate.issuer,
|
|
74
|
+
certExpiresAt: certificate.expiresAt,
|
|
75
|
+
validityPeriod: assertionValidity,
|
|
76
|
+
generateAssertionFor: (rpDomain, sessionId, validFor) => {
|
|
77
|
+
ensureSignerCanBeUsed();
|
|
78
|
+
if (typeof validFor === 'number') {
|
|
79
|
+
if (validFor > assertionValidity) {
|
|
80
|
+
validFor = assertionValidity;
|
|
81
|
+
}
|
|
82
|
+
else if (validFor < 0) {
|
|
83
|
+
new Error(`Given assertion validity is illegal: ${validFor}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
validFor = assertionValidity;
|
|
88
|
+
}
|
|
89
|
+
let now = Math.floor(Date.now() / 1000);
|
|
90
|
+
if (now <= certificate.issuedAt) {
|
|
91
|
+
now = certificate.issuedAt + 1;
|
|
92
|
+
}
|
|
93
|
+
if (now >= certificate.expiresAt) {
|
|
94
|
+
throw new Error(`Signing key has already expiried at ${certificate.expiresAt} and now is ${now}`);
|
|
95
|
+
}
|
|
96
|
+
const assertion = {
|
|
97
|
+
rpDomain: rpDomain,
|
|
98
|
+
sessionId: sessionId,
|
|
99
|
+
user: certificate.cert.principal.address,
|
|
100
|
+
issuedAt: now,
|
|
101
|
+
expiresAt: now + validFor
|
|
102
|
+
};
|
|
103
|
+
const assertionBytes = buffer_utils_1.utf8.pack(JSON.stringify(assertion));
|
|
104
|
+
const sigBytes = ecma_nacl_1.signing.signature(assertionBytes, signKey.k, arrFactory);
|
|
105
|
+
return {
|
|
106
|
+
alg: signKey.alg,
|
|
107
|
+
kid: signKey.kid,
|
|
108
|
+
sig: buffer_utils_1.base64.pack(sigBytes),
|
|
109
|
+
load: buffer_utils_1.base64.pack(assertionBytes)
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
certifyPublicKey: (pkey, validFor) => {
|
|
113
|
+
ensureSignerCanBeUsed();
|
|
114
|
+
if (validFor < 0) {
|
|
115
|
+
new Error(`Given certificate validity is illegal: ${validFor}`);
|
|
116
|
+
}
|
|
117
|
+
const now = Math.floor(Date.now() / 1000);
|
|
118
|
+
if (now >= certificate.expiresAt) {
|
|
119
|
+
throw new Error(`Signing key has already expiried at ${certificate.expiresAt} and now is ${now}`);
|
|
120
|
+
}
|
|
121
|
+
return (0, utils_NaCl_Ed_1.makeCert)(pkey, certificate.cert.principal.address, certificate.cert.principal.address, now, now + validFor, signKey, arrFactory);
|
|
122
|
+
},
|
|
123
|
+
destroy: () => {
|
|
124
|
+
if (!signKey) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
ecma_nacl_1.arrays.wipe(signKey.k);
|
|
128
|
+
signKey = undefined;
|
|
129
|
+
arrFactory.wipeRecycled();
|
|
130
|
+
arrFactory = undefined;
|
|
131
|
+
},
|
|
132
|
+
sign: payload => {
|
|
133
|
+
ensureSignerCanBeUsed();
|
|
134
|
+
const sigBytes = ecma_nacl_1.signing.signature(payload, signKey.k, arrFactory);
|
|
135
|
+
return {
|
|
136
|
+
signature: {
|
|
137
|
+
alg: signKey.alg,
|
|
138
|
+
kid: signKey.kid,
|
|
139
|
+
sig: buffer_utils_1.base64.pack(sigBytes),
|
|
140
|
+
load: buffer_utils_1.base64.pack(payload)
|
|
141
|
+
},
|
|
142
|
+
provCert: (0, json_utils_1.copy)(provCert),
|
|
143
|
+
signeeCert: (0, json_utils_1.copy)(userCert)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
Object.freeze(signer);
|
|
148
|
+
return signer;
|
|
149
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { GetRandom, arrays } from "ecma-nacl";
|
|
2
|
+
import { Keypair } from "./index";
|
|
3
|
+
type JsonKey = web3n.keys.JsonKey;
|
|
4
|
+
type Key = web3n.keys.Key;
|
|
5
|
+
type SignedLoad = web3n.keys.SignedLoad;
|
|
6
|
+
export declare function genSignKeyPair(use: string, kidLen: number, random: GetRandom, arrFactory?: arrays.Factory): Keypair;
|
|
7
|
+
export declare function makeCert(pkey: JsonKey, principalAddr: string, issuer: string, issuedAt: number, expiresAt: number, signKey: Key, arrFactory?: arrays.Factory): SignedLoad;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
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.genSignKeyPair = genSignKeyPair;
|
|
20
|
+
exports.makeCert = makeCert;
|
|
21
|
+
const ecma_nacl_1 = require("ecma-nacl");
|
|
22
|
+
const buffer_utils_1 = require("../buffer-utils");
|
|
23
|
+
const index_1 = require("./index");
|
|
24
|
+
function genSignKeyPair(use, kidLen, random, arrFactory) {
|
|
25
|
+
const pair = ecma_nacl_1.signing.generate_keypair(random(ecma_nacl_1.signing.SEED_LENGTH), arrFactory);
|
|
26
|
+
const pkey = {
|
|
27
|
+
use: use,
|
|
28
|
+
alg: ecma_nacl_1.signing.JWK_ALG_NAME,
|
|
29
|
+
kid: buffer_utils_1.base64.pack(random(kidLen)),
|
|
30
|
+
k: buffer_utils_1.base64.pack(pair.pkey)
|
|
31
|
+
};
|
|
32
|
+
const skey = {
|
|
33
|
+
use: pkey.use,
|
|
34
|
+
alg: pkey.alg,
|
|
35
|
+
kid: pkey.kid,
|
|
36
|
+
k: pair.skey
|
|
37
|
+
};
|
|
38
|
+
return { pkey, skey };
|
|
39
|
+
}
|
|
40
|
+
function makeCert(pkey, principalAddr, issuer, issuedAt, expiresAt, signKey, arrFactory) {
|
|
41
|
+
if (signKey.alg !== ecma_nacl_1.signing.JWK_ALG_NAME) {
|
|
42
|
+
throw (0, index_1.makeMailerIdException)({ algMismatch: true }, { message: `Given signing key is used with unknown algorithm ${signKey.alg}` });
|
|
43
|
+
}
|
|
44
|
+
const cert = {
|
|
45
|
+
cert: {
|
|
46
|
+
publicKey: pkey,
|
|
47
|
+
principal: { address: principalAddr }
|
|
48
|
+
},
|
|
49
|
+
issuer: issuer,
|
|
50
|
+
issuedAt: issuedAt,
|
|
51
|
+
expiresAt: expiresAt
|
|
52
|
+
};
|
|
53
|
+
const certBytes = buffer_utils_1.utf8.pack(JSON.stringify(cert));
|
|
54
|
+
const sigBytes = ecma_nacl_1.signing.signature(certBytes, signKey.k, arrFactory);
|
|
55
|
+
return {
|
|
56
|
+
alg: signKey.alg,
|
|
57
|
+
kid: signKey.kid,
|
|
58
|
+
sig: buffer_utils_1.base64.pack(sigBytes),
|
|
59
|
+
load: buffer_utils_1.base64.pack(certBytes)
|
|
60
|
+
};
|
|
61
|
+
}
|