Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions src/Library/Encryption/JWEDecrypter.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,12 @@ private function decryptRecipientKey(
);
$this->checkCompleteHeader($completeHeader);

$key_encryption_algorithm = $this->getKeyEncryptionAlgorithm($completeHeader);
$content_encryption_algorithm = $this->getContentEncryptionAlgorithm($completeHeader);
// RFC 7516 §4.1.1 (alg) and §4.1.2 (enc) require both parameters to be
// integrity-protected. Reading them from the merged $completeHeader allows
// an attacker to override either value via an unprotected header field.
$sharedProtectedHeader = $jwe->getSharedProtectedHeader();
$key_encryption_algorithm = $this->getKeyEncryptionAlgorithm($sharedProtectedHeader);
$content_encryption_algorithm = $this->getContentEncryptionAlgorithm($sharedProtectedHeader);

$this->checkIvSize($jwe->getIV(), $content_encryption_algorithm->getIVSize());

Expand Down Expand Up @@ -253,26 +257,38 @@ private function checkCompleteHeader(array $completeHeaders): void
}
}

private function getKeyEncryptionAlgorithm(array $completeHeaders): KeyEncryptionAlgorithm
private function getKeyEncryptionAlgorithm(array $protectedHeader): KeyEncryptionAlgorithm
{
$key_encryption_algorithm = $this->keyEncryptionAlgorithmManager->get($completeHeaders['alg']);
$alg = $protectedHeader['alg'] ?? null;
if (! is_string($alg) || $alg === '') {
throw new InvalidArgumentException(
'The "alg" parameter must be a non-empty string in the protected header (RFC 7516 §4.1.1).'
);
}
$key_encryption_algorithm = $this->keyEncryptionAlgorithmManager->get($alg);
if (! $key_encryption_algorithm instanceof KeyEncryptionAlgorithm) {
throw new InvalidArgumentException(sprintf(
'The key encryption algorithm "%s" is not supported or does not implement KeyEncryptionAlgorithm interface.',
$completeHeaders['alg']
$alg
));
}

return $key_encryption_algorithm;
}

private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm
private function getContentEncryptionAlgorithm(array $protectedHeader): ContentEncryptionAlgorithm
{
$content_encryption_algorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']);
$enc = $protectedHeader['enc'] ?? null;
if (! is_string($enc) || $enc === '') {
throw new InvalidArgumentException(
'The "enc" parameter must be a non-empty string in the protected header (RFC 7516 §4.1.2).'
);
}
$content_encryption_algorithm = $this->contentEncryptionAlgorithmManager->get($enc);
if (! $content_encryption_algorithm instanceof ContentEncryptionAlgorithm) {
throw new InvalidArgumentException(sprintf(
'The key encryption algorithm "%s" is not supported or does not implement the ContentEncryption interface.',
$completeHeader['enc']
'The content encryption algorithm "%s" is not supported or does not implement the ContentEncryption interface.',
$enc
));
}

Expand Down
Loading