diff options
author | Stephen Paul Weber <singpolyma@singpolyma.net> | 2011-08-12 21:03:43 -0500 |
---|---|---|
committer | Stephen Paul Weber <singpolyma@singpolyma.net> | 2011-08-12 21:04:40 -0500 |
commit | 1cc474786194555bec47dd5c061c1bcc5d992952 (patch) | |
tree | 6b4c838a4abad603c208183a17b9df89772cca3c /Data/OpenPGP | |
parent | 531dc4a28554ceaaa495aa02374b559721aa6a9a (diff) |
Refactor sign to handle keys
Also, now if you pass in a message with a signature packet we'll just
use that one instead of making a default one.
Return value is now just the new/filled-in signature packet, update
example accordingly.
Diffstat (limited to 'Data/OpenPGP')
-rw-r--r-- | Data/OpenPGP/Crypto.hs | 77 |
1 files changed, 55 insertions, 22 deletions
diff --git a/Data/OpenPGP/Crypto.hs b/Data/OpenPGP/Crypto.hs index d4d08c0..15c0d63 100644 --- a/Data/OpenPGP/Crypto.hs +++ b/Data/OpenPGP/Crypto.hs | |||
@@ -10,6 +10,7 @@ import Data.Word | |||
10 | import Data.List (find) | 10 | import Data.List (find) |
11 | import Data.Map ((!)) | 11 | import Data.Map ((!)) |
12 | import qualified Data.ByteString.Lazy as LZ | 12 | import qualified Data.ByteString.Lazy as LZ |
13 | import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString) | ||
13 | 14 | ||
14 | import Data.Binary | 15 | import Data.Binary |
15 | import Codec.Utils (fromOctets) | 16 | import Codec.Utils (fromOctets) |
@@ -77,7 +78,7 @@ emsa_pkcs1_v1_5_encode m emLen algo = | |||
77 | 78 | ||
78 | -- | Verify a message signature. Only supports RSA keys for now. | 79 | -- | Verify a message signature. Only supports RSA keys for now. |
79 | verify :: OpenPGP.Message -- ^ Keys that may have made the signature | 80 | verify :: OpenPGP.Message -- ^ Keys that may have made the signature |
80 | -> OpenPGP.Message -- ^ Message containing data and signature packet | 81 | -> OpenPGP.Message -- ^ Message containing data or key to sign, and optional signature packet |
81 | -> Int -- ^ Index of signature to verify (0th, 1st, etc) | 82 | -> Int -- ^ Index of signature to verify (0th, 1st, etc) |
82 | -> Bool | 83 | -> Bool |
83 | verify keys message sigidx = | 84 | verify keys message sigidx = |
@@ -94,47 +95,79 @@ verify keys message sigidx = | |||
94 | (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) = | 95 | (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) = |
95 | OpenPGP.signatures_and_data message | 96 | OpenPGP.signatures_and_data message |
96 | 97 | ||
97 | -- | Sign a message. Only supports RSA keys for now. | 98 | -- | Sign data or key/userID pair. Only supports RSA keys for now. |
98 | sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used | 99 | sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used |
99 | -> OpenPGP.Message -- ^ Message containing LiteralData to sign | 100 | -> OpenPGP.Message -- ^ Message containing LiteralData to sign |
100 | -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use is signature | 101 | -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use is signature |
101 | -> String -- ^ KeyID of key to choose or @[]@ for first | 102 | -> String -- ^ KeyID of key to choose or @[]@ for first |
102 | -> Integer -- ^ Timestamp to put in signature | 103 | -> Integer -- ^ Timestamp for signature (unless sig supplied) |
103 | -> OpenPGP.Message | 104 | -> OpenPGP.Packet |
104 | sign keys message hsh keyid timestamp = | 105 | sign keys message hsh keyid timestamp = |
105 | OpenPGP.Message $ (sig' { | 106 | sig { |
106 | OpenPGP.signature = OpenPGP.MPI $ toNum $ reverse final, | 107 | OpenPGP.signature = OpenPGP.MPI $ toNum final, |
107 | OpenPGP.hash_head = toNum $ take 2 final | 108 | OpenPGP.hash_head = toNum $ take 2 final |
108 | }):m | 109 | } |
109 | where | 110 | where |
110 | -- toNum has explicit param so that it can remain polymorphic | 111 | -- toNum has explicit param so that it can remain polymorphic |
111 | toNum l = fromOctets (256::Integer) l | 112 | toNum l = fromOctets (256::Integer) l |
112 | final = RSA.decrypt (n, d) encoded | 113 | final = dropWhile (==0) $ RSA.decrypt (n, d) encoded |
113 | encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh | 114 | encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh |
114 | (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd') | 115 | (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd') |
115 | dta = LZ.unpack $ LZ.append | 116 | dta = LZ.unpack $ case signOver of { |
116 | (OpenPGP.content dataP) (OpenPGP.trailer sig') | 117 | OpenPGP.LiteralDataPacket {OpenPGP.content = c} -> c; |
117 | sig' = sig { | 118 | _ -> LZ.concat $ OpenPGP.fingerprint_material signOver ++ [ |
118 | OpenPGP.trailer = OpenPGP.calculate_signature_trailer sig | 119 | LZ.singleton 0xB4, |
119 | } | 120 | encode (fromIntegral (length firstUserID) :: Word32), |
120 | sig = OpenPGP.SignaturePacket { | 121 | LZ.fromString firstUserID |
121 | OpenPGP.version = 4, | 122 | ] |
123 | } `LZ.append` OpenPGP.trailer sig | ||
124 | -- Always force key and hash algorithm | ||
125 | sig = let s = (findSigOrDefault (find isSignature m)) { | ||
122 | OpenPGP.key_algorithm = OpenPGP.RSA, | 126 | OpenPGP.key_algorithm = OpenPGP.RSA, |
123 | OpenPGP.hash_algorithm = hsh, | 127 | OpenPGP.hash_algorithm = hsh |
124 | OpenPGP.signature_type = stype, | 128 | } in s { OpenPGP.trailer = OpenPGP.calculate_signature_trailer s } |
129 | |||
130 | -- Either a SignaturePacket was found, or we need to make one | ||
131 | findSigOrDefault (Just s) = s | ||
132 | findSigOrDefault Nothing = OpenPGP.SignaturePacket { | ||
133 | OpenPGP.version = 4, | ||
134 | OpenPGP.key_algorithm = undefined, | ||
135 | OpenPGP.hash_algorithm = undefined, | ||
136 | OpenPGP.signature_type = defaultStype, | ||
125 | OpenPGP.hashed_subpackets = [ | 137 | OpenPGP.hashed_subpackets = [ |
138 | -- Do we really need to pass in timestamp just for the default? | ||
126 | OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp, | 139 | OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp, |
127 | OpenPGP.IssuerPacket keyid' | 140 | OpenPGP.IssuerPacket keyid' |
128 | ], | 141 | ] ++ (case signOver of |
142 | OpenPGP.LiteralDataPacket {} -> [] | ||
143 | _ -> [] -- TODO: OpenPGP.KeyFlagsPacket [0x01, 0x02] | ||
144 | ), | ||
129 | OpenPGP.unhashed_subpackets = [], | 145 | OpenPGP.unhashed_subpackets = [], |
130 | OpenPGP.signature = undefined, | 146 | OpenPGP.signature = undefined, |
131 | OpenPGP.trailer = undefined, | 147 | OpenPGP.trailer = undefined, |
132 | OpenPGP.hash_head = undefined | 148 | OpenPGP.hash_head = undefined |
133 | } | 149 | } |
150 | |||
134 | keyid' = reverse $ take 16 $ reverse $ fingerprint k | 151 | keyid' = reverse $ take 16 $ reverse $ fingerprint k |
135 | stype = if OpenPGP.format dataP == 'b' then 0x00 else 0x01 | ||
136 | Just k = find_key keys keyid | 152 | Just k = find_key keys keyid |
137 | Just dataP = find isLiteralData m | 153 | |
154 | Just (OpenPGP.UserIDPacket firstUserID) = find isUserID m | ||
155 | |||
156 | defaultStype = case signOver of | ||
157 | OpenPGP.LiteralDataPacket {OpenPGP.format = f} -> | ||
158 | if f == 'b' then 0x00 else 0x01 | ||
159 | _ -> 0x13 | ||
160 | |||
161 | Just signOver = find isSignable m | ||
138 | OpenPGP.Message m = message | 162 | OpenPGP.Message m = message |
139 | isLiteralData (OpenPGP.LiteralDataPacket {}) = True | 163 | |
140 | isLiteralData _ = False | 164 | isSignable (OpenPGP.LiteralDataPacket {}) = True |
165 | isSignable (OpenPGP.PublicKeyPacket {}) = True | ||
166 | isSignable (OpenPGP.SecretKeyPacket {}) = True | ||
167 | isSignable _ = False | ||
168 | |||
169 | isSignature (OpenPGP.SignaturePacket {}) = True | ||
170 | isSignature _ = False | ||
171 | |||
172 | isUserID (OpenPGP.UserIDPacket {}) = True | ||
173 | isUserID _ = False | ||