Unverified Commit df8ca2d0 authored by Hong Minhee's avatar Hong Minhee
Browse files

Merge tag '1.6.4' into 1.7-maintenance

Fedify 1.6.4
parents 83888ef3 96de5efc
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -8,6 +8,11 @@ Version 1.7.2

To be released.

 -  Fixed HTTP signature verification to handle malformed RFC 9421 signatures
    gracefully instead of returning `500 Internal Server Error` responses.
    Malformed signatures now properly fail verification and return appropriate
    error responses.


Version 1.7.1
-------------
@@ -49,6 +54,17 @@ Released on June 25, 2025.
[#252]: https://github.com/fedify-dev/fedify/pull/252


Version 1.6.4
-------------

Released on July 2, 2025.

 -  Fixed HTTP signature verification to handle malformed RFC 9421 signatures
    gracefully instead of returning `500 Internal Server Error` responses.
    Malformed signatures now properly fail verification and return appropriate
    error responses.


Version 1.6.3
-------------

+64 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import {
  assertExists,
  assertFalse,
  assertStringIncludes,
  assertThrows,
} from "@std/assert";
import { encodeBase64 } from "byte-encodings/base64";
import fetchMock from "fetch-mock";
@@ -1813,3 +1814,66 @@ test("timingSafeEqual()", async (t) => {
    },
  );
});

test("signRequest() [rfc9421] error handling for invalid signature base creation", async () => {
  // Test that createRfc9421SignatureBase errors are properly caught and wrapped
  // We'll test this by directly calling createRfc9421SignatureBase with invalid input
  const request = new Request("https://example.com/test", {
    method: "POST",
    body: "test body",
  });

  // First verify that createRfc9421SignatureBase throws for unsupported components
  await assertThrows(
    () => {
      createRfc9421SignatureBase(
        request,
        ["@unsupported"], // This will trigger the "Unsupported derived component" error
        'alg="rsa-pss-sha256";keyid="https://example.com/key2";created=1234567890',
      );
    },
    Error,
    "Unsupported derived component: @unsupported",
  );

  // The actual error handling in signRequest is tested indirectly by ensuring
  // that normal signing operations work without throwing the wrapped error
  const signedRequest = await signRequest(
    request,
    rsaPrivateKey2,
    new URL("https://example.com/key2"),
    { spec: "rfc9421" },
  );

  // Verify that the request was signed successfully
  assertExists(signedRequest.headers.get("Signature-Input"));
  assertExists(signedRequest.headers.get("Signature"));
});

test("verifyRequest() [rfc9421] error handling for invalid signature base creation", async () => {
  // Create a request with a malformed signature input that will cause createRfc9421SignatureBase to fail
  const request = new Request("https://example.com/test", {
    method: "GET",
    headers: {
      "Accept": "application/json",
      // Add a malformed signature input that references an unsupported component
      "Signature-Input":
        'sig1=("@unsupported");alg="rsa-pss-sha256";keyid="https://example.com/key2";created=1234567890',
      "Signature": "sig1=:invalid_signature_data:",
    },
  });

  // Attempt verification with the malformed signature input
  // This should fail gracefully and return null instead of throwing
  const result = await verifyRequest(request, {
    spec: "rfc9421",
    documentLoader: mockDocumentLoader,
    contextLoader: mockDocumentLoader,
  });

  assertEquals(
    result,
    null,
    "Verification should fail gracefully for malformed signature inputs",
  );
});
+30 −13
Original line number Diff line number Diff line
@@ -434,7 +434,9 @@ async function signRequestRfc9421(
    keyId,
    created,
  });
  const signatureBase = createRfc9421SignatureBase(
  let signatureBase: string;
  try {
    signatureBase = createRfc9421SignatureBase(
      new Request(request.url, {
        method: request.method,
        headers,
@@ -442,6 +444,12 @@ async function signRequestRfc9421(
      components,
      signatureParams,
    );
  } catch (error) {
    throw new TypeError(
      `Failed to create signature base: ${String(error)}; it is probably ` +
        `a bug in the implementation.  Please report it at Fedify's issue tracker.`,
    );
  }

  // Sign the signature base
  const signatureBytes = await crypto.subtle.sign(
@@ -1094,11 +1102,20 @@ async function verifyRequestRfc9421(
    }

    // Rebuild the signature base for verification
    const signatureBase = createRfc9421SignatureBase(
    let signatureBase: string;
    try {
      signatureBase = createRfc9421SignatureBase(
        request,
        sigInput.components,
        sigInput.parameters,
      );
    } catch (error) {
      logger.debug(
        "Failed to create signature base for verification: {error}",
        { error, signatureInput: sigInput },
      );
      continue;
    }
    const signatureBaseBytes = new TextEncoder().encode(signatureBase);

    // Verify the signature