packages feed

jose-jwt 0.9.0 → 0.9.1

raw patch · 4 files changed

+41/−21 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,3 +1,8 @@+0.9.1+-----++* Fix for tests broken due to [different aeson key ordering](https://github.com/commercialhaskell/stackage/issues/5878).+ 0.9.0 ----- @@ -6,8 +11,7 @@ 0.8.0 ----- -* The result of the `Jose.Jwt.decodeClaims` function is now polymorphic so it can be used with-any `FromJSON` type.+* The result of the `Jose.Jwt.decodeClaims` function is now polymorphic so it can be used with any `FromJSON` type. * Only ghc 8 upwards are now supported. * the RSA-OAEP-256 algorithm is now supported. 
Jose/Jwe.hs view
@@ -12,20 +12,20 @@ -- of the token need to have a copy of the key, which they must keep secret. With -- RSA anyone can send you a JWE if they have a copy of your public key. ----- In the example below, we show encoding and decoding using a 512 byte RSA key pair--- (in practice you would use a larger key-size, for example 2048 bytes):+-- In the example below, we show encoding and decoding using a 2048 bit RSA key pair+-- (256 bytes). -- -- >>> import Jose.Jwe -- >>> import Jose.Jwa -- >>> import Jose.Jwk (generateRsaKeyPair, generateSymmetricKey, KeyUse(Enc), KeyId)--- >>> (kPub, kPr) <- generateRsaKeyPair 512 (KeyId "My RSA Key") Enc Nothing+-- >>> (kPub, kPr) <- generateRsaKeyPair 256 (KeyId "My RSA Key") Enc Nothing -- >>> Right (Jwt jwt) <- jwkEncode RSA_OAEP A128GCM kPub (Claims "secret claims") -- >>> Right (Jwe (hdr, claims)) <- jwkDecode kPr jwt -- >>> claims -- "secret claims" -- -- Using 128-bit AES keywrap is very similar, the main difference is that--- we generate a 128-bit symmetric key:+-- we generate a 128-bit symmetric key (16 bytes): -- -- >>> aesKey <- generateSymmetricKey 16 (KeyId "My Keywrap Key") Enc Nothing -- >>> Right (Jwt jwt) <- jwkEncode A128KW A128GCM aesKey (Claims "more secret claims")@@ -46,10 +46,13 @@ import Crypto.Cipher.Types (AuthTag(..)) import Crypto.PubKey.RSA (PrivateKey(..), PublicKey(..), generateBlinder, private_pub) import Crypto.Random (MonadRandom)+import qualified Data.Aeson as A import Data.ByteArray (ByteArray, ScrubbedBytes) import qualified Data.ByteArray as BA import Data.ByteString (ByteString) import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import Data.Maybe (isNothing) import Jose.Types import qualified Jose.Internal.Base64 as B64 import Jose.Internal.Crypto@@ -67,13 +70,24 @@     -> Payload                         -- ^ The token content (claims or nested JWT)     -> m (Either JwtError Jwt)         -- ^ The encoded JWE if successful jwkEncode a e jwk payload = runExceptT $ case jwk of-    RsaPublicJwk kPub kid _ _ -> doEncode (hdr kid) (doRsa kPub) bytes-    RsaPrivateJwk kPr kid _ _ -> doEncode (hdr kid) (doRsa (private_pub kPr)) bytes-    SymmetricJwk  kek kid _ _ -> doEncode (hdr kid) (ExceptT .  return . keyWrap a (BA.convert kek)) bytes+    RsaPublicJwk kPub kid _ _ -> doEncode (hdr kid) e (doRsa kPub) bytes+    RsaPrivateJwk kPr kid _ _ -> doEncode (hdr kid) e (doRsa (private_pub kPr)) bytes+    SymmetricJwk  kek kid _ _ -> doEncode (hdr kid) e (ExceptT .  return . keyWrap a (BA.convert kek)) bytes     _                         -> throwE $ KeyError "JWK cannot encode a JWE"   where     doRsa kPub = ExceptT . rsaEncrypt kPub a-    hdr kid = defJweHdr {jweAlg = a, jweEnc = e, jweKid = kid, jweCty = contentType}+    hdr :: Maybe KeyId -> B.ByteString+    hdr kid = BL.toStrict $+        BL.concat+            [ "{\"alg\":"+            , A.encode a+            , ",\"enc\":"+            , A.encode e+            , maybe "" (\c -> BL.concat [",\"cty\":\"", c, "\"" ]) contentType+            , if isNothing kid then "" else BL.concat [",\"kid\":", A.encode kid ]+            , "}"+            ]+     (contentType, bytes) = case payload of         Claims c       -> (Nothing, c)         Nested (Jwt b) -> (Just "JWT", b)@@ -117,19 +131,18 @@   doEncode :: (MonadRandom m, ByteArray ba)-    => JweHeader+    => ByteString+    -> Enc     -> (ScrubbedBytes -> ExceptT JwtError m ByteString)     -> ba     -> ExceptT JwtError m Jwt-doEncode h encryptKey claims = do+doEncode hdr e encryptKey claims = do     (cmk, iv) <- lift (generateCmkAndIV e)     let Just (AuthTag sig, ct) = encryptPayload e cmk iv aad claims     jweKey <- encryptKey cmk     let jwe = B.intercalate "." $ map B64.encode [hdr, jweKey, BA.convert iv, BA.convert ct, BA.convert sig]     return (Jwt jwe)   where-    e   = jweEnc h-    hdr = encodeHeader h     aad = B64.encode hdr  -- | Creates a JWE with the content key encoded using RSA.@@ -139,7 +152,9 @@     -> PublicKey       -- ^ RSA key to encrypt with     -> ByteString      -- ^ The JWT claims (content)     -> m (Either JwtError Jwt) -- ^ The encoded JWE-rsaEncode a e kPub claims = runExceptT $ doEncode (defJweHdr {jweAlg = a, jweEnc = e}) (ExceptT . rsaEncrypt kPub a) claims+rsaEncode a e kPub claims = runExceptT $ doEncode hdr e (ExceptT . rsaEncrypt kPub a) claims+  where+    hdr = BL.toStrict $ BL.concat ["{\"alg\":", A.encode a, ",", "\"enc\":", A.encode e, "}"]   -- | Decrypts a JWE.
jose-jwt.cabal view
@@ -1,5 +1,5 @@ Name:               jose-jwt-Version:            0.9.0+Version:            0.9.1 Synopsis:           JSON Object Signing and Encryption Library Homepage:           http://github.com/tekul/jose-jwt Bug-Reports:        http://github.com/tekul/jose-jwt/issues
tests/Tests/JweSpec.hs view
@@ -5,11 +5,12 @@ module Tests.JweSpec where  import Control.Applicative-import Data.Aeson (decodeStrict')+import Data.Aeson (decodeStrict', ToJSON) import Data.Bits (xor) import Data.Word (Word8, Word64) import qualified Data.ByteArray as BA import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as BC import Test.Hspec import Test.HUnit hiding (Test)@@ -48,7 +49,7 @@             (rsaEncrypt a1PubKey RSA_OAEP a1cek) @?= (Right a1jweKey, RNG "")        it "encrypts the payload to the expected ciphertext and authentication tag" $ do-        let aad = B64.encode . encodeHeader $ a1Header+        let aad = B64.encode ("{\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\"}" :: B.ByteString)         encryptPayload A256GCM a1cek a1iv aad a1Payload @?= Just (AuthTag a1Tag, a1Ciphertext)        it "encodes the payload to the expected JWT, leaving the RNG empty" $@@ -94,7 +95,7 @@      context "when using JWE Appendix 2 data" $ do       let a2Header = defJweHdr {jweAlg = RSA1_5, jweEnc = A128CBC_HS256}-      let aad = B64.encode . encodeHeader $ a2Header+      let aad = B64.encode ("{\"alg\":\"RSA1_5\",\"enc\":\"A128CBC-HS256\"}" :: B.ByteString)        it "generates the expected RSA-encrypted content key" $         withDRG (RNG a2seed) (rsaEncrypt a2PubKey RSA1_5 a2cek) @?= (Right a2jweKey, RNG "")@@ -130,7 +131,7 @@     context "when using JWE Appendix 3 data" $ do       let Just jwk = decodeStrict' a3jwk           a3Header = defJweHdr {jweAlg = A128KW, jweEnc = A128CBC_HS256}-      it "encodes the payload to the epected JWT" $+      it "encodes the payload to the expected JWT" $         withDRG (RNG $ B.concat [a3cek, a3iv])             (Jwe.jwkEncode A128KW A128CBC_HS256 jwk (Claims a3Payload)) @?= (Right (Jwt a3), RNG "") @@ -159,7 +160,7 @@  -- verboseQuickCheckWith quickCheckWith stdArgs {maxSuccess=10000}  jweRoundTrip jweRoundTrip :: RNG -> JWEAlgs -> [Word8] -> Bool-jweRoundTrip g (JWEAlgs a e) msg = encodeDecode == Right (Jwe (defJweHdr {jweAlg = a, jweEnc = e}, bs))+jweRoundTrip g (JWEAlgs a e) msg = encodeDecode == Right (Jwe (defJweHdr {jweAlg = a, jweEnc = e }, bs))   where     jwks = [a1jwk, a2jwk, a3jwk, aes192jwk, aes256jwk] >>= \j -> let Just jwk = decodeStrict' j in [jwk]     bs = B.pack msg