Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 5 additions & 2 deletions src/functions/public/ConvertTo-Base64UrlString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
System.String

.NOTES
Converts standard base64 output to JWT-safe base64url text by replacing URL-sensitive characters and removing padding.
Converts standard base64 output to JWT-safe base64url text by replacing URL-sensitive
characters and removing padding.

.LINK
https://psmodule.io/Jwt/Functions/ConvertTo-Base64UrlString/
Expand All @@ -48,7 +49,9 @@
} elseif ($InputObject -is [byte[]]) {
[Convert]::ToBase64String($InputObject) -replace '\+', '-' -replace '/', '_' -replace '='
} else {
throw [System.ArgumentException]::new("ConvertTo-Base64UrlString requires string or byte array input, received $($InputObject.GetType())")
$type = $InputObject.GetType()
$message = "ConvertTo-Base64UrlString requires string or byte array input, received $type"
throw [System.ArgumentException]::new($message)
}
}

Expand Down
24 changes: 17 additions & 7 deletions src/functions/public/New-Jwt.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
try {
$algorithm = (ConvertFrom-Json -InputObject $Header -ErrorAction Stop).alg
} catch {
throw [System.FormatException]::new("The supplied JWT header is not valid JSON. Header length: $($Header.Length) characters.")
$message = "The supplied JWT header is not valid JSON. Header length: $($Header.Length) characters."
throw [System.FormatException]::new($message)
}
if ([string]::IsNullOrEmpty($algorithm)) {
throw [System.FormatException]::new('The JWT header is missing the required "alg" claim.')
Expand All @@ -87,7 +88,8 @@
try {
$null = ConvertFrom-Json -InputObject $PayloadJson -ErrorAction Stop
} catch {
throw [System.FormatException]::new("The supplied JWT payload is not valid JSON. Payload length: $($PayloadJson.Length) characters.")
$message = "The supplied JWT payload is not valid JSON. Payload length: $($PayloadJson.Length) characters."
throw [System.FormatException]::new($message)
}

$encodedHeader = ConvertTo-Base64UrlString $Header
Expand All @@ -98,12 +100,14 @@
switch ($algorithm) {
'RS256' {
if (-not $PSBoundParameters.ContainsKey('Cert')) {
throw [System.ArgumentException]::new('RS256 requires a -Cert parameter of type X509Certificate2.', 'Cert')
$message = 'RS256 requires a -Cert parameter of type X509Certificate2.'
throw [System.ArgumentException]::new($message, 'Cert')
}
Write-Verbose "Signing certificate: $($Cert.Subject)"
$rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($Cert)
if ($null -eq $rsa) {
throw [System.ArgumentException]::new('The supplied certificate has no RSA private key and cannot be used to sign.', 'Cert')
$message = 'The supplied certificate has no RSA private key and cannot be used to sign.'
throw [System.ArgumentException]::new($message, 'Cert')
} else {
try {
$signature = $rsa.SignData(
Expand All @@ -125,11 +129,16 @@
throw [System.ArgumentException]::new('HS256 requires a -Secret parameter.', 'Secret')
}
if ($Secret -isnot [byte[]] -and $Secret -isnot [string]) {
throw [System.ArgumentException]::new("Expected Secret parameter as byte array or string, instead got $($Secret.GetType())", 'Secret')
$message = "Expected Secret parameter as byte array or string, instead got $($Secret.GetType())"
throw [System.ArgumentException]::new($message, 'Secret')
}
$hmacsha256 = [System.Security.Cryptography.HMACSHA256]::new()
try {
$hmacsha256.Key = if ($Secret -is [byte[]]) { $Secret } else { [System.Text.Encoding]::UTF8.GetBytes($Secret) }
$hmacsha256.Key = if ($Secret -is [byte[]]) {
$Secret
} else {
[System.Text.Encoding]::UTF8.GetBytes($Secret)
}
$encodedSignature = ConvertTo-Base64UrlString $hmacsha256.ComputeHash($contentBytes)
} catch {
throw [System.Exception]::new("Signing with HMACSHA256 failed: $_", $_.Exception)
Expand All @@ -141,7 +150,8 @@
$encodedSignature = $null
}
default {
throw [System.NotSupportedException]::new('The algorithm is not one of the supported: "RS256", "HS256", "none".')
$message = 'The algorithm is not one of the supported: "RS256", "HS256", "none".'
throw [System.NotSupportedException]::new($message)
}
}

Expand Down
21 changes: 15 additions & 6 deletions src/functions/public/Test-Jwt.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ function Test-Jwt {
try {
$algorithm = (ConvertFrom-Json -InputObject $header -ErrorAction Stop).alg
} catch {
throw [System.FormatException]::new("The supplied JWT header segment is not valid JSON. Header length: $($header.Length) characters.")
$message = "The supplied JWT header segment is not valid JSON. Header length: $($header.Length) characters."
throw [System.FormatException]::new($message)
}
if ([string]::IsNullOrEmpty($algorithm)) {
throw [System.FormatException]::new('The JWT header is missing the required "alg" claim.')
Expand All @@ -85,7 +86,8 @@ function Test-Jwt {
switch ($algorithm) {
'RS256' {
if (-not $PSBoundParameters.ContainsKey('Cert')) {
throw [System.ArgumentException]::new('RS256 requires a -Cert parameter of type X509Certificate2.', 'Cert')
$message = 'RS256 requires a -Cert parameter of type X509Certificate2.'
throw [System.ArgumentException]::new($message, 'Cert')
}
if ([string]::IsNullOrEmpty($parts[2])) {
return $false
Expand All @@ -100,7 +102,8 @@ function Test-Jwt {
$computed = [System.Security.Cryptography.SHA256]::HashData($signedContent)
$rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPublicKey($Cert)
if ($null -eq $rsa) {
throw [System.ArgumentException]::new('The supplied certificate has no RSA public key and cannot be used to verify.', 'Cert')
$message = 'The supplied certificate has no RSA public key and cannot be used to verify.'
throw [System.ArgumentException]::new($message, 'Cert')
}
try {
$rsa.VerifyHash(
Expand All @@ -118,11 +121,16 @@ function Test-Jwt {
throw [System.ArgumentException]::new('HS256 requires a -Secret parameter.', 'Secret')
}
if ($Secret -isnot [byte[]] -and $Secret -isnot [string]) {
throw [System.ArgumentException]::new("Expected Secret parameter as byte array or string, instead got $($Secret.GetType())", 'Secret')
$message = "Expected Secret parameter as byte array or string, instead got $($Secret.GetType())"
throw [System.ArgumentException]::new($message, 'Secret')
}
$hmacsha256 = [System.Security.Cryptography.HMACSHA256]::new()
try {
$hmacsha256.Key = if ($Secret -is [byte[]]) { $Secret } else { [System.Text.Encoding]::UTF8.GetBytes($Secret) }
$hmacsha256.Key = if ($Secret -is [byte[]]) {
$Secret
} else {
[System.Text.Encoding]::UTF8.GetBytes($Secret)
}
$signedContent = [System.Text.Encoding]::UTF8.GetBytes($parts[0] + '.' + $parts[1])
$signature = $hmacsha256.ComputeHash($signedContent)
if (-not $parts[2]) {
Expand Down Expand Up @@ -151,7 +159,8 @@ function Test-Jwt {
$parts[2] -eq ''
}
default {
throw [System.NotSupportedException]::new('The algorithm is not one of the supported: "RS256", "HS256", "none".')
$message = 'The algorithm is not one of the supported: "RS256", "HS256", "none".'
throw [System.NotSupportedException]::new($message)
}
}
}
Expand Down
Loading