summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-07-04 16:14:13 -0400
committerJoe Crayne <joe@jerkface.net>2019-07-04 16:14:13 -0400
commitbc518fbdc3bce78f61bfa76bac95ae435a7216a8 (patch)
tree24e0790498bdce7ae5bbfa905a1529b24ff46aed
parenteba3661ee3007c5e9e5444020b38333ef60fb88b (diff)
Minimal support for cv25519 parsing.
-rw-r--r--Data/OpenPGP.hs80
1 files changed, 71 insertions, 9 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs
index 8fef50a..2fab94a 100644
--- a/Data/OpenPGP.hs
+++ b/Data/OpenPGP.hs
@@ -62,7 +62,8 @@ module Data.OpenPGP (
62 signatures, 62 signatures,
63 signature_issuer, 63 signature_issuer,
64 public_key_fields, 64 public_key_fields,
65 secret_key_fields 65 secret_key_fields,
66 eccOID
66) where 67) where
67 68
68import Numeric 69import Numeric
@@ -288,7 +289,7 @@ instance BINARY_CLASS Packet where
288 get = do 289 get = do
289 tag <- get 290 tag <- get
290 let (t, l) = 291 let (t, l) =
291 if testBit tag 6 then 292 if testBit (tag :: Word8) 6 then
292 (tag .&. 63, parse_new_length) 293 (tag .&. 63, parse_new_length)
293 else 294 else
294 ((tag `shiftR` 2) .&. 15, (,) <$> parse_old_length tag <*> pure False) 295 ((tag `shiftR` 2) .&. 15, (,) <$> parse_old_length tag <*> pure False)
@@ -342,8 +343,10 @@ public_key_fields RSA_E = public_key_fields RSA
342public_key_fields RSA_S = public_key_fields RSA 343public_key_fields RSA_S = public_key_fields RSA
343public_key_fields ELGAMAL = ['p', 'g', 'y'] 344public_key_fields ELGAMAL = ['p', 'g', 'y']
344public_key_fields DSA = ['p', 'q', 'g', 'y'] 345public_key_fields DSA = ['p', 'q', 'g', 'y']
345public_key_fields ECDSA = ['c','l','x', 'y'] 346public_key_fields ECDSA = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling.
346public_key_fields _ = undefined -- Nothing in the spec. Maybe empty 347public_key_fields Ed25519 = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling.
348public_key_fields ECC = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling.
349public_key_fields alg = error ("Unknown key fields for "++show alg) -- Nothing in the spec. Maybe empty
347 350
348-- http://tools.ietf.org/html/rfc4880#section-5.5.3 351-- http://tools.ietf.org/html/rfc4880#section-5.5.3
349secret_key_fields :: KeyAlgorithm -> [Char] 352secret_key_fields :: KeyAlgorithm -> [Char]
@@ -353,7 +356,7 @@ secret_key_fields RSA_S = secret_key_fields RSA
353secret_key_fields ELGAMAL = ['x'] 356secret_key_fields ELGAMAL = ['x']
354secret_key_fields DSA = ['x'] 357secret_key_fields DSA = ['x']
355secret_key_fields ECDSA = ['d'] 358secret_key_fields ECDSA = ['d']
356secret_key_fields _ = undefined -- Nothing in the spec. Maybe empty 359secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty
357 360
358(!) :: (Eq k) => [(k,v)] -> k -> v 361(!) :: (Eq k) => [(k,v)] -> k -> v
359(!) xs k = let Just x = lookup k xs in x 362(!) xs k = let Just x = lookup k xs in x
@@ -405,6 +408,16 @@ calculate_signature_trailer x =
405 error ("Trying to calculate signature trailer for: " ++ show x) 408 error ("Trying to calculate signature trailer for: " ++ show x)
406 409
407 410
411-- 0x2b06010401da470f01
412-- common/openpgp-oid.c 50 { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
413--
414-- 0x2b060104019755010501
415-- common/openpgp-oid.c 49 { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
416eccOID :: Packet -> Maybe BS.ByteString
417eccOID PublicKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $ putBigNum oid)
418eccOID SecretKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $ putBigNum oid)
419eccOID _ = Nothing
420
408encode_public_key_material :: Packet -> [B.ByteString] 421encode_public_key_material :: Packet -> [B.ByteString]
409encode_public_key_material k | key_algorithm k == ECDSA = do 422encode_public_key_material k | key_algorithm k == ECDSA = do
410 -- http://tools.ietf.org/html/rfc6637 423 -- http://tools.ietf.org/html/rfc6637
@@ -421,13 +434,30 @@ encode_public_key_material k | key_algorithm k == ECDSA = do
421encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) 434encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k)
422 435
423decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] 436decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)]
424decode_public_key_material ECDSA = do 437decode_public_key_material algorithm | algorithm `elem` [ECDSA, Ed25519] = do
425 -- http://tools.ietf.org/html/rfc6637 438 -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDSA keys
439 oidlen <- get :: Get Word8
440 oidbytes <- getSomeByteString (fromIntegral oidlen)
441 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes)
442 oid = mpiFromBytes oidbytes
443 MPI xy <- get
444 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2
445 width = ( integerBytesize xy - 1 ) `div` 2
446 (fx,y) = xy `quotRem` (256^width)
447 x = fx `rem` (256^width)
448 l = width*8
449 return [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y)]
450decode_public_key_material ECC = do
451 -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDH keys:
426 oidlen <- get :: Get Word8 452 oidlen <- get :: Get Word8
427 oidbytes <- getSomeByteString (fromIntegral oidlen) 453 oidbytes <- getSomeByteString (fromIntegral oidlen)
428 let mpiFromBytes bytes = MPI (B.foldl (\a b -> a `shiftL` 8 .|. fromIntegral b) 0 bytes) 454 let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes)
429 oid = mpiFromBytes oidbytes 455 oid = mpiFromBytes oidbytes
430 MPI xy <- get 456 MPI xy <- get
457 flen <- get :: Get Word8
458 one <- get :: Get Word8
459 hashid <- get :: Get Word8
460 algoid <- get :: Get Word8
431 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 461 let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2
432 width = ( integerBytesize xy - 1 ) `div` 2 462 width = ( integerBytesize xy - 1 ) `div` 2
433 (fx,y) = xy `quotRem` (256^width) 463 (fx,y) = xy `quotRem` (256^width)
@@ -556,6 +586,36 @@ put_packet (ModificationDetectionCodePacket bstr) = (bstr, 19)
556put_packet (UnsupportedPacket tag bytes) = (bytes, fromIntegral tag) 586put_packet (UnsupportedPacket tag bytes) = (bytes, fromIntegral tag)
557put_packet x = error ("Unsupported Packet version or type in put_packet: " ++ show x) 587put_packet x = error ("Unsupported Packet version or type in put_packet: " ++ show x)
558 588
589-- For reference, GnuPG (as of commit 3a403ab04) uses this:
590-- typedef enum
591-- {
592-- PKT_NONE = 0,
593-- PKT_PUBKEY_ENC = 1, /* Public key encrypted packet. */
594-- PKT_SIGNATURE = 2, /* Secret key encrypted packet. */
595-- PKT_SYMKEY_ENC = 3, /* Session key packet. */
596-- PKT_ONEPASS_SIG = 4, /* One pass sig packet. */
597-- PKT_SECRET_KEY = 5, /* Secret key. */
598-- PKT_PUBLIC_KEY = 6, /* Public key. */
599-- PKT_SECRET_SUBKEY = 7, /* Secret subkey. */
600-- PKT_COMPRESSED = 8, /* Compressed data packet. */
601-- PKT_ENCRYPTED = 9, /* Conventional encrypted data. */
602-- PKT_MARKER = 10, /* Marker packet. */
603-- PKT_PLAINTEXT = 11, /* Literal data packet. */
604-- PKT_RING_TRUST = 12, /* Keyring trust packet. */
605-- PKT_USER_ID = 13, /* User id packet. */
606-- PKT_PUBLIC_SUBKEY = 14, /* Public subkey. */
607-- PKT_OLD_COMMENT = 16, /* Comment packet from an OpenPGP draft. */
608-- PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */
609-- PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
610-- PKT_MDC = 19, /* Manipulation detection code packet. */
611-- PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */
612-- PKT_COMMENT = 61, /* new comment packet (GnuPG specific). */
613-- PKT_GPG_CONTROL = 63 /* internal control packet (GnuPG specific). */
614-- }
615-- pkttype_t;
616--
617-- PKT_OLD_COMMENT, PKT_ATTRIBUTE, PKT_ENCRYPTED_AEAD, are not implemented here.
618-- Also ommitted are GnuPG-specific packets: PKT_COMMENT and PKT_GPG_CONTROL.
559parse_packet :: Word8 -> Get Packet 619parse_packet :: Word8 -> Get Packet
560-- AsymmetricSessionKeyPacket, http://tools.ietf.org/html/rfc4880#section-5.1 620-- AsymmetricSessionKeyPacket, http://tools.ietf.org/html/rfc4880#section-5.1
561parse_packet 1 = AsymmetricSessionKeyPacket 621parse_packet 1 = AsymmetricSessionKeyPacket
@@ -832,7 +892,7 @@ instance BINARY_CLASS HashAlgorithm where
832 put = put . enum_to_word8 892 put = put . enum_to_word8
833 get = fmap enum_from_word8 get 893 get = fmap enum_from_word8 get
834 894
835data KeyAlgorithm = RSA | RSA_E | RSA_S | ELGAMAL | DSA | ECC | ECDSA | DH | KeyAlgorithm Word8 895data KeyAlgorithm = RSA | RSA_E | RSA_S | ELGAMAL | DSA | ECC | ECDSA | DH | Ed25519 | KeyAlgorithm Word8
836 deriving (Show, Read, Eq) 896 deriving (Show, Read, Eq)
837 897
838instance Enum KeyAlgorithm where 898instance Enum KeyAlgorithm where
@@ -844,6 +904,7 @@ instance Enum KeyAlgorithm where
844 toEnum 18 = ECC 904 toEnum 18 = ECC
845 toEnum 19 = ECDSA 905 toEnum 19 = ECDSA
846 toEnum 21 = DH 906 toEnum 21 = DH
907 toEnum 22 = Ed25519
847 toEnum x = KeyAlgorithm $ fromIntegral x 908 toEnum x = KeyAlgorithm $ fromIntegral x
848 fromEnum RSA = 01 909 fromEnum RSA = 01
849 fromEnum RSA_E = 02 910 fromEnum RSA_E = 02
@@ -853,6 +914,7 @@ instance Enum KeyAlgorithm where
853 fromEnum ECC = 18 914 fromEnum ECC = 18
854 fromEnum ECDSA = 19 915 fromEnum ECDSA = 19
855 fromEnum DH = 21 916 fromEnum DH = 21
917 fromEnum Ed25519 = 22
856 fromEnum (KeyAlgorithm x) = fromIntegral x 918 fromEnum (KeyAlgorithm x) = fromIntegral x
857 919
858instance BINARY_CLASS KeyAlgorithm where 920instance BINARY_CLASS KeyAlgorithm where