Esempio n. 1
0
 /**
  * @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));
 }
Esempio n. 2
0
 /**
  * @param array $caKeyPair
  * @param string $caCert
  *   PEM-encoded cert.
  * @param string $csr
  *   PEM-encoded CSR.
  * @param int $serialNumber
  * @return string
  *   PEM-encoded cert.
  */
 public static function signCSR($caKeyPair, $caCert, $csr, $serialNumber = 1)
 {
     $privKey = new \Crypt_RSA();
     $privKey->loadKey($caKeyPair['privatekey']);
     $subject = new \File_X509();
     $subject->loadCSR($csr);
     $issuer = new \File_X509();
     $issuer->loadX509($caCert);
     $issuer->setPrivateKey($privKey);
     $x509 = new \File_X509();
     $x509->setSerialNumber($serialNumber, 10);
     $x509->setEndDate(date('c', strtotime(Constants::APP_DURATION, Time::getTime())));
     $result = $x509->sign($issuer, $subject, Constants::CERT_SIGNATURE_ALGORITHM);
     return $x509->saveX509($result);
 }
 protected static function validate($certPem, $caCertPem, $crlPem = NULL, $crlDistCertPem = NULL)
 {
     $caCertObj = X509Util::loadCACert($caCertPem);
     $certObj = new \File_X509();
     $certObj->loadCA($caCertPem);
     if ($crlPem !== NULL) {
         $crlObj = new \File_X509();
         if ($crlDistCertPem) {
             $crlDistCertObj = X509Util::loadCrlDistCert($crlDistCertPem, NULL, $caCertPem);
             if ($crlDistCertObj->getSubjectDN(FILE_X509_DN_STRING) !== $caCertObj->getSubjectDN(FILE_X509_DN_STRING)) {
                 throw new InvalidCertException(sprintf("CRL distributor (%s) does not act on behalf of this CA (%s)", $crlDistCertObj->getSubjectDN(FILE_X509_DN_STRING), $caCertObj->getSubjectDN(FILE_X509_DN_STRING)));
             }
             try {
                 self::validate($crlDistCertPem, $caCertPem);
             } catch (InvalidCertException $ie) {
                 throw new InvalidCertException("CRL distributor has an invalid certificate", 0, $ie);
             }
             $crlObj->loadCA($crlDistCertPem);
         }
         $crlObj->loadCA($caCertPem);
         $crlObj->loadCRL($crlPem);
         if (!$crlObj->validateSignature()) {
             throw new InvalidCertException("CRL signature is invalid");
         }
     }
     $parsedCert = $certObj->loadX509($certPem);
     if ($crlPem !== NULL) {
         if (empty($parsedCert)) {
             throw new InvalidCertException("Identity is invalid. Empty certificate.");
         }
         if (empty($parsedCert['tbsCertificate']['serialNumber'])) {
             throw new InvalidCertException("Identity is invalid. No serial number.");
         }
         $revoked = $crlObj->getRevoked($parsedCert['tbsCertificate']['serialNumber']->toString());
         if (!empty($revoked)) {
             throw new InvalidCertException("Identity is invalid. Certificate revoked.");
         }
     }
     if (!$certObj->validateSignature()) {
         throw new InvalidCertException("Identity is invalid. Certificate is not signed by proper CA.");
     }
     if (!$certObj->validateDate(Time::getTime())) {
         throw new ExpiredCertException("Identity is invalid. Certificate expired.");
     }
 }
Esempio n. 4
0
 /**
  * Validate the signature and date of the message, then
  * decrypt it.
  *
  * @param string $secret
  * @param string $body
  * @param string $signature
  * @return string
  *   Plain text.
  * @throws InvalidMessageException
  */
 public static function authenticateThenDecrypt($secret, $body, $signature)
 {
     $keys = self::deriveAesKeys($secret);
     $localHmac = hash_hmac('sha256', $body, $keys['auth']);
     if (!self::hash_compare($signature, $localHmac)) {
         throw new InvalidMessageException("Incorrect hash");
     }
     list($jsonEnvelope, $jsonEncrypted) = explode(Constants::PROTOCOL_DELIM, $body, 2);
     if (strlen($jsonEnvelope) > Constants::MAX_ENVELOPE_BYTES) {
         throw new InvalidMessageException("Oversized envelope");
     }
     $envelope = json_decode($jsonEnvelope, TRUE);
     if (!$envelope) {
         throw new InvalidMessageException("Malformed envelope");
     }
     if (!is_numeric($envelope['ttl']) || Time::getTime() > $envelope['ttl']) {
         throw new InvalidMessageException("Invalid TTL");
     }
     if (!is_string($envelope['iv']) || strlen($envelope['iv']) !== Constants::AES_BYTES * 2 || !preg_match('/^[a-f0-9]+$/', $envelope['iv'])) {
         // AES_BYTES (32) ==> bin2hex ==> 2 hex digits (4-bit) per byte (8-bit)
         throw new InvalidMessageException("Malformed initialization vector");
     }
     $jsonPlaintext = UserError::adapt('Civi\\Cxn\\Rpc\\Exception\\InvalidMessageException', function () use($jsonEncrypted, $envelope, $keys) {
         $cipher = new \Crypt_AES(CRYPT_AES_MODE_CBC);
         $cipher->setKeyLength(Constants::AES_BYTES);
         $cipher->setKey($keys['enc']);
         $cipher->setIV(BinHex::hex2bin($envelope['iv']));
         return $cipher->decrypt($jsonEncrypted);
     });
     return $jsonPlaintext;
 }