/** * @param CertificateValidatorInterface|NULL $certValidator * @param string $blob * @return AppMetasMessage * Validated message. * @throws InvalidMessageException */ public static function decode($certValidator, $blob) { $parts = explode(Constants::PROTOCOL_DELIM, $blob, 4); if (count($parts) != 4) { throw new InvalidMessageException('Invalid message: insufficient parameters'); } list($wireProt, $wireCert, $wireSig, $wireEnvelope) = $parts; if ($wireProt != self::NAME) { throw new InvalidMessageException('Invalid message: wrong protocol name'); } if ($certValidator !== NULL) { $certValidator->validateCert($wireCert); $wireCertX509 = new \File_X509(); $wireCertX509->loadX509($wireCert); $cn = $wireCertX509->getDNProp('CN'); if (count($cn) != 1 || $cn[0] != Constants::OFFICIAL_APPMETAS_CN) { throw new InvalidMessageException('Invalid message: signed by unauthorized party'); } $isValid = UserError::adapt('Civi\\Cxn\\Rpc\\Exception\\InvalidMessageException', function () use($wireCertX509, $wireEnvelope, $wireSig) { return AppMetasMessage::getRsaFromCert($wireCertX509)->verify($wireEnvelope, base64_decode($wireSig)); }); if (!$isValid) { throw new InvalidMessageException("Invalid message: incorrect signature"); } } $envelope = json_decode($wireEnvelope, TRUE); if (empty($envelope)) { throw new InvalidMessageException("Invalid message: malformed envelope"); } if (Time::getTime() > $envelope['ttl']) { throw new InvalidMessageException("Invalid message: expired"); } return new AppMetasMessage($wireCert, NULL, json_decode($envelope['r'], TRUE)); }