@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/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