diff options
author | Stephen Paul Weber <singpolyma@singpolyma.net> | 2012-04-25 11:11:09 -0500 |
---|---|---|
committer | Stephen Paul Weber <singpolyma@singpolyma.net> | 2012-04-25 11:11:09 -0500 |
commit | da82b6a356e6a1571047fdea15d26ec10c869fa4 (patch) | |
tree | 84876a89db1a41a81b36ab17b85b9e1dfeda15af /Data/OpenPGP.hs | |
parent | 7de451e7d9761126da49cc71ef1fe6eed728ccb4 (diff) |
Make SignaturePacket opaque, emit trailer
Instead of the Put instance emitting the actual packet header, it emits
the start of the trailer data (which is the same bytes as the packet
header).
SignaturePacket is opaque and there is a smart constructor,
signaturePacket, that takes all the data *except* the trailer and
auto-generates the trailer, making sure the trailer is always valid, so
that the above becomes possible.
WARNING: SignaturePacket is not *fully* opaque. You *may* still update
fields directly using record syntax (on an already constructed packet).
This may be useful, but if any of the values that make up the trailer
are changed this will MAKE THE PACKET INVALID. This trade-off is deemed
acceptable for now, but may change in the future. Any fields that do not
affect the trailer (unhashed subpackets, etc) may be safely updated in
this way. Other fields MUST be updated by constructing a new
SignaturePacket with the smart constructor.
This usage is exemplefied by Data.OpenPGP.Crypto
The major upside of this is that it is now possible to re-emit
unmodified (or even modified, if only fields not in the trailer are
modified) SignaturePackets without invalidating the signature.
Closes #11
Diffstat (limited to 'Data/OpenPGP.hs')
-rw-r--r-- | Data/OpenPGP.hs | 79 |
1 files changed, 65 insertions, 14 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs index be50d1a..d950570 100644 --- a/Data/OpenPGP.hs +++ b/Data/OpenPGP.hs | |||
@@ -3,7 +3,47 @@ | |||
3 | -- The recommended way to import this module is: | 3 | -- The recommended way to import this module is: |
4 | -- | 4 | -- |
5 | -- > import qualified Data.OpenPGP as OpenPGP | 5 | -- > import qualified Data.OpenPGP as OpenPGP |
6 | module Data.OpenPGP (Message(..), Packet(..), SignatureSubpacket(..), HashAlgorithm(..), KeyAlgorithm(..), CompressionAlgorithm(..), MPI(..), fingerprint_material, signatures_and_data, signature_issuer, calculate_signature_trailer, decode_s2k_count, encode_s2k_count) where | 6 | module Data.OpenPGP ( |
7 | Packet(OnePassSignaturePacket, PublicKeyPacket, SecretKeyPacket, CompressedDataPacket, LiteralDataPacket, UserIDPacket, UnsupportedPacket), | ||
8 | compression_algorithm, | ||
9 | content, | ||
10 | encrypted_data, | ||
11 | filename, | ||
12 | format, | ||
13 | hash_algorithm, | ||
14 | hashed_subpackets, | ||
15 | hash_head, | ||
16 | key, | ||
17 | key_algorithm, | ||
18 | key_id, | ||
19 | message, | ||
20 | nested, | ||
21 | private_hash, | ||
22 | s2k_count, | ||
23 | s2k_hash_algorithm, | ||
24 | s2k_salt, | ||
25 | s2k_type, | ||
26 | s2k_useage, | ||
27 | signature, | ||
28 | signature_type, | ||
29 | symmetric_type, | ||
30 | timestamp, | ||
31 | trailer, | ||
32 | unhashed_subpackets, | ||
33 | version, | ||
34 | isSignaturePacket, | ||
35 | signaturePacket, | ||
36 | Message(..), | ||
37 | SignatureSubpacket(..), | ||
38 | HashAlgorithm(..), | ||
39 | KeyAlgorithm(..), | ||
40 | CompressionAlgorithm(..), | ||
41 | MPI(..), | ||
42 | fingerprint_material, | ||
43 | signatures_and_data, | ||
44 | signature_issuer, | ||
45 | decode_s2k_count, encode_s2k_count | ||
46 | ) where | ||
7 | 47 | ||
8 | import Control.Monad | 48 | import Control.Monad |
9 | import Data.Bits | 49 | import Data.Bits |
@@ -181,22 +221,16 @@ calculate_signature_trailer p = | |||
181 | 221 | ||
182 | put_packet :: (Num a) => Packet -> (LZ.ByteString, a) | 222 | put_packet :: (Num a) => Packet -> (LZ.ByteString, a) |
183 | put_packet (SignaturePacket { version = 4, | 223 | put_packet (SignaturePacket { version = 4, |
184 | signature_type = signature_type, | ||
185 | key_algorithm = key_algorithm, | ||
186 | hash_algorithm = hash_algorithm, | ||
187 | hashed_subpackets = hashed_subpackets, | ||
188 | unhashed_subpackets = unhashed_subpackets, | 224 | unhashed_subpackets = unhashed_subpackets, |
189 | hash_head = hash_head, | 225 | hash_head = hash_head, |
190 | signature = signature }) = | 226 | signature = signature, |
191 | (LZ.concat [ LZ.singleton 4, encode signature_type, | 227 | trailer = trailer }) = |
192 | encode key_algorithm, encode hash_algorithm, | 228 | (LZ.concat [ trailer_top, |
193 | encode (fromIntegral $ LZ.length hashed :: Word16), | ||
194 | hashed, | ||
195 | encode (fromIntegral $ LZ.length unhashed :: Word16), | 229 | encode (fromIntegral $ LZ.length unhashed :: Word16), |
196 | unhashed, | 230 | unhashed, |
197 | encode hash_head, encode signature ], 2) | 231 | encode hash_head, encode signature ], 2) |
198 | where | 232 | where |
199 | hashed = LZ.concat $ map encode hashed_subpackets | 233 | trailer_top = LZ.reverse $ LZ.drop 6 $ LZ.reverse trailer |
200 | unhashed = LZ.concat $ map encode unhashed_subpackets | 234 | unhashed = LZ.concat $ map encode unhashed_subpackets |
201 | put_packet (OnePassSignaturePacket { version = version, | 235 | put_packet (OnePassSignaturePacket { version = version, |
202 | signature_type = signature_type, | 236 | signature_type = signature_type, |
@@ -522,10 +556,8 @@ signatures_and_data :: Message -> ([Packet], [Packet]) | |||
522 | signatures_and_data (Message ((CompressedDataPacket {message = m}):_)) = | 556 | signatures_and_data (Message ((CompressedDataPacket {message = m}):_)) = |
523 | signatures_and_data m | 557 | signatures_and_data m |
524 | signatures_and_data (Message lst) = | 558 | signatures_and_data (Message lst) = |
525 | (filter isSig lst, filter isDta lst) | 559 | (filter isSignaturePacket lst, filter isDta lst) |
526 | where | 560 | where |
527 | isSig (SignaturePacket {}) = True | ||
528 | isSig _ = False | ||
529 | isDta (LiteralDataPacket {}) = True | 561 | isDta (LiteralDataPacket {}) = True |
530 | isDta _ = False | 562 | isDta _ = False |
531 | 563 | ||
@@ -631,3 +663,22 @@ encode_s2k_count iterations | |||
631 | encode_s2k_count' count c | 663 | encode_s2k_count' count c |
632 | | count < 32 = (count, c) | 664 | | count < 32 = (count, c) |
633 | | otherwise = encode_s2k_count' (count `shiftR` 1) (c+1) | 665 | | otherwise = encode_s2k_count' (count `shiftR` 1) (c+1) |
666 | |||
667 | -- SignaturePacket smart constructor | ||
668 | signaturePacket :: Word8 -> Word8 -> KeyAlgorithm -> HashAlgorithm -> [SignatureSubpacket] -> [SignatureSubpacket] -> Word16 -> MPI -> Packet | ||
669 | signaturePacket version signature_type key_algorithm hash_algorithm hashed_subpackets unhashed_subpackets hash_head signature = | ||
670 | let p = SignaturePacket { | ||
671 | version = version, | ||
672 | signature_type = signature_type, | ||
673 | key_algorithm = key_algorithm, | ||
674 | hash_algorithm = hash_algorithm, | ||
675 | hashed_subpackets = hashed_subpackets, | ||
676 | unhashed_subpackets = unhashed_subpackets, | ||
677 | hash_head = hash_head, | ||
678 | signature = signature, | ||
679 | trailer = undefined | ||
680 | } in p { trailer = calculate_signature_trailer p } | ||
681 | |||
682 | isSignaturePacket :: Packet -> Bool | ||
683 | isSignaturePacket (SignaturePacket {}) = True | ||
684 | isSignaturePacket _ = False | ||