import { sha256 } from "@suaveplan/crypto-hash"; import { toHex } from "@suaveplan/crypto-utils"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { RSA_2048_PUBLIC_KEY } from "../__fixtures__/rsa-2048-key.js"; import { CRYPTO_RSA_CODES, type CryptoRsaError } from "../errors/errors.js"; import { serializeRsaPublicKeySpki } from "../keys/serialize-spki.js"; import { computeSpkiFingerprint } from "./spki.js"; describe("computeSpkiFingerprint", () => { it("hashes the SPKI DER bytes with SHA-256 by default", { timeout: 5000, }, () => { const fingerprint = computeSpkiFingerprint(RSA_2048_PUBLIC_KEY); const expected = sha256(serializeRsaPublicKeySpki(RSA_2048_PUBLIC_KEY)); expect(toHex(fingerprint)).toBe(toHex(expected)); expect(fingerprint.length).toBe(32); }); it("supports SHA-1 / SHA-384 / SHA-512 overrides", { timeout: 5000, }, () => { const sha1 = computeSpkiFingerprint(RSA_2048_PUBLIC_KEY, { hash: "SHA-1", }); const sha384 = computeSpkiFingerprint(RSA_2048_PUBLIC_KEY, { hash: "SHA-384", }); const sha512 = computeSpkiFingerprint(RSA_2048_PUBLIC_KEY, { hash: "SHA-512", }); expect(sha1.length).toBe(20); expect(sha384.length).toBe(48); expect(sha512.length).toBe(64); }); it("rejects unsupported hash with UNSUPPORTED_HASH", { timeout: 5000, }, () => { try { computeSpkiFingerprint(RSA_2048_PUBLIC_KEY, { hash: "MD5" as never, }); throw new Error("should have thrown"); } catch (err) { expect((err as CryptoRsaError).code).toBe( CRYPTO_RSA_CODES.UNSUPPORTED_HASH ); } }); it("wraps SPKI serialiser failure as FINGERPRINT_FAILED", { timeout: 5000, }, () => { // n=0n forces the i2osp path inside SPKI serialise to throw. const broken = { ...RSA_2048_PUBLIC_KEY, n: -1n }; try { computeSpkiFingerprint(broken); throw new Error("should have thrown"); } catch (err) { expect((err as CryptoRsaError).code).toBe( CRYPTO_RSA_CODES.FINGERPRINT_FAILED ); } }); });