/** * @param string $input * @return array * @throws InvalidJWTException */ public static function deserialize($input) { $e_parts = explode(IBasicJWT::SegmentSeparator, $input); if (count($e_parts) < 2) { throw new InvalidJWTException(sprintf('%s has only 2 or less encoded parts!')); } $e_header = $e_parts[0]; $e_payload = $e_parts[1]; $e_signature = count($e_parts) > 2 ? $e_parts[2] : ''; $header = JOSEHeaderSerializer::deserialize($e_header); $payload = $header->getType()->getString() === 'JWT' ? JWTClaimSetSerializer::deserialize($e_payload) : JWTRawSerializer::deserialize($e_payload); $signature = !empty($e_signature) ? JWTRawSerializer::deserialize($e_signature) : ''; return array($header, $payload, $signature); }
/** * https://tools.ietf.org/html/rfc7516#section-9 * @param string $compact_serialization * @return IBasicJWT * @throws InvalidJWKType * @throws InvalidCompactSerializationException */ public static function build($compact_serialization) { $segments = explode(IBasicJWT::SegmentSeparator, $compact_serialization); // JWSs have three segments separated by two period ('.') characters. // JWEs have five segments separated by four period ('.') characters. switch (count($segments)) { case 3: // JWS or unsecured one $header = JOSEHeaderSerializer::deserialize($segments[0]); if ($header->getAlgorithm()->getString() === 'none' && empty($segments[2])) { return UnsecuredJWT::fromCompactSerialization($compact_serialization); } return JWSFactory::build(new JWS_CompactFormatSpecification($compact_serialization)); break; case 5: // JWE return JWEFactory::build(new JWE_CompactFormatSpecification($compact_serialization)); break; default: throw new InvalidCompactSerializationException(); break; } return null; }
/** * @return $this * @throws InvalidJWKAlgorithm * @throws InvalidKeyTypeAlgorithmException * @throws JWEInvalidCompactFormatException * @throws JWEInvalidRecipientKeyException * @throws JWEUnsupportedContentEncryptionAlgorithmException * @throws JWEUnsupportedKeyManagementAlgorithmException * @throws \Exception */ private function decrypt() { if (is_null($this->jwk)) { throw new JWEInvalidRecipientKeyException(); } if (!$this->should_decrypt) { return $this; } if ($this->jwk->getAlgorithm()->getValue() !== $this->header->getAlgorithm()->getString()) { throw new InvalidJWKAlgorithm(sprintf('mismatch between algorithm intended for use with the key %s and the cryptographic algorithm used to encrypt or determine the value of the CEK %s', $this->jwk->getAlgorithm()->getValue(), $this->header->getAlgorithm()->getString())); } $key_management_algorithm = KeyManagementAlgorithms_Registry::getInstance()->get($this->header->getAlgorithm()->getString()); if (is_null($key_management_algorithm)) { throw new JWEUnsupportedKeyManagementAlgorithmException(sprintf('alg %s', $this->header->getAlgorithm()->getString())); } $content_encryption_algorithm = ContentEncryptionAlgorithms_Registry::getInstance()->get($this->header->getEncryptionAlgorithm()->getString()); if (is_null($content_encryption_algorithm)) { throw new JWEUnsupportedContentEncryptionAlgorithmException(sprintf('enc %s', $this->header->getEncryptionAlgorithm()->getString())); } $this->cek = $this->decryptJWEEncryptedKey($key_management_algorithm); // We encrypt the payload and get the tag $jwt_shared_protected_header = JOSEHeaderSerializer::serialize($this->header); /** * Decrypt the JWE Cipher Text using the CEK, the JWE Initialization * Vector, the Additional Authenticated Data value, and the JWE * Authentication Tag (which is the Authentication Tag input to the * calculation) using the specified content encryption algorithm, * returning the decrypted plaintext and validating the JWE * Authentication Tag in the manner specified for the algorithm, * rejecting the input without emitting any decrypted output if the * JWE Authentication Tag is incorrect. */ $plain_text = $content_encryption_algorithm->decrypt($this->cipher_text, $this->cek->getEncoded(), $this->iv, $jwt_shared_protected_header, $this->tag); $zip = $this->header->getCompressionAlgorithm(); /** * If a "zip" parameter was included, uncompress the decrypted * plaintext using the specified compression algorithm. */ if (!is_null($zip)) { $compression__algorithm = CompressionAlgorithms_Registry::getInstance()->get($zip->getValue()); $plain_text = $compression__algorithm->uncompress($plain_text); } $this->setPayload(JWSPayloadFactory::build($plain_text)); $this->should_decrypt = false; return $this; }
/** * @param string $original_alg * @return bool * @throws InvalidJWKAlgorithm * @throws JWSInvalidJWKException * @throws JWSInvalidPayloadException * @throws JWSNotSupportedAlgorithm */ public function verify($original_alg) { if (is_null($this->jwk)) { throw new JWSInvalidJWKException(); } if ($this->jwk->getKeyUse()->getString() !== JSONWebKeyPublicKeyUseValues::Signature) { throw new JWSInvalidJWKException(sprintf('use %s not supported ', $this->jwk->getKeyUse()->getString())); } if (is_null($this->jwk->getAlgorithm())) { throw new InvalidJWKAlgorithm('algorithm intended for use with the key is not set! '); } if (!is_null($this->jwk->getId()) && !is_null($this->header->getKeyID()) && $this->header->getKeyID()->getValue() != $this->jwk->getId()->getValue()) { throw new JWSInvalidJWKException(sprintf('original kid %s - current kid %s', $this->header->getKeyID()->getValue(), $this->jwk->getId()->getValue())); } $alg = DigitalSignatures_MACs_Registry::getInstance()->get($original_alg); if (is_null($alg)) { throw new JWSNotSupportedAlgorithm(sprintf('algo %s', $original_alg)); } $former_alg = $this->header->getAlgorithm()->getString(); if ($former_alg != $original_alg) { throw new JWSNotSupportedAlgorithm(sprintf('former alg %s - original alg %s', $former_alg, $original_alg)); } if ($this->jwk->getAlgorithm()->getValue() !== $original_alg) { throw new InvalidJWKAlgorithm(sprintf('mismatch between algorithm intended for use with the key %s and the cryptographic algorithm used to secure the JWS %s', $this->jwk->getAlgorithm()->getValue(), $original_alg)); } $secured_input_bytes = JOSEHeaderSerializer::serialize($this->header) . IBasicJWT::SegmentSeparator . $this->getEncodedPayload(); // use public key / secret $key = $this->jwk->getKey(JSONWebKeyKeyOperationsValues::VerifyDigitalSignatureOrMAC); return $alg->verify($key, $secured_input_bytes, $this->signature); }