_verifySignature = $verifySignature; } /** * Validate that the given sns message is valid * defined as being signed by Amazon and that the * signature matches the message contents * * @param Message $snsMessage sns message to check * * @throws OffAmazonPaymentsNotifications_InvalidMessageException if the * validation * fails * * @return void */ public function validateMessage(Message $snsMessage) { switch($snsMessage->getMandatoryField("SignatureVersion")) { case "1": $this->_verifySignatureWithVersionOneAlgorithm($snsMessage); break; default: throw new OffAmazonPaymentsNotifications_InvalidMessageException( "Error with signature verification - " . "unable to handle signature version " . $snsMessage->getMandatoryField("SignatureVersion") ); } } /** * Implement the version one signature verification algorithm * * @param Message $snsMessage sns message * * @throws OffAmazonPaymentsNotifications_InvalidMessageException if the * validation * fails * * @return void */ private function _verifySignatureWithVersionOneAlgorithm(Message $snsMessage) { $result = $this->_verifySignature->verifySignatureIsCorrect( $this->_constructSignatureFromSnsMessage($snsMessage), base64_decode($snsMessage->getMandatoryField("Signature")), $snsMessage->getMandatoryField("SigningCertURL") ); if (!$result) { throw new OffAmazonPaymentsNotifications_InvalidMessageException( "Unable to match signature from remote server: signature of " . $this->_constructSignatureFromSnsMessage($snsMessage) . " , SigningCertURL of " . $snsMessage->getMandatoryField("SigningCertURL") . " , SignatureOf " . $snsMessage->getMandatoryField("Signature") ); } } /** * Recreate the signature based on the field values for the * sns message * * @param Message $snsMessage sns message * * @throws OffAmazonPaymentsNotifications_InvalidMessageException if the * validation * fails * * @return string signature string */ private function _constructSignatureFromSnsMessage(Message $snsMessage) { if (strcmp($snsMessage->getMandatoryField("Type"), "Notification") != 0) { throw new OffAmazonPaymentsNotifications_InvalidMessageException( "Error with signature verification - unable to verify " . $snsMessage->getMandatoryField("Type") . " message" ); } // get the list of fields that we are interested in $fields = array( "Timestamp" => true, "Message" => true, "MessageId" => true, "Subject" => false, "TopicArn" => true, "Type" => true ); // sort the fields into byte order based on the key name(A-Za-z) ksort($fields); // extract the key value pairs and sort in byte order $signatureFields = array(); foreach ($fields as $fieldName => $mandatoryField) { if ($mandatoryField) { $value = $snsMessage->getMandatoryField($fieldName); } else { $value = $snsMessage->getField($fieldName); } if (!is_null($value)) { array_push($signatureFields, $fieldName); array_push($signatureFields, $value); } } // create the signature string - key / value in byte order // delimited by newline character + ending with a new line character return implode("\n", $signatureFields) . "\n"; } }