@vchasno/signer 1.0.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/.dockerignore +11 -0
- package/CHANGELOG.md +580 -0
- package/Dockerfile +14 -0
- package/README.md +156 -0
- package/docker/entrypoint.sh +15 -0
- package/index.d.ts +210 -0
- package/justfile +23 -0
- package/lib/vchasnoSigner.js +9066 -0
- package/package.json +51 -0
- package/scripts/generateCAServers.js +45 -0
- package/scripts/rawCAs.json +424 -0
- package/scripts/testCAs.json +14 -0
- package/scripts/versionBump.js +73 -0
- package/scripts/weights.json +106 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Vchasno Signer
|
|
2
|
+
|
|
3
|
+
Library to work with private keys, sign data and verify signatures.
|
|
4
|
+
(@evo/vchasno-signer => @vchasno/signer)
|
|
5
|
+
|
|
6
|
+
# Instalation
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
npm install @vchasno/signer
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
# Usage
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
import vchasnoSigner from '@vchasno/signer';
|
|
16
|
+
|
|
17
|
+
// Minimal config for signer, more details you can find in config object section
|
|
18
|
+
const configObject = { proxyServiceUrl: '/internal-api/proxy' };
|
|
19
|
+
|
|
20
|
+
// Initialize signer
|
|
21
|
+
await vchasnoSigner.init(configObject);
|
|
22
|
+
|
|
23
|
+
// Read private key
|
|
24
|
+
const key = await vchasnoSigner.readKey(keyFile, password, caServerIdx, certificateFiles);
|
|
25
|
+
|
|
26
|
+
// Sign data
|
|
27
|
+
const eSign = vchasnoSigner.signData(data, key);
|
|
28
|
+
|
|
29
|
+
// Verify signature
|
|
30
|
+
const signInfo = vchasnoSigner.verifySign(data, eSign);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Config object
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
{
|
|
37
|
+
// Allow to use only power certificates, default is true
|
|
38
|
+
checkIsPowerCertificate: true,
|
|
39
|
+
// Download internal sign library from specific url. If not specified, library
|
|
40
|
+
// will be downloaded from Vchasno servers
|
|
41
|
+
downloadSignLibraryUrl: null,
|
|
42
|
+
// Max data size to work with in bytes, library will take 10x size in memory.
|
|
43
|
+
// *Implicit* default value is 5Mb for desktop and 2Mb for mobile
|
|
44
|
+
maxFileSize: undefined,
|
|
45
|
+
// By default path to library is `/js/lib/iit`, but you can specify your own path
|
|
46
|
+
pathToLibrary: '/path/to/library',
|
|
47
|
+
// To work library need proxy service in your backend.
|
|
48
|
+
// Library send a POST request to proxy service url with address in GET parameter
|
|
49
|
+
// and data string in body. Backend needs to make a request to this address with
|
|
50
|
+
// data string and return received data to the library
|
|
51
|
+
proxyServiceUrl: '/internal-api/proxy',
|
|
52
|
+
// By default library will use Web Workers if supported, but you can force it
|
|
53
|
+
// by setting useMainThread = true
|
|
54
|
+
useMainThread: false,
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Read private key
|
|
59
|
+
|
|
60
|
+
Read PK file to get key object with PK content, associated certificates, information about PK and actual certificate.
|
|
61
|
+
|
|
62
|
+
Parameters:
|
|
63
|
+
|
|
64
|
+
- `keyFile`: PK file in `Blob` format
|
|
65
|
+
- `password`: PK password
|
|
66
|
+
- `caServerIdx`: PK vendor, you can get list of supported CA servers with `getCAServers` function
|
|
67
|
+
- `certificateFiles`: optional parameter, some CA use certificates from file, so we need to pass PK file and associated certificates file/files. You can use `getCAServerSettings` function to find out which certificates type are used.
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// List of supported CA servers
|
|
71
|
+
const caServers = vchasnoSigner.getCAServers();
|
|
72
|
+
|
|
73
|
+
// CA server settings
|
|
74
|
+
const caServerSettings = vchasnoSigner.getCAServerSettings(caServers[idx]);
|
|
75
|
+
caServerSettings.loadCertsFromFile; // true - need to pass associated certificates, false - certificates will be found in CA servers
|
|
76
|
+
|
|
77
|
+
// Read PK
|
|
78
|
+
const key = await vchasnoSigner.readKey(keyFile, password, caServerIdx, certificateFiles);
|
|
79
|
+
key.keyData //content of PK
|
|
80
|
+
key.password //PK password
|
|
81
|
+
key.certificates //PK associated certificates
|
|
82
|
+
key.keyInfo //information about PK owner
|
|
83
|
+
key.certificateInfo //information about actual associated certificate
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Sign data
|
|
87
|
+
|
|
88
|
+
Sign data with PK, verify signature and return signature object.
|
|
89
|
+
|
|
90
|
+
Parameters:
|
|
91
|
+
|
|
92
|
+
- `data`: data to sign in `Blob`, `ArrayBuffer`, or `Uint8Array` format
|
|
93
|
+
- `key`: key object from `readKey` function
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const eSign = vchasnoSigner.signData(data, key);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Also data can be signed internaly in p7s container
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const [eSign, p7s] = vchasnoSigner.signDataInternal(data, key);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Verify signature
|
|
106
|
+
|
|
107
|
+
Verify association between data and signature, return information about signature.
|
|
108
|
+
|
|
109
|
+
Parameters:
|
|
110
|
+
|
|
111
|
+
- `data`: data to sign in `Blob`, `ArrayBuffer` or `Uint8Array` format
|
|
112
|
+
- `eSign`: signature string from `signData` function
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const signInfo = vchasnoSigner.verifySign(data, eSign);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For internal signatures need to pass only p7s container.
|
|
119
|
+
|
|
120
|
+
Parameters:
|
|
121
|
+
|
|
122
|
+
- `p7s`: p7s container from `signDataInternal` function
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const signInfo = vchasnoSigner.verifySignInternal(p7s);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
# For library developers
|
|
129
|
+
|
|
130
|
+
## Autodeploy
|
|
131
|
+
|
|
132
|
+
To deploy new version:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
npm version <patch|minor|major>
|
|
136
|
+
git push origin --atomic HEAD v0.0.1
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Update certificates
|
|
140
|
+
|
|
141
|
+
1. Update CAs.json, CACertificates
|
|
142
|
+
- Docker with [just](https://github.com/casey/just)
|
|
143
|
+
```
|
|
144
|
+
# buid container if needed
|
|
145
|
+
just docker-build-image
|
|
146
|
+
# update certificates
|
|
147
|
+
just docker-update-ca-servers
|
|
148
|
+
```
|
|
149
|
+
- Node
|
|
150
|
+
```
|
|
151
|
+
wget --output-document ./scripts/rawCAs.json https://iit.com.ua/download/productfiles/CAs.json
|
|
152
|
+
wget --output-document ./src/files/CACertificates.p7b https://iit.com.ua/download/productfiles/CACertificates.p7b
|
|
153
|
+
|
|
154
|
+
node scripts/generateCAServers.js
|
|
155
|
+
```
|
|
156
|
+
2. [Add new tag](https://gitlab.vchasno.com.ua/libs/signerjs/-/tags)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
NPM_RC_FILE="/build/.npmrc"
|
|
5
|
+
|
|
6
|
+
# Check if NPM_TOKEN is set and not empty string
|
|
7
|
+
if [ -n "${NPM_TOKEN:-}" ]; then
|
|
8
|
+
echo "Found NPM_TOKEN. Configuring registry authentication..."
|
|
9
|
+
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > "$NPM_RC_FILE"
|
|
10
|
+
else
|
|
11
|
+
echo "Notice: NPM_TOKEN is not set. Proceeding without configuring npm authentication."
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Execute the passed command
|
|
15
|
+
exec "$@"
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Type definitions for @vchasno/signer
|
|
2
|
+
// Project: https://vchasno.ua
|
|
3
|
+
// Definitions by: vchasno
|
|
4
|
+
|
|
5
|
+
export = VchasnoSigner;
|
|
6
|
+
export as namespace VchasnoSigner;
|
|
7
|
+
|
|
8
|
+
declare namespace VchasnoSigner {
|
|
9
|
+
interface VchasnoSignerConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Sign library need proxy service to work, specify it here
|
|
12
|
+
*/
|
|
13
|
+
proxyServiceUrl: string;
|
|
14
|
+
/**
|
|
15
|
+
* Allow to use only power certificates
|
|
16
|
+
*/
|
|
17
|
+
checkIsPowerCertificate?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* download sign library from specific url
|
|
20
|
+
*/
|
|
21
|
+
downloadSignLibraryUrl?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Max data size to work with in bytes, library will take 10x size in memory
|
|
24
|
+
*/
|
|
25
|
+
maxFileSize?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Path to sign library files
|
|
28
|
+
*/
|
|
29
|
+
pathToLibrary?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Version helps to avoid CDN library file caching.
|
|
32
|
+
*/
|
|
33
|
+
libraryVersion?: string;
|
|
34
|
+
/**
|
|
35
|
+
* By default, library will use Web Workers if supported
|
|
36
|
+
*/
|
|
37
|
+
useMainThread?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* By default, library will use CAdES-BES (1)
|
|
40
|
+
*/
|
|
41
|
+
signType?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Add properties for setting with SetRuntimeParameter
|
|
44
|
+
*/
|
|
45
|
+
runtimeParameters?: Record<string, string | boolean | number>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface CaServer {
|
|
49
|
+
name: string;
|
|
50
|
+
issuerCNs: string;
|
|
51
|
+
address: string;
|
|
52
|
+
ocspAccessPointAddress: string;
|
|
53
|
+
ocspAccessPointPort: string;
|
|
54
|
+
cmpAddress: string;
|
|
55
|
+
tspAddress: string;
|
|
56
|
+
tspAddressPort: string;
|
|
57
|
+
certsInKey?: boolean;
|
|
58
|
+
}
|
|
59
|
+
interface CaServerSetting {
|
|
60
|
+
offline: boolean;
|
|
61
|
+
useCMP: boolean;
|
|
62
|
+
loadCertsFromFile: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface JksKey {
|
|
66
|
+
privateKeyName: string;
|
|
67
|
+
subjectName: string;
|
|
68
|
+
keyData: Uint8Array;
|
|
69
|
+
certificates: Uint8Array[];
|
|
70
|
+
}
|
|
71
|
+
interface Key {
|
|
72
|
+
keyData: Uint8Array;
|
|
73
|
+
password: string;
|
|
74
|
+
certificates: Uint8Array;
|
|
75
|
+
keyInfo: KeyInfo;
|
|
76
|
+
certificateInfo: CertificateInfo;
|
|
77
|
+
}
|
|
78
|
+
interface KeyCtx {
|
|
79
|
+
keyContextId: string;
|
|
80
|
+
keyInfo: KeyInfo;
|
|
81
|
+
certificateInfo: CertificateInfo;
|
|
82
|
+
}
|
|
83
|
+
interface KeyCtxCAIdx extends KeyCtx {
|
|
84
|
+
caServerIdx: number
|
|
85
|
+
}
|
|
86
|
+
interface CertificateInfo {
|
|
87
|
+
publicKeyID: string;
|
|
88
|
+
isPowerCert: boolean;
|
|
89
|
+
isStamp: boolean;
|
|
90
|
+
certBeginDate: Date;
|
|
91
|
+
certEndDate: Date;
|
|
92
|
+
keyBeginDate: Date;
|
|
93
|
+
keyEndDate: Date;
|
|
94
|
+
state: string;
|
|
95
|
+
locality: string;
|
|
96
|
+
}
|
|
97
|
+
interface KeyInfo {
|
|
98
|
+
isLegal: boolean;
|
|
99
|
+
edrpou: string;
|
|
100
|
+
drfo: string | null;
|
|
101
|
+
caServer: string;
|
|
102
|
+
companyName: string;
|
|
103
|
+
ownerFullName: string;
|
|
104
|
+
ownerPosition: string;
|
|
105
|
+
serialNumber: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface Signature {
|
|
109
|
+
keyType: string;
|
|
110
|
+
eds: string;
|
|
111
|
+
edsInfo: SignatureInfo;
|
|
112
|
+
}
|
|
113
|
+
interface SignatureInfo extends KeyInfo {
|
|
114
|
+
timemark: string;
|
|
115
|
+
data?: Uint8Array;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface ReceiptResult {
|
|
119
|
+
receiptNumber: string | null;
|
|
120
|
+
initiators: string[];
|
|
121
|
+
receiptData: Uint8Array;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface GeneratedKeyData {
|
|
125
|
+
privateKeyName: string;
|
|
126
|
+
privateKey: Uint8Array;
|
|
127
|
+
uaRequestName: string;
|
|
128
|
+
uaRequest: Uint8Array;
|
|
129
|
+
uaKEPRequestName: string;
|
|
130
|
+
uaKEPRequest: Uint8Array;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Not the best typings, but it's better than nothing
|
|
134
|
+
interface GeneratedKeyDataExt {
|
|
135
|
+
privateKeyName: string;
|
|
136
|
+
privateKeyInfoName: string;
|
|
137
|
+
privateKey: Uint8Array;
|
|
138
|
+
privateKeyInfo: Uint8Array;
|
|
139
|
+
intRequest: Uint8Array | null;
|
|
140
|
+
intRequestName: string | null;
|
|
141
|
+
uaKEPRequest: Uint8Array | null;
|
|
142
|
+
uaKEPRequestName: string | null;
|
|
143
|
+
uaRequest: Uint8Array | null;
|
|
144
|
+
uaRequestName: string | null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface SessionData {
|
|
148
|
+
session: string;
|
|
149
|
+
authData: Uint8Array;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type Data = Blob | ArrayBuffer | Uint8Array;
|
|
153
|
+
|
|
154
|
+
function base64Encode(data: Uint8Array): Promise<string>;
|
|
155
|
+
function base64Decode(data: string): Promise<Uint8Array>;
|
|
156
|
+
function clearKeyCtx(keyContextId: string): Promise<void>;
|
|
157
|
+
function clearKeysCtx(): Promise<void>;
|
|
158
|
+
function generatePrivateKey(pkPassword: string, isStamp: boolean): Promise<GeneratedKeyData>;
|
|
159
|
+
function generatePrivateKeyExt(pkPassword: string, params?: Partial<{
|
|
160
|
+
uaKeysType: number,
|
|
161
|
+
uaDSKeysSpec: number,
|
|
162
|
+
useDSKeyAsKEP: boolean,
|
|
163
|
+
uaKepSpec: number,
|
|
164
|
+
intKeysType: number,
|
|
165
|
+
intKeysSpec: number,
|
|
166
|
+
userInfo: unknown,
|
|
167
|
+
extKeyUsages: string,
|
|
168
|
+
}>): Promise<GeneratedKeyDataExt>;
|
|
169
|
+
function getCAServers(): Promise<CaServer[]>;
|
|
170
|
+
function getCAServerSettings(caServer: CaServer): Promise<CaServerSetting>;
|
|
171
|
+
function getRootCertificates(enableTestCertificates?: boolean): Uint8Array;
|
|
172
|
+
function init(inputConfig: VchasnoSignerConfig): Promise<void>;
|
|
173
|
+
function protectData(data: string): Promise<string>;
|
|
174
|
+
function protectReport(
|
|
175
|
+
reportData: Data,
|
|
176
|
+
recipientCert: Blob,
|
|
177
|
+
senderEmail: string,
|
|
178
|
+
reportName: string,
|
|
179
|
+
directorPKey: KeyCtx | null,
|
|
180
|
+
accountantPKey: KeyCtx | null,
|
|
181
|
+
stampPKey: KeyCtx | null,
|
|
182
|
+
): Promise<Uint8Array>;
|
|
183
|
+
function envelopDataCtx(
|
|
184
|
+
data: Data,
|
|
185
|
+
recipientCert: Blob,
|
|
186
|
+
key: KeyCtx,
|
|
187
|
+
asBase64String: boolean | null,
|
|
188
|
+
): Promise<Uint8Array | String>;
|
|
189
|
+
function developDataCtx(data: Data, recipientCert: Blob, key: KeyCtx): Promise<Uint8Array>;
|
|
190
|
+
function unprotectReceipt(reportData: Data, key: KeyCtx): Promise<ReceiptResult>;
|
|
191
|
+
function readJksFile(keyFile: Blob): Promise<JksKey[]>;
|
|
192
|
+
function readJksKeyCtx(keyData: Uint8Array, certificates: Uint8Array[], password: string, caServerIdx: number): Promise<Key>;
|
|
193
|
+
function readKey(keyFile: Blob, password: string, caServerIdx: number, certificateFiles?: FileList): Promise<Key>;
|
|
194
|
+
function readKeyCtx(keyFile: Blob, password: string, caServerIdx: number, certificateFiles?: FileList): Promise<KeyCtx>;
|
|
195
|
+
function readPKKeyCtxWithCMP(keyFile: Blob, password: string): Promise<KeyCtxCAIdx>;
|
|
196
|
+
function signData(data: Data, keys: Key | Key[]): Promise<Signature | Signature[]>;
|
|
197
|
+
function signDataCtx(data: Data): Promise<Signature[]>;
|
|
198
|
+
function signDataInternal(data: Data, keys: Key | Key[]): Promise<[Signature | Signature[], Data]>;
|
|
199
|
+
function signDataInternalCtx(data: Data): Promise<[Signature[], Data]>;
|
|
200
|
+
function signDataInternalAppendedCtx(data: Data): Promise<[Signature[], Data]>;
|
|
201
|
+
function signHashCtx(data: string): Promise<Signature[]>;
|
|
202
|
+
function signDataDFS(data: Blob | ArrayBuffer, signKeys: Key[], cypherKey: Key[]): Promise<[Signature[], Data]>;
|
|
203
|
+
function unprotectData(data: string): Promise<string>;
|
|
204
|
+
function verifySign(data: Data, eSign: Signature): Promise<SignatureInfo>;
|
|
205
|
+
function verifySignInternal(p7s: Data, withData: boolean): Promise<SignatureInfo>;
|
|
206
|
+
function createClientSession(duration: number, certificate: Uint8Array): Promise<SessionData>;
|
|
207
|
+
function sessionEncrypt(data: Uint8Array | string, asBase64String?: boolean): Promise<Uint8Array | string>;
|
|
208
|
+
function sessionDecrypt(data: Uint8Array | string): Promise<Uint8Array>;
|
|
209
|
+
function hashData(data: Uint8Array | string, asBase64String?: boolean): Promise<Uint8Array | string>;
|
|
210
|
+
}
|
package/justfile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
TAG := 'vchasno-signer'
|
|
2
|
+
|
|
3
|
+
# Build the docker image
|
|
4
|
+
docker-build-image:
|
|
5
|
+
docker build -t {{TAG}} . --target dev
|
|
6
|
+
|
|
7
|
+
# Update certificates inside docker
|
|
8
|
+
docker-generate-ca-servers:
|
|
9
|
+
wget --output-document ./scripts/rawCAs.json https://iit.com.ua/download/productfiles/CAs.json
|
|
10
|
+
wget --output-document ./src/files/CACertificates.p7b https://iit.com.ua/download/productfiles/CACertificates.p7b
|
|
11
|
+
docker run --rm -v $(pwd):/build {{TAG}} node /build/scripts/generateCAServers.js
|
|
12
|
+
|
|
13
|
+
docker-update-ca-servers: docker-generate-ca-servers
|
|
14
|
+
docker run --rm -v $(pwd):/build {{TAG}} node /build/scripts/versionBump.js
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Run the tests inside docker. Consider using docker-build-image first
|
|
18
|
+
docker-test:
|
|
19
|
+
docker run --rm {{TAG}} npm run test
|
|
20
|
+
|
|
21
|
+
# Run the linter inside docker. Consider using docker-build-image first
|
|
22
|
+
docker-lint:
|
|
23
|
+
docker run --rm {{TAG}} npm run lint
|