diff options
author | Joe Crayne <joe@jerkface.net> | 2019-07-04 16:14:13 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-07-04 16:14:13 -0400 |
commit | bc518fbdc3bce78f61bfa76bac95ae435a7216a8 (patch) | |
tree | 24e0790498bdce7ae5bbfa905a1529b24ff46aed | |
parent | eba3661ee3007c5e9e5444020b38333ef60fb88b (diff) |
Minimal support for cv25519 parsing.
-rw-r--r-- | Data/OpenPGP.hs | 80 |
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 | ||
68 | import Numeric | 69 | import 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 | |||
342 | public_key_fields RSA_S = public_key_fields RSA | 343 | public_key_fields RSA_S = public_key_fields RSA |
343 | public_key_fields ELGAMAL = ['p', 'g', 'y'] | 344 | public_key_fields ELGAMAL = ['p', 'g', 'y'] |
344 | public_key_fields DSA = ['p', 'q', 'g', 'y'] | 345 | public_key_fields DSA = ['p', 'q', 'g', 'y'] |
345 | public_key_fields ECDSA = ['c','l','x', 'y'] | 346 | public_key_fields ECDSA = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling. |
346 | public_key_fields _ = undefined -- Nothing in the spec. Maybe empty | 347 | public_key_fields Ed25519 = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling. |
348 | public_key_fields ECC = ['c','l','x', 'y'] -- TODO: These probably need special fingerprint handling. | ||
349 | public_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 |
349 | secret_key_fields :: KeyAlgorithm -> [Char] | 352 | secret_key_fields :: KeyAlgorithm -> [Char] |
@@ -353,7 +356,7 @@ secret_key_fields RSA_S = secret_key_fields RSA | |||
353 | secret_key_fields ELGAMAL = ['x'] | 356 | secret_key_fields ELGAMAL = ['x'] |
354 | secret_key_fields DSA = ['x'] | 357 | secret_key_fields DSA = ['x'] |
355 | secret_key_fields ECDSA = ['d'] | 358 | secret_key_fields ECDSA = ['d'] |
356 | secret_key_fields _ = undefined -- Nothing in the spec. Maybe empty | 359 | secret_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 }, | ||
416 | eccOID :: Packet -> Maybe BS.ByteString | ||
417 | eccOID PublicKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $ putBigNum oid) | ||
418 | eccOID SecretKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $ putBigNum oid) | ||
419 | eccOID _ = Nothing | ||
420 | |||
408 | encode_public_key_material :: Packet -> [B.ByteString] | 421 | encode_public_key_material :: Packet -> [B.ByteString] |
409 | encode_public_key_material k | key_algorithm k == ECDSA = do | 422 | encode_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 | |||
421 | encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) | 434 | encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) |
422 | 435 | ||
423 | decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] | 436 | decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] |
424 | decode_public_key_material ECDSA = do | 437 | decode_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)] | ||
450 | decode_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) | |||
556 | put_packet (UnsupportedPacket tag bytes) = (bytes, fromIntegral tag) | 586 | put_packet (UnsupportedPacket tag bytes) = (bytes, fromIntegral tag) |
557 | put_packet x = error ("Unsupported Packet version or type in put_packet: " ++ show x) | 587 | put_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. | ||
559 | parse_packet :: Word8 -> Get Packet | 619 | parse_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 |
561 | parse_packet 1 = AsymmetricSessionKeyPacket | 621 | parse_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 | ||
835 | data KeyAlgorithm = RSA | RSA_E | RSA_S | ELGAMAL | DSA | ECC | ECDSA | DH | KeyAlgorithm Word8 | 895 | data 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 | ||
838 | instance Enum KeyAlgorithm where | 898 | instance 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 | ||
858 | instance BINARY_CLASS KeyAlgorithm where | 920 | instance BINARY_CLASS KeyAlgorithm where |