summaryrefslogtreecommitdiff
path: root/Data/OpenPGP.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Data/OpenPGP.hs')
-rw-r--r--Data/OpenPGP.hs75
1 files changed, 51 insertions, 24 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs
index 35298c8..4627d4e 100644
--- a/Data/OpenPGP.hs
+++ b/Data/OpenPGP.hs
@@ -64,7 +64,9 @@ module Data.OpenPGP (
64 signature_issuer, 64 signature_issuer,
65 public_key_fields, 65 public_key_fields,
66 secret_key_fields, 66 secret_key_fields,
67 eccOID 67 eccOID,
68 encode_public_key_material,
69 decode_public_key_material
68) where 70) where
69 71
70import Control.Applicative 72import Control.Applicative
@@ -80,6 +82,7 @@ import Data.Maybe
80import Data.Monoid 82import Data.Monoid
81import Data.OpenPGP.Internal 83import Data.OpenPGP.Internal
82import Data.Word 84import Data.Word
85import GHC.Stack
83import Numeric 86import Numeric
84 87
85#ifdef CEREAL 88#ifdef CEREAL
@@ -345,8 +348,8 @@ public_key_fields RSA_S = public_key_fields RSA
345public_key_fields ELGAMAL = ['p', 'g', 'y'] 348public_key_fields ELGAMAL = ['p', 'g', 'y']
346public_key_fields DSA = ['p', 'q', 'g', 'y'] 349public_key_fields DSA = ['p', 'q', 'g', 'y']
347public_key_fields ECDSA = ['c','l','x', 'y', 'f'] 350public_key_fields ECDSA = ['c','l','x', 'y', 'f']
348public_key_fields Ed25519 = ['c','l','x', 'y', 'f'] 351public_key_fields Ed25519 = ['c','l','x', 'y', 'n', 'f']
349public_key_fields ECC = ['c','l','x', 'y', 'f'] 352public_key_fields ECC = ['c','l','x', 'y', 'n', 'f', 'e']
350public_key_fields alg = error ("Unknown key fields for "++show alg) -- Nothing in the spec. Maybe empty 353public_key_fields alg = error ("Unknown key fields for "++show alg) -- Nothing in the spec. Maybe empty
351 354
352-- http://tools.ietf.org/html/rfc4880#section-5.5.3 355-- http://tools.ietf.org/html/rfc4880#section-5.5.3
@@ -359,8 +362,10 @@ secret_key_fields DSA = ['x']
359secret_key_fields ECDSA = ['d'] 362secret_key_fields ECDSA = ['d']
360secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty 363secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty
361 364
362(!) :: (Eq k) => [(k,v)] -> k -> v 365(!) :: (HasCallStack, Show k, Eq k) => [(k,v)] -> k -> v
363(!) xs k = let Just x = lookup k xs in x 366(!) xs k = case lookup k xs of
367 Just v -> v
368 Nothing -> error ("Missing field "++show k++" at "++prettyCallStack callStack)
364 369
365-- Need this seperate for trailer calculation 370-- Need this seperate for trailer calculation
366signature_packet_start :: Packet -> B.ByteString 371signature_packet_start :: Packet -> B.ByteString
@@ -420,19 +425,28 @@ eccOID SecretKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $
420eccOID _ = Nothing 425eccOID _ = Nothing
421 426
422encode_public_key_material :: Packet -> [B.ByteString] 427encode_public_key_material :: Packet -> [B.ByteString]
423encode_public_key_material k | key_algorithm k `elem` [ECDSA,Ed25519] = do 428encode_public_key_material k | key_algorithm k `elem` [ECDSA,Ed25519,ECC] = do
424 -- http://tools.ietf.org/html/rfc6637 429 -- http://tools.ietf.org/html/rfc6637
425 c <- maybeToList $ lookup 'c' (key k) 430 c <- maybeToList $ lookup 'c' (key k)
426 MPI l <- maybeToList $ lookup 'l' (key k) 431 MPI l <- maybeToList $ lookup 'l' (key k)
427 MPI x <- maybeToList $ lookup 'x' (key k)
428 MPI y <- maybeToList $ lookup 'y' (key k)
429 MPI flag <- maybeToList $ lookup 'f' (key k) 432 MPI flag <- maybeToList $ lookup 'f' (key k)
430 let (bitlen,oid) = B.splitAt 2 (encode c) 433 let (bitlen,oid) = B.splitAt 2 (encode c)
431 len16 = decode bitlen :: Word16 434 len16 = decode bitlen :: Word16
432 (fullbytes,rembits) = len16 `quotRem` 8 435 (fullbytes,rembits) = len16 `quotRem` 8
433 len8 = fromIntegral (fullbytes + if rembits/=0 then 1 else 0) :: Word8 436 len8 = fromIntegral (fullbytes + if rembits/=0 then 1 else 0) :: Word8
434 xy = flag*(4^l) + x*(2^l) + y -- flag could be 0x04 or 0x40 437 eccstuff = case lookup 'e' (key k) of
435 [ len8 `B.cons` oid, encode (MPI xy) ] 438 Just stuff -> encode stuff
439 Nothing -> B.empty
440 case flag of
441 0x40 -> do
442 MPI n <- maybeToList $ lookup 'n' (key k)
443 let xy = flag*(4^l) + n
444 [ len8 `B.cons` oid, encode (MPI xy), eccstuff ]
445 _ -> do
446 MPI x <- maybeToList $ lookup 'x' (key k)
447 MPI y <- maybeToList $ lookup 'y' (key k)
448 let xy = flag*(4^l) + x*(2^l) + y
449 [ len8 `B.cons` oid, encode (MPI xy), eccstuff ]
436encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) 450encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k)
437 451
438decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] 452decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)]
@@ -442,30 +456,42 @@ decode_public_key_material algorithm | algorithm `elem` [ECDSA, Ed25519] = do
442 oidbytes <- getSomeByteString (fromIntegral oidlen) 456 oidbytes <- getSomeByteString (fromIntegral oidlen)
443 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) 457 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes)
444 oid = mpiFromBytes oidbytes 458 oid = mpiFromBytes oidbytes
445 MPI xy <- get 459 MPI fxy <- get
446 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 460 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2
447 width = ( integerBytesize xy - 1 ) `div` 2 461 width = ( integerBytesize fxy - 1 ) `div` 2
448 (fx,y) = xy `quotRem` (256^width)
449 (flag,x) = fx `quotRem` (256^width)
450 l = width*8 462 l = width*8
451 return [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] 463 (flag,xy) = fxy `quotRem` (256^(2*width))
464 return $ case flag of
465 0x40 -> [('c',oid), ('l',MPI l), ('n',MPI xy), ('f',MPI flag)]
466 _ -> let (x,y) = xy `quotRem` (256^width)
467 -- (fx,y) = xy `quotRem` (256^width)
468 -- (flag,x) = fx `quotRem` (256^width)
469 in [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)]
452decode_public_key_material ECC = do 470decode_public_key_material ECC = do
453 -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDH keys: 471 -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDH keys:
454 oidlen <- get :: Get Word8 472 oidlen <- get :: Get Word8
455 oidbytes <- getSomeByteString (fromIntegral oidlen) 473 oidbytes <- getSomeByteString (fromIntegral oidlen)
456 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) 474 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes)
457 oid = mpiFromBytes oidbytes 475 oid = mpiFromBytes oidbytes
458 MPI xy <- get 476 MPI fxy <- get
459 flen <- get :: Get Word8 477 eccstuff <- get :: Get Word32
460 one <- get :: Get Word8 478 {- eccstuff is 4 one-byte fields:
461 hashid <- get :: Get Word8 479 flen <- get :: Get Word8
462 algoid <- get :: Get Word8 480 one <- get :: Get Word8 -- always 0x01
481 hashid <- get :: Get Word8
482 algoid <- get :: Get Word8
483 -}
463 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 484 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2
464 width = ( integerBytesize xy - 1 ) `div` 2 485 width = ( integerBytesize fxy - 1 ) `div` 2
465 (fx,y) = xy `quotRem` (256^width)
466 (flag,x) = fx `quotRem` (256^width)
467 l = width*8 486 l = width*8
468 return [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] 487 (flag,xy) = fxy `quotRem` (256^(2*width))
488 result = case flag of
489 0x40 -> [('c',oid), ('l',MPI l), ('n',MPI xy), ('f',MPI flag)]
490 _ -> let (x,y) = xy `quotRem` (256^width)
491 -- (fx,y) = xy `quotRem` (256^width)
492 -- (flag,x) = fx `quotRem` (256^width)
493 in [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)]
494 return $ result ++ [('e',MPI (fromIntegral eccstuff))]
469decode_public_key_material algorithm = mapM (\f -> fmap ((,)f) get) (public_key_fields algorithm) 495decode_public_key_material algorithm = mapM (\f -> fmap ((,)f) get) (public_key_fields algorithm)
470 496
471put_packet :: Packet -> (B.ByteString, Word8) 497put_packet :: Packet -> (B.ByteString, Word8)
@@ -1130,6 +1156,7 @@ data SignatureSubpacket =
1130 hash :: B.ByteString 1156 hash :: B.ByteString
1131 } | 1157 } |
1132 EmbeddedSignaturePacket Packet | 1158 EmbeddedSignaturePacket Packet |
1159 -- TODO: IssuerFingerprintPacket (tag=33)
1133 UnsupportedSignatureSubpacket Word8 B.ByteString 1160 UnsupportedSignatureSubpacket Word8 B.ByteString
1134 deriving (Show, Read, Eq) 1161 deriving (Show, Read, Eq)
1135 1162