diff --git a/index.php b/index.php index fcfceb4..5bd2a78 100644 --- a/index.php +++ b/index.php @@ -1485,13 +1485,46 @@ HTML; $headers = array_change_key_case( $headers, CASE_LOWER ); // Validate the timestamp is within ±30 seconds - if ( !isset( $headers["date"] ) ) { return null; } // No date set + // 7.2.4 of https://datatracker.ietf.org/doc/rfc9421/ says compare the Date header and the published date of the message + if ( !isset( $headers["date"] ) ) { + // No date set + // Filename for the log + $filename = "{$timestamp}.{$type}.Signature.Date_Failure.txt"; + + // Save headers and request data to the timestamped file in the logs directory + file_put_contents( $directories["logs"] . "/{$filename}", + "Original Body:\n" . print_r( $body, true ) . "\n\n" . + "Original Headers:\n" . print_r( $headers, true ) . "\n\n" + ); + return null; + } $dateHeader = $headers["date"]; $headerDatetime = DateTime::createFromFormat('D, d M Y H:i:s T', $dateHeader); $currentDatetime = new DateTime(); + // First, check if the message was sent more than 30 seconds ago // Calculate the time difference in seconds $timeDifference = abs( $currentDatetime->getTimestamp() - $headerDatetime->getTimestamp() ); + if ( $timeDifference > 30 ) { + // Write a log detailing the error + // Filename for the log + $filename = "{$timestamp}.{$type}.Signature.Delay_Failure.txt"; + + // Save headers and request data to the timestamped file in the logs directory + file_put_contents( $directories["logs"] . "/{$filename}", + "Header Date:\n" . print_r( $dateHeader, true ) . "\n" . + "Server Date:\n" . print_r( $currentDatetime->format('D, d M Y H:i:s T'), true ) ."\n" . + "Original Body:\n" . print_r( $body, true ) . "\n\n" . + "Original Headers:\n" . print_r( $headers, true ) . "\n\n" + ); + return false; + } + + // Is there a significant difference between the Date header and the published timestamp? + $published = $body["published"]; + $publishedDatetime = new DateTime($published); + // Calculate the time difference in seconds + $timeDifference = abs( $publishedDatetime->getTimestamp() - $headerDatetime->getTimestamp() ); if ( $timeDifference > 30 ) { // Write a log detailing the error // Filename for the log @@ -1499,8 +1532,10 @@ HTML; // Save headers and request data to the timestamped file in the logs directory file_put_contents( $directories["logs"] . "/{$filename}", - "Original Date:\n" . print_r( $dateHeader, true ) . "\n" . - "Local Date:\n" . print_r( $currentDatetime->format('D, d M Y H:i:s T'), true ) . "\n" + "Header Date:\n" . print_r( $dateHeader, true ) . "\n" . + "Published Date:\n" . print_r( $publishedDatetime->format('D, d M Y H:i:s T'), true ) ."\n" . + "Original Body:\n" . print_r( $body, true ) . "\n\n" . + "Original Headers:\n" . print_r( $headers, true ) . "\n\n" ); return false; } @@ -1588,38 +1623,50 @@ HTML; $actorPublicKey = $actorData["publicKey"]["publicKeyPem"]; if ( $publicKey != $actorPublicKey ) { - $verified = false; - } else { - // Get the remaining parts - $signature = base64_decode( $signatureParts["signature"] ); - $algorithm = $signatureParts["algorithm"]; + // Filename for the log + $filename = "{$timestamp}.{$type}.Signature.Mismatch_Failure.txt"; - // There might be many different signing algorithms - // TODO: Find a way to transform these automatically - // See https://github.com/superseriousbusiness/gotosocial/issues/1186#issuecomment-1976166659 and https://github.com/snarfed/bridgy-fed/issues/430 for hs2019 - if ( "hs2019" == $algorithm ) { - $algorithm = "sha256"; - } - - // Finally! Calculate whether the signature is valid - // Returns 1 if verified, 0 if not, false or -1 if an error occurred - $verified = openssl_verify( - $signatureString, - $signature, - $publicKey, - $algorithm + // Save headers and request data to the timestamped file in the logs directory + file_put_contents( $directories["logs"] . "/{$filename}", + "Original Body:\n" . print_r( $body, true ) . "\n\n" . + "Original Headers:\n" . print_r( $headers, true ) . "\n\n" . + "Signature Headers:\n" . print_r( $signatureHeaders, true ) . "\n\n" . + "publicKeyURL:\n" . print_r( $publicKeyURL, true ) . "\n\n" . + "publicKey:\n" . print_r( $publicKey, true ) . "\n\n" . + "actorPublicKey:\n" . print_r( $actorPublicKey, true ) . "\n" ); + return false; + } + + // Get the remaining parts + $signature = base64_decode( $signatureParts["signature"] ); + $algorithm = $signatureParts["algorithm"]; - // Convert to boolean - if ( $verified === 1 ) { - $verified = true; - } elseif ( $verified === 0 ) { - $verified = false; - } else { - $verified = null; - } + // There might be many different signing algorithms + // TODO: Find a way to transform these automatically + // See https://github.com/superseriousbusiness/gotosocial/issues/1186#issuecomment-1976166659 and https://github.com/snarfed/bridgy-fed/issues/430 for hs2019 + if ( "hs2019" == $algorithm ) { + $algorithm = "sha256"; } + // Finally! Calculate whether the signature is valid + // Returns 1 if verified, 0 if not, false or -1 if an error occurred + $verified = openssl_verify( + $signatureString, + $signature, + $publicKey, + $algorithm + ); + + // Convert to boolean + if ( $verified === 1 ) { + $verified = true; + } elseif ( $verified === 0 ) { + $verified = false; + } else { + $verified = null; + } + // Filename for the log $filename = "{$timestamp}.{$type}.Signature.". json_encode( $verified ) . ".txt";