jose-0.9: test/JWK.hs
-- Copyright (C) 2013, 2017, 2018 Fraser Tweedale
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
{-# LANGUAGE OverloadedStrings #-}
module JWK where
import Data.Monoid ((<>))
import Control.Lens (_Left, _Right, review, view)
import Control.Lens.Extras (is)
import Data.Aeson
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Test.Hspec
import Crypto.JOSE.JWA.JWK
import Crypto.JOSE.JWK
import qualified Crypto.JOSE.Types as Types
spec :: Spec
spec = do
jwk3Spec
jwkAppendixA1Spec
jwkAppendixA2Spec
jwkAppendixA3Spec
jwkAppendixBSpec
jwkAppendixC1Spec
jwsAppendixA1Spec
cfrgSpec
thumbprintSpec
jwsAppendixA1Spec :: Spec
jwsAppendixA1Spec = describe "RFC 7515 A.1.1. JWK" $ do
-- can't make aeson encode JSON to exact representation used in
-- IETF doc, be we can go in reverse and then ensure that the
-- round-trip checks out
--
it "decodes the example to the correct value" $
decode exampleJWK `shouldBe` Just jwk
it "round-trips correctly" $
eitherDecode (encode jwk) `shouldBe` Right jwk
where
exampleJWK = ""
<> "{\"kty\":\"oct\","
<> "\"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75"
<> "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\""
<> "}"
jwk = fromOctets
[3,35,53,75,43,15,165,188,131,126,6,101,119,123,166,143,90,179,40,
230,240,84,201,40,169,15,132,178,210,80,46,191,211,251,90,146,
210,6,71,239,150,138,180,195,119,98,61,34,61,46,33,114,5,46,79,8,
192,205,154,245,103,208,128,163]
jwk3Spec :: Spec
jwk3Spec = describe "RFC 7517 §3. Example JWK" $
it "successfully decodes the examples" $
(eitherDecode exampleJWK :: Either String JWK) `shouldSatisfy` is _Right
where
exampleJWK = ""
<> "{\"kty\":\"EC\","
<> " \"crv\":\"P-256\","
<> " \"x\":\"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\","
<> " \"y\":\"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\","
<> " \"kid\":\"Public key used in JWS spec Appendix A.3 example\""
<> "}"
jwkAppendixA1Spec :: Spec
jwkAppendixA1Spec = describe "RFC 7517 A.1. Example Public Keys" $
it "successfully decodes the examples" $
(eitherDecode exampleJWKSet :: Either String JWKSet) `shouldSatisfy` is _Right
where
exampleEC = ""
<> "{\"kty\":\"EC\","
<> " \"crv\":\"P-256\","
<> " \"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\","
<> " \"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\","
<> " \"use\":\"enc\","
<> " \"kid\":\"1\"}"
exampleRSA = ""
<> "{\"kty\":\"RSA\","
<> " \"n\": \"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx"
<> "4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs"
<> "tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2"
<> "QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI"
<> "SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb"
<> "w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\","
<> " \"e\":\"AQAB\","
<> " \"alg\":\"RS256\","
<> " \"kid\":\"2011-04-29\"}"
exampleJWKSet = "{\"keys\": ["
`L.append` exampleEC `L.append` ","
`L.append` exampleRSA `L.append` "]}"
jwkAppendixA2Spec :: Spec
jwkAppendixA2Spec = describe "RFC 7517 A.2. Example Private Keys" $
it "successfully decodes the examples" $
(eitherDecode exampleJWKSet :: Either String JWKSet) `shouldSatisfy` is _Right
where
exampleJWKSet = ""
<> "{\"keys\":"
<> " ["
<> " {\"kty\":\"EC\","
<> " \"crv\":\"P-256\","
<> " \"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\","
<> " \"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\","
<> " \"d\":\"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE\","
<> " \"use\":\"enc\","
<> " \"kid\":\"1\"},"
<> ""
<> " {\"kty\":\"RSA\","
<> " \"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4"
<> "cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMst"
<> "n64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2Q"
<> "vzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS"
<> "D08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw"
<> "0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\","
<> " \"e\":\"AQAB\","
<> " \"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9"
<> "M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij"
<> "wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d"
<> "_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz"
<> "nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz"
<> "me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\","
<> " \"p\":\"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPV"
<> "nwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqV"
<> "WlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs\","
<> " \"q\":\"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyum"
<> "qjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgx"
<> "kIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk\","
<> " \"dp\":\"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oim"
<> "YwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_Nmtu"
<> "YZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0\","
<> " \"dq\":\"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUU"
<> "vMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9"
<> "GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk\","
<> " \"qi\":\"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzg"
<> "UIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rx"
<> "yR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU\","
<> " \"alg\":\"RS256\","
<> " \"kid\":\"2011-04-29\"}"
<> " ]"
<> "}"
jwkAppendixA3Spec :: Spec
jwkAppendixA3Spec = describe "RFC 7517 A.3. Example Symmetric Keys" $
it "successfully decodes the examples" $
(eitherDecode exampleJWKSet :: Either String JWKSet) `shouldSatisfy` is _Right
where
exampleJWKSet = ""
<> "{\"keys\":"
<> " ["
<> " {\"kty\":\"oct\","
<> " \"alg\":\"A128KW\","
<> " \"k\":\"GawgguFyGrWKav7AX4VKUg\"},"
<> ""
<> " {\"kty\":\"oct\","
<> " \"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75"
<> "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\","
<> " \"kid\":\"HMAC key used in JWS spec Appendix A.1 example\"}"
<> " ]"
<> "}"
jwkAppendixBSpec :: Spec
jwkAppendixBSpec = describe "JWK B. Example Use of \"x5c\" (X.509 Certificate Chain) Parameter" $ do
let
appendixBExampleX5c = ""
<> "[\"MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB"
<> "gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD"
<> "VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1"
<> "wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg"
<> "NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV"
<> "QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w"
<> "YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH"
<> "YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66"
<> "s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6"
<> "SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn"
<> "fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq"
<> "PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk"
<> "aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA"
<> "QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL"
<> "+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1"
<> "zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL"
<> "2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo"
<> "4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq"
<> "gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA==\"]"
exampleKeyCommon = ""
<> "{\"kty\":\"RSA\","
<> " \"use\":\"sig\","
<> " \"kid\":\"1b94c\","
<> " \"n\":\"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08"
<> "PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q"
<> "u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a"
<> "YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH"
<> "MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv"
<> "VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\","
<> " \"e\":\"AQAB\""
Just exampleJWKWithX5c = decode $ exampleKeyCommon <> ",\"x5c\":" <> appendixBExampleX5c <> "}"
Just exampleJWKWithoutX5c = decode $ exampleKeyCommon <> "}"
-- Note: this key is bogus: the "d" param does not correspond to the "n"
-- of the public key. This is not what we're testing, but if a "n"/"d"
-- sanity check gets implemented in future this test will need updating
Just examplePrivateJWKWithoutX5c = decode $ exampleKeyCommon
<> ",\"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9"
<> "M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij"
<> "wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d"
<> "_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz"
<> "nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz"
<> "me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\"}"
Just certs = (fmap . fmap) (\(Types.Base64X509 cert) -> cert) (decode appendixBExampleX5c)
jwkWithMismatchedPubKeyAndX5c = ""
<> "{\"kty\":\"RSA\","
<> " \"n\":\"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08"
<> "HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_"
<> "u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a"
<> "YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH"
<> "MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv"
<> "VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\","
<> " \"e\":\"AQAB\",\"x5c\":" <> appendixBExampleX5c <> "}"
it "sets x5c in JWK with PUBLIC key when first cert matches key" $
setJWKX5c (Just certs) exampleJWKWithoutX5c `shouldBe` Just exampleJWKWithX5c
it "sets x5c in JWK with PRIVATE key when first cert matches key" $
(setJWKX5c (Just certs) examplePrivateJWKWithoutX5c >>= view asPublicKey)
`shouldBe` Just exampleJWKWithX5c
it "unsets x5c in JWK when given x5c = Nothing" $
setJWKX5c Nothing exampleJWKWithX5c `shouldBe` Just exampleJWKWithoutX5c
it "rejects (parse error) keys with x5c that does not match public key" $
(eitherDecode jwkWithMismatchedPubKeyAndX5c :: Either String JWK) `shouldSatisfy` is _Left
jwkAppendixC1Spec :: Spec
jwkAppendixC1Spec = describe "RFC 7517 C.1. Plaintext RSA Private Key" $
it "successfully decodes the example" $
(eitherDecode exampleJWK :: Either String JWK) `shouldSatisfy` is _Right
where
exampleJWK = ""
<> "{"
<> " \"kty\":\"RSA\","
<> " \"kid\":\"juliet@capulet.lit\","
<> " \"use\":\"enc\","
<> " \"n\":\"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy"
<> "O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP"
<> "8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0"
<> "Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X"
<> "OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1"
<> "_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q\","
<> " \"e\":\"AQAB\","
<> " \"d\":\"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS"
<> "NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U"
<> "vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu"
<> "ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu"
<> "rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a"
<> "hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ\","
<> " \"p\":\"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf"
<> "QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8"
<> "UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws\","
<> " \"q\":\"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I"
<> "edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK"
<> "rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s\","
<> " \"dp\":\"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3"
<> "tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w"
<> "Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c\","
<> " \"dq\":\"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9"
<> "GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy"
<> "mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots\","
<> " \"qi\":\"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq"
<> "abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o"
<> "Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8\""
<> "}"
cfrgSpec :: Spec
cfrgSpec = describe "RFC 8037 test vectors" $ do
let
_A2_jwkJson = ""
<> "{\"kty\":\"OKP\",\"crv\":\"Ed25519\","
<> "\"x\":\"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo\"}"
_A1_result = eitherDecode rfc8037_A1_jwkJson :: Either String JWK
_A2_result = eitherDecode _A2_jwkJson
describe "A.1. Ed25519 Private Key" $
it "successfully decodes the example" $ _A1_result `shouldSatisfy` is _Right
describe "A.2. Ed25519 Public Key" $ do
it "successfully decodes the example" $ _A2_result `shouldSatisfy` is _Right
it "corresponds to A.1. private key" $ Right True == do
sk <- _A1_result
pk <- _A2_result
pure $ view asPublicKey sk == Just pk
rfc8037_A1_jwkJson :: L.ByteString
rfc8037_A1_jwkJson =
"{\"kty\":\"OKP\",\"crv\":\"Ed25519\","
<> "\"d\":\"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A\","
<> "\"x\":\"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo\"}"
thumbprintSpec :: Spec
thumbprintSpec = describe "JWK Thumbprint" $ do
describe "RFC 7638 §3.1. Example JWK Thumbprint Computation" $ do
let
Just k = decode $ ""
<> "{"
<> " \"kty\": \"RSA\","
<> " \"n\": \"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt"
<> "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6"
<> "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD"
<> "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9"
<> "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH"
<> "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\","
<> " \"e\": \"AQAB\","
<> " \"alg\": \"RS256\","
<> " \"kid\": \"2011-04-29\""
<> "}"
it "correctly computes thumbprint of RSA key" $
review (base64url . digest) (view thumbprint k :: Digest SHA256)
`shouldBe` ("NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" :: B.ByteString)
describe "RFC 8037 A.3. JWK Thumbprint Canonicalization" $ do
let Just k = decode rfc8037_A1_jwkJson
it "correctly computes thumbprint of Ed25519 key" $
review (base64url . digest) (view thumbprint k :: Digest SHA256)
`shouldBe` ("kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k" :: B.ByteString)