Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/api/pdf-signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export class PDFSignature {

// Extract bytes to sign and hash them
const signedBytes = extractSignedBytes(pdfBytes, byteRange);
const documentHash = hashData(signedBytes, resolved.digestAlgorithm);
const documentHash = await hashData(signedBytes, resolved.digestAlgorithm);

// Build CMS signature
const formatBuilder = this.getFormatBuilder(resolved.subFilter);
Expand All @@ -202,7 +202,7 @@ export class PDFSignature {
if (resolved.timestampAuthority) {
// Hash the signature value for timestamping
const signatureValue = signedData.getSignatureValue();
const signatureHash = hashData(signatureValue, resolved.digestAlgorithm);
const signatureHash = await hashData(signatureValue, resolved.digestAlgorithm);

// Request timestamp from TSA
const timestampToken = await resolved.timestampAuthority.timestamp(
Expand Down Expand Up @@ -476,7 +476,7 @@ export class PDFSignature {

// Hash and get timestamp
const signedBytes = extractSignedBytes(savedBytes, byteRange);
const documentHash = hashData(signedBytes, digestAlgorithm);
const documentHash = await hashData(signedBytes, digestAlgorithm);
const timestampToken = await timestampAuthority.timestamp(documentHash, digestAlgorithm);

// Patch Contents
Expand Down
14 changes: 7 additions & 7 deletions src/signatures/formats/cades-detached.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class CAdESDetachedBuilder implements CMSFormatBuilder, CMSSignedData {
const allCerts = [signerCert, ...chainCerts];

// Build signed attributes
const signedAttrs = this.buildSignedAttributes(
const signedAttrs = await this.buildSignedAttributes(
documentHash,
digestAlgorithm,
signer,
Expand Down Expand Up @@ -151,13 +151,13 @@ export class CAdESDetachedBuilder implements CMSFormatBuilder, CMSSignedData {
/**
* Build the signed attributes for CAdES signature.
*/
private buildSignedAttributes(
private async buildSignedAttributes(
documentHash: Uint8Array,
digestAlgorithm: DigestAlgorithm,
signer: Signer,
signerCert: pkijs.Certificate,
signingTime?: Date,
): pkijs.Attribute[] {
): Promise<pkijs.Attribute[]> {
const attrs: pkijs.Attribute[] = [];

// Content Type (required)
Expand Down Expand Up @@ -190,7 +190,7 @@ export class CAdESDetachedBuilder implements CMSFormatBuilder, CMSSignedData {
);

// ESS signing-certificate-v2 (required for CAdES/PAdES)
attrs.push(this.buildSigningCertificateV2(signerCert, digestAlgorithm));
attrs.push(await this.buildSigningCertificateV2(signerCert, digestAlgorithm));

return attrs;
}
Expand All @@ -213,13 +213,13 @@ export class CAdESDetachedBuilder implements CMSFormatBuilder, CMSSignedData {
* issuerSerial IssuerSerial OPTIONAL
* }
*/
private buildSigningCertificateV2(
private async buildSigningCertificateV2(
signerCert: pkijs.Certificate,
digestAlgorithm: DigestAlgorithm,
): pkijs.Attribute {
): Promise<pkijs.Attribute> {
// Hash the certificate
const certDer = signerCert.toSchema().toBER(false);
const certHash = hashData(new Uint8Array(certDer), digestAlgorithm);
const certHash = await hashData(new Uint8Array(certDer), digestAlgorithm);

// Build IssuerSerial using pkijs classes for proper encoding
// IssuerSerial ::= SEQUENCE {
Expand Down
25 changes: 13 additions & 12 deletions src/signatures/signers/google-kms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import { toArrayBuffer } from "#src/helpers/buffer.ts";
import { derToPem, isPem, normalizePem, parsePem } from "#src/helpers/pem.ts";
import { sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
import { fromBER } from "asn1js";
import * as pkijs from "pkijs";

Expand Down Expand Up @@ -659,7 +658,7 @@ export class GoogleKmsSigner implements Signer {
}

// Hash data locally and build digest object for KMS
const { digest, digestKey } = this.hashData(data, algorithm);
const { digest, digestKey } = await this.hashData(data, algorithm);

try {
const [response] = await this.client.asymmetricSign({
Expand Down Expand Up @@ -701,19 +700,21 @@ export class GoogleKmsSigner implements Signer {
/**
* Hash data using the specified algorithm.
*
* Uses the Web Crypto API for native-speed hashing.
*
* @returns The digest bytes and the KMS digest key name
*/
private hashData(
private async hashData(
data: Uint8Array,
algorithm: DigestAlgorithm,
): { digest: Uint8Array; digestKey: "sha256" | "sha384" | "sha512" } {
switch (algorithm) {
case "SHA-256":
return { digest: sha256(data), digestKey: "sha256" };
case "SHA-384":
return { digest: sha384(data), digestKey: "sha384" };
case "SHA-512":
return { digest: sha512(data), digestKey: "sha512" };
}
): Promise<{ digest: Uint8Array; digestKey: "sha256" | "sha384" | "sha512" }> {
const digestKeyMap: Record<DigestAlgorithm, "sha256" | "sha384" | "sha512"> = {
"SHA-256": "sha256",
"SHA-384": "sha384",
"SHA-512": "sha512",
};

const arrayBuffer = await crypto.subtle.digest(algorithm, data as Uint8Array<ArrayBuffer>);
return { digest: new Uint8Array(arrayBuffer), digestKey: digestKeyMap[algorithm] };
}
}
18 changes: 8 additions & 10 deletions src/signatures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Shared utilities for signature operations.
*/

import { sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
import { fromBER } from "asn1js";
import * as pkijs from "pkijs";

Expand Down Expand Up @@ -38,19 +37,18 @@ export function escapePdfString(str: string): string {
/**
* Hash data using the specified algorithm.
*
* Uses the Web Crypto API for native-speed hashing, which is significantly
* faster than pure-JS implementations for large inputs (e.g. hashing an
* entire PDF during signing).
*
* @param data - Data to hash
* @param algorithm - Digest algorithm
* @returns Hash bytes
*/
export function hashData(data: Uint8Array, algorithm: DigestAlgorithm): Uint8Array {
switch (algorithm) {
case "SHA-256":
return sha256(data);
case "SHA-384":
return sha384(data);
case "SHA-512":
return sha512(data);
}
export async function hashData(data: Uint8Array, algorithm: DigestAlgorithm): Promise<Uint8Array> {
const digest = await crypto.subtle.digest(algorithm, data as Uint8Array<ArrayBuffer>);

return new Uint8Array(digest);
}

// ─────────────────────────────────────────────────────────────────────────────
Expand Down