@embedpdf/core-signature 3.0.0-next.13
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/LICENSE +192 -0
- package/dist/index.cjs +886 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +328 -0
- package/dist/index.d.ts +328 -0
- package/dist/index.js +843 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import * as pkijs from "pkijs";
|
|
2
|
+
import { DigestAlgorithm, DocumentHandle, SignatureCompleteResult, SignatureDTO, SignaturePrepareInput, SignaturePrepared, SignatureSubFilter } from "@embedpdf/engine-core/runtime";
|
|
3
|
+
//#region src/cms/parse.d.ts
|
|
4
|
+
/** What a detached CMS says about itself. Nothing here is verified. */
|
|
5
|
+
interface ParsedCms {
|
|
6
|
+
digestAlgorithm: DigestAlgorithm;
|
|
7
|
+
/** The `message-digest` signed attribute: what the signer claims the content hashes to. */
|
|
8
|
+
messageDigest: Uint8Array;
|
|
9
|
+
/** The CMS `signing-time` signed attribute, when present (PAdES forbids it; the PDF's `/M` is the claim there). */
|
|
10
|
+
signingTime: Date | null;
|
|
11
|
+
/** DER of the signer's certificate. */
|
|
12
|
+
signerCertificate: Uint8Array;
|
|
13
|
+
/** DER of every certificate carried by the CMS, signer first. */
|
|
14
|
+
certificates: Uint8Array[];
|
|
15
|
+
/** The signature algorithm OID (`1.2.840.113549.1.1.11` = sha256WithRSAEncryption, …). */
|
|
16
|
+
signatureAlgorithm: string;
|
|
17
|
+
/** The ESS `signing-certificate-v2` attribute is present (a CAdES requirement). */
|
|
18
|
+
signingCertificateV2: boolean;
|
|
19
|
+
/** DER of an RFC 3161 timestamp token carried as an unsigned attribute, when present. */
|
|
20
|
+
timestampToken: Uint8Array | null;
|
|
21
|
+
}
|
|
22
|
+
declare class CmsError extends Error {
|
|
23
|
+
readonly reason: 'malformed' | 'unsupported';
|
|
24
|
+
constructor(reason: 'malformed' | 'unsupported', message: string);
|
|
25
|
+
}
|
|
26
|
+
interface ParsedCmsInternal {
|
|
27
|
+
parsed: ParsedCms;
|
|
28
|
+
signedData: pkijs.SignedData;
|
|
29
|
+
signerInfo: pkijs.SignerInfo;
|
|
30
|
+
signerCertificate: pkijs.Certificate;
|
|
31
|
+
certificates: pkijs.Certificate[];
|
|
32
|
+
/** DER of the signing-certificate-v2 attribute's first certHash, when present. */
|
|
33
|
+
essCertHash: Uint8Array | null;
|
|
34
|
+
}
|
|
35
|
+
/** Parse a detached CMS SignedData with exactly one signer. Throws `CmsError`. */
|
|
36
|
+
declare function parseDetachedCms(cms: Uint8Array): ParsedCms;
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/cms/verify.d.ts
|
|
39
|
+
type CryptographyVerdict = 'valid' | 'invalid' | 'unsupported';
|
|
40
|
+
/**
|
|
41
|
+
* Does the CMS's signature verify with the certificate it names, over the
|
|
42
|
+
* attributes it signed? Says nothing about the content: the message digest
|
|
43
|
+
* is compared by the caller (`validateSignatures`, `verifyForCompletion`).
|
|
44
|
+
* `unsupported` means the algorithm is unknown to this engine, which is
|
|
45
|
+
* never `invalid`.
|
|
46
|
+
*/
|
|
47
|
+
declare function verifyCmsSignature(cms: Uint8Array | ParsedCmsInternal): Promise<CryptographyVerdict>;
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/cms/build.d.ts
|
|
50
|
+
type SignatureProfile = 'pkcs7' | 'cades-b';
|
|
51
|
+
type RawSignatureAlgorithm = 'RSA-PKCS1-v1_5' | 'RSA-PSS' | 'ECDSA';
|
|
52
|
+
/**
|
|
53
|
+
* Something that signs bytes with a private key it never hands out: a
|
|
54
|
+
* WebCrypto key, an HSM, a smart card. `sign` receives the DER of the CMS
|
|
55
|
+
* signed attributes and returns the raw signature (for ECDSA: `r || s`,
|
|
56
|
+
* as WebCrypto produces it; the CMS encoding is done here).
|
|
57
|
+
*/
|
|
58
|
+
interface RawSigner {
|
|
59
|
+
readonly kind: 'raw';
|
|
60
|
+
/** DER certificates, the signer's first, then its issuers. */
|
|
61
|
+
readonly certificateChain: Uint8Array[];
|
|
62
|
+
readonly algorithm: RawSignatureAlgorithm;
|
|
63
|
+
readonly hash: Exclude<DigestAlgorithm, 'sha1'>;
|
|
64
|
+
sign(signedAttributesDer: Uint8Array): Promise<Uint8Array>;
|
|
65
|
+
}
|
|
66
|
+
interface BuildDetachedCmsInput {
|
|
67
|
+
/** The digest the engine prepared (over the `/ByteRange`). */
|
|
68
|
+
digest: Uint8Array;
|
|
69
|
+
hash: Exclude<DigestAlgorithm, 'sha1'>;
|
|
70
|
+
profile: SignatureProfile;
|
|
71
|
+
signer: RawSigner;
|
|
72
|
+
/** `pkcs7` only: the CMS `signing-time` attribute. PAdES (`cades-b`) never carries one. */
|
|
73
|
+
signingTime?: Date;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build a detached CMS SignedData around a raw signature: content-type,
|
|
77
|
+
* message-digest, and for CAdES-B the ESS signing-certificate-v2 attribute;
|
|
78
|
+
* the signer's certificate chain; one SignerInfo identified by issuer and
|
|
79
|
+
* serial number.
|
|
80
|
+
*/
|
|
81
|
+
declare function buildDetachedCms(input: BuildDetachedCmsInput): Promise<Uint8Array>;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/gate.d.ts
|
|
84
|
+
type CompletionRefusal = 'malformed' | 'too-large' | 'algorithm-mismatch' | 'digest-mismatch' | 'signature-invalid' | 'profile-violation';
|
|
85
|
+
type CompletionGate = {
|
|
86
|
+
ok: true;
|
|
87
|
+
} | {
|
|
88
|
+
ok: false;
|
|
89
|
+
reason: CompletionRefusal;
|
|
90
|
+
detail: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* The gate between a signer's answer and `signatures.complete`: the CMS
|
|
94
|
+
* must fit the reserved room, hash with the prepared algorithm, carry the
|
|
95
|
+
* prepared digest as its message digest, verify with its own certificate,
|
|
96
|
+
* and match the profile the `/SubFilter` promises (CAdES: ESS
|
|
97
|
+
* signing-certificate-v2 present, no CMS signing-time). A bad CMS never
|
|
98
|
+
* reaches the document.
|
|
99
|
+
*/
|
|
100
|
+
declare function verifyForCompletion(input: {
|
|
101
|
+
cms: Uint8Array;
|
|
102
|
+
prepared: SignaturePrepared;
|
|
103
|
+
profile: SignatureProfile;
|
|
104
|
+
}): Promise<CompletionGate>;
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/trust.d.ts
|
|
107
|
+
/**
|
|
108
|
+
* Where trust comes from. The engine has no opinion: an application
|
|
109
|
+
* supplies its anchors (a company root, a national trust list, the AATL).
|
|
110
|
+
*/
|
|
111
|
+
interface TrustPort {
|
|
112
|
+
/** DER certificates trusted as anchors. */
|
|
113
|
+
anchors(): Promise<Uint8Array[]>;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* When a chain is judged. `now` is the honest default; `timestamp` is only
|
|
117
|
+
* legitimate for a verified RFC 3161 token, which is why it carries the
|
|
118
|
+
* proof flag. The signature's own `/M` is a claim and never a validation
|
|
119
|
+
* time.
|
|
120
|
+
*/
|
|
121
|
+
type ValidationTime = {
|
|
122
|
+
kind: 'now';
|
|
123
|
+
} | {
|
|
124
|
+
kind: 'timestamp';
|
|
125
|
+
genTime: Date;
|
|
126
|
+
tokenVerified: true;
|
|
127
|
+
};
|
|
128
|
+
type TrustStatus = 'trusted' | 'untrusted' | 'unknown';
|
|
129
|
+
interface TrustVerdict {
|
|
130
|
+
status: TrustStatus;
|
|
131
|
+
/** Why, when not trusted. */
|
|
132
|
+
reason?: string;
|
|
133
|
+
/** DER certificates of the validated path, anchor last, when trusted. */
|
|
134
|
+
path?: Uint8Array[];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build and validate the certificate path from the CMS's signer to one
|
|
138
|
+
* of the port's anchors at `at`. No port, or a port with no anchors, is
|
|
139
|
+
* `unknown`: nothing was checked, and nothing was refused.
|
|
140
|
+
*/
|
|
141
|
+
declare function validateChain(cms: Uint8Array | ParsedCmsInternal, trust: TrustPort | null | undefined, at?: ValidationTime): Promise<TrustVerdict>;
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/sign.d.ts
|
|
144
|
+
/** A service that turns a digest into a finished detached CMS (most hosted signing APIs). */
|
|
145
|
+
interface CmsSigner {
|
|
146
|
+
readonly kind: 'cms';
|
|
147
|
+
sign(input: {
|
|
148
|
+
digest: Uint8Array;
|
|
149
|
+
algorithm: Exclude<DigestAlgorithm, 'sha1'>;
|
|
150
|
+
subFilter: SignatureSubFilter;
|
|
151
|
+
}): Promise<Uint8Array>;
|
|
152
|
+
}
|
|
153
|
+
type SignerPort = CmsSigner | RawSigner;
|
|
154
|
+
type SignInput = Omit<SignaturePrepareInput, 'kind'> & {
|
|
155
|
+
signer: SignerPort;
|
|
156
|
+
};
|
|
157
|
+
declare class SigningError extends Error {
|
|
158
|
+
readonly reason: CompletionRefusal;
|
|
159
|
+
constructor(reason: CompletionRefusal, detail: string);
|
|
160
|
+
}
|
|
161
|
+
declare function profileFor(subFilter: SignatureSubFilter): SignatureProfile;
|
|
162
|
+
/**
|
|
163
|
+
* Sign a field in one call: `prepare` on the engine, the signer turns the
|
|
164
|
+
* digest into a CMS (or a raw signature this package wraps), the gate
|
|
165
|
+
* checks the CMS matches what was prepared, `complete` installs it. Any
|
|
166
|
+
* failure aborts the candidate and rethrows; the document is never left
|
|
167
|
+
* with a pending signing.
|
|
168
|
+
*/
|
|
169
|
+
declare function sign(doc: DocumentHandle, input: SignInput): Promise<SignatureCompleteResult>;
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/verdict.d.ts
|
|
172
|
+
type IntegrityVerdict = 'valid' | 'invalid' | 'indeterminate';
|
|
173
|
+
type ModificationsVerdict = 'unchanged' | 'permitted' | 'forbidden' | 'indeterminate';
|
|
174
|
+
/**
|
|
175
|
+
* Four independent facts and a summary, never one boolean — the shape
|
|
176
|
+
* Acrobat reports ("signature valid", "signer unknown", "document changed,
|
|
177
|
+
* changes allowed") and the shape a UI can explain.
|
|
178
|
+
*/
|
|
179
|
+
interface SignatureVerdict {
|
|
180
|
+
signature: SignatureDTO;
|
|
181
|
+
/** The sealed bytes are intact: whole-revision coverage and the CMS message digest matches them. */
|
|
182
|
+
integrity: IntegrityVerdict;
|
|
183
|
+
/** The CMS verifies with its own certificate. */
|
|
184
|
+
cryptography: CryptographyVerdict;
|
|
185
|
+
/** The certificate chains to one of the caller's anchors. */
|
|
186
|
+
trust: TrustStatus;
|
|
187
|
+
trustReason?: string;
|
|
188
|
+
validatedAt: ValidationTime;
|
|
189
|
+
/**
|
|
190
|
+
* What changed after the signature, and which bytes were judged: the loaded
|
|
191
|
+
* file (`persisted`), or the session's unsaved edits snapshotted as one
|
|
192
|
+
* more revision (`working-copy` — only when such edits existed).
|
|
193
|
+
*/
|
|
194
|
+
modifications: {
|
|
195
|
+
verdict: ModificationsVerdict;
|
|
196
|
+
detail?: string;
|
|
197
|
+
basis: 'persisted' | 'working-copy';
|
|
198
|
+
/** Revisions appended after the one this signature sealed (present when there are any). */
|
|
199
|
+
laterRevisions?: number;
|
|
200
|
+
/** Some object was changed after the signature and holds the sealed value again. */
|
|
201
|
+
undone?: boolean;
|
|
202
|
+
};
|
|
203
|
+
/** `invalid` only on positive evidence; `indeterminate` whenever a fact could not be established. */
|
|
204
|
+
summary: 'valid' | 'valid-untrusted' | 'invalid' | 'indeterminate';
|
|
205
|
+
cms: ParsedCms | null;
|
|
206
|
+
}
|
|
207
|
+
interface ValidateSignaturesOptions {
|
|
208
|
+
trust?: TrustPort | null;
|
|
209
|
+
at?: ValidationTime;
|
|
210
|
+
/**
|
|
211
|
+
* `persisted` (default): the loaded bytes — what a file on disk says.
|
|
212
|
+
* `working-copy`: unsaved edits are judged too, as the revision a save would
|
|
213
|
+
* write — what the file a save produces will say. A viewer shows this one.
|
|
214
|
+
*/
|
|
215
|
+
until?: 'persisted' | 'working-copy';
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Validate every signature of a document: integrity from the engine's
|
|
219
|
+
* bytes, cryptography from the CMS, trust from the caller's anchors.
|
|
220
|
+
*/
|
|
221
|
+
declare function validateSignatures(doc: DocumentHandle, opts?: ValidateSignaturesOptions): Promise<SignatureVerdict[]>;
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/signers/webcrypto.d.ts
|
|
224
|
+
/**
|
|
225
|
+
* A `RawSigner` over a WebCrypto private key: the key never leaves the
|
|
226
|
+
* runtime. The algorithm and hash come from the key itself.
|
|
227
|
+
*/
|
|
228
|
+
declare function webCryptoSigner(input: {
|
|
229
|
+
privateKey: CryptoKey;
|
|
230
|
+
certificateChain: Uint8Array[];
|
|
231
|
+
/** Required for ECDSA keys (the key carries no hash); ignored for RSA keys. */
|
|
232
|
+
hash?: Exclude<DigestAlgorithm, 'sha1'>;
|
|
233
|
+
}): RawSigner;
|
|
234
|
+
interface TestSigner extends RawSigner {
|
|
235
|
+
/** DER of the self-signed certificate — also the only trust anchor that validates it. */
|
|
236
|
+
readonly certificate: Uint8Array;
|
|
237
|
+
readonly privateKey: CryptoKey;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* A throwaway signer for tests and demos: a fresh key pair and a
|
|
241
|
+
* self-signed certificate, never persisted. Trust it with
|
|
242
|
+
* `{ anchors: async () => [signer.certificate] }`.
|
|
243
|
+
*/
|
|
244
|
+
declare function createTestSigner(opts?: {
|
|
245
|
+
commonName?: string;
|
|
246
|
+
algorithm?: 'RSA-PKCS1-v1_5' | 'RSA-PSS' | 'ECDSA';
|
|
247
|
+
hash?: 'sha256' | 'sha384' | 'sha512';
|
|
248
|
+
}): Promise<TestSigner>;
|
|
249
|
+
/** A WebCrypto signing key pair; `extractable: false` keeps the private key inside the runtime for good. */
|
|
250
|
+
declare function generateSigningKeyPair(algorithm: 'RSA-PKCS1-v1_5' | 'RSA-PSS' | 'ECDSA', hash: 'sha256' | 'sha384' | 'sha512', extractable: boolean): Promise<CryptoKeyPair>;
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/signers/remote.d.ts
|
|
253
|
+
/**
|
|
254
|
+
* A `CmsSigner` over the customer's own signing service or HSM: the engine's
|
|
255
|
+
* digest goes out, a finished detached CMS comes back. Nothing but the
|
|
256
|
+
* digest (and which hash and profile it is for) ever leaves the runtime.
|
|
257
|
+
*/
|
|
258
|
+
declare function remoteSigner(input: {
|
|
259
|
+
sign: (request: {
|
|
260
|
+
digest: Uint8Array;
|
|
261
|
+
algorithm: 'sha256' | 'sha384' | 'sha512';
|
|
262
|
+
subFilter: 'adbe.pkcs7.detached' | 'ETSI.CAdES.detached';
|
|
263
|
+
}) => Promise<Uint8Array>;
|
|
264
|
+
}): CmsSigner;
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/signers/personal.d.ts
|
|
267
|
+
/** What a personal signer keeps: a NON-extractable private key and its self-signed certificate. */
|
|
268
|
+
interface PersonalKeyRecord {
|
|
269
|
+
privateKey: CryptoKey;
|
|
270
|
+
certificate: Uint8Array;
|
|
271
|
+
}
|
|
272
|
+
/** Where personal keys live. Keys are structured-cloneable, so a store can keep the `CryptoKey` itself. */
|
|
273
|
+
interface PersonalKeyStore {
|
|
274
|
+
load(subject: string): Promise<PersonalKeyRecord | null>;
|
|
275
|
+
save(subject: string, record: PersonalKeyRecord): Promise<void>;
|
|
276
|
+
remove(subject: string): Promise<void>;
|
|
277
|
+
}
|
|
278
|
+
interface PersonalSigner extends RawSigner {
|
|
279
|
+
/** DER of the self-signed certificate — the only anchor that validates it. */
|
|
280
|
+
readonly certificate: Uint8Array;
|
|
281
|
+
readonly subject: string;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* One self-signed identity per subject (a person's name), persisted in the
|
|
285
|
+
* caller's store and created on first use. The private key is generated
|
|
286
|
+
* non-extractable: it can sign, it can be stored by the browser, it can
|
|
287
|
+
* never be read out. This is Preview's "sign with your own signature"
|
|
288
|
+
* experience with real cryptography behind it — a reader who trusts the
|
|
289
|
+
* certificate validates the signature; every other reader sees "validity
|
|
290
|
+
* unknown", which is the honest answer for a self-issued identity.
|
|
291
|
+
*/
|
|
292
|
+
declare function personalSigner(input: {
|
|
293
|
+
subject: string;
|
|
294
|
+
store: PersonalKeyStore;
|
|
295
|
+
algorithm?: 'RSA-PKCS1-v1_5' | 'RSA-PSS' | 'ECDSA';
|
|
296
|
+
hash?: 'sha256' | 'sha384' | 'sha512';
|
|
297
|
+
}): Promise<PersonalSigner>;
|
|
298
|
+
/** An in-memory store: tests, and runtimes without IndexedDB. */
|
|
299
|
+
declare function memoryKeyStore(): PersonalKeyStore;
|
|
300
|
+
/**
|
|
301
|
+
* An IndexedDB store: the browser keeps the non-extractable `CryptoKey`
|
|
302
|
+
* itself (structured clone), so the key survives reloads without ever
|
|
303
|
+
* existing as bytes.
|
|
304
|
+
*/
|
|
305
|
+
declare function indexedDbKeyStore(dbName: string, opts?: {
|
|
306
|
+
storeName?: string;
|
|
307
|
+
}): PersonalKeyStore;
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/signers/self-signed.d.ts
|
|
310
|
+
/**
|
|
311
|
+
* A self-signed certificate over a WebCrypto key pair: the shape a personal
|
|
312
|
+
* signer, a test signer, and a demo all need. It is its own trust anchor and
|
|
313
|
+
* nothing else's — Acrobat shows a signature made with it as "validity
|
|
314
|
+
* unknown" until the reader trusts the certificate explicitly.
|
|
315
|
+
*/
|
|
316
|
+
declare function selfSignedCertificate(input: {
|
|
317
|
+
publicKey: CryptoKey;
|
|
318
|
+
privateKey: CryptoKey;
|
|
319
|
+
commonName: string;
|
|
320
|
+
hash: 'sha256' | 'sha384' | 'sha512';
|
|
321
|
+
/** Validity in days; default one year. */
|
|
322
|
+
validityDays?: number;
|
|
323
|
+
}): Promise<Uint8Array>;
|
|
324
|
+
/** The subject common name of a DER certificate, or null when it has none. */
|
|
325
|
+
declare function certificateCommonName(der: Uint8Array): string | null;
|
|
326
|
+
//#endregion
|
|
327
|
+
export { type BuildDetachedCmsInput, CmsError, type CmsSigner, type CompletionGate, type CompletionRefusal, type CryptographyVerdict, type IntegrityVerdict, type ModificationsVerdict, type ParsedCms, type PersonalKeyRecord, type PersonalKeyStore, type PersonalSigner, type RawSignatureAlgorithm, type RawSigner, type SignInput, type SignatureProfile, type SignatureVerdict, type SignerPort, SigningError, type TestSigner, type TrustPort, type TrustStatus, type TrustVerdict, type ValidateSignaturesOptions, type ValidationTime, buildDetachedCms, certificateCommonName, createTestSigner, generateSigningKeyPair, indexedDbKeyStore, memoryKeyStore, parseDetachedCms, personalSigner, profileFor, remoteSigner, selfSignedCertificate, sign, validateChain, validateSignatures, verifyCmsSignature, verifyForCompletion, webCryptoSigner };
|
|
328
|
+
//# sourceMappingURL=index.d.ts.map
|