get('SigningCertURL'); $this->validateUrl($certUrl); // Get the cert itself and extract the public key $response = wp_remote_get($certUrl); if (is_wp_error($response)) throw new CannotGetPublicKeyFromCertificateException('Could not retrieve certificate from ' . $certUrl); $certificate = wp_remote_retrieve_body($response); $publicKey = openssl_get_publickey($certificate); if (!$publicKey) { throw new CannotGetPublicKeyFromCertificateException('Could not extract public key from ' . $certUrl); } // Verify the signature of the message $stringToSign = $message->getStringToSign(); $incomingSignature = base64_decode($message->get('Signature')); if (0 !== openssl_verify($stringToSign, $incomingSignature, $publicKey, OPENSSL_ALGO_SHA1)) { throw new InvalidMessageSignatureException('The message did not match the signature ' . "\n" . $stringToSign); } } /** * Ensures that the URL of the certificate is one belonging to AWS, and not * just something from the amazonaws domain, which could include S3 buckets. * * @param string $url Certificate URL * * @throws InvalidSnsMessageException if the cert url is invalid. */ private function validateUrl($url) { $parsed = parse_url($url); if (empty($parsed['scheme']) || empty($parsed['host']) || $parsed['scheme'] !== 'https' || substr($url, -4) !== '.pem' || !preg_match($this->hostPattern, $parsed['host']) ) { throw new InvalidSnsMessageException( 'The certificate is located on an invalid domain.' ); } } /** * Determines if a message is valid and that is was delivered by AWS. This method does not throw exceptions and * returns a simple boolean value. * * @param Message $message The message to validate * @return bool */ public function isValid($message) { try { $this->validate($message); return true; } catch (SnsMessageValidatorException $e) { $error = $e->getMessage(); return false; } } }