3 ### Testing key-management functionality
5 ### (c) 2019 Straylight/Edgeware
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of the Python interface to Catacomb.
12 ### Catacomb/Python is free software: you can redistribute it and/or
13 ### modify it under the terms of the GNU General Public License as
14 ### published by the Free Software Foundation; either version 2 of the
15 ### License, or (at your option) any later version.
17 ### Catacomb/Python is distributed in the hope that it will be useful, but
18 ### WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ### General Public License for more details.
22 ### You should have received a copy of the GNU General Public License
23 ### along with Catacomb/Python. If not, write to the Free Software
24 ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 ###--------------------------------------------------------------------------
36 ###--------------------------------------------------------------------------
37 class TestKeyError (U
.TestCase
):
39 def test_keyerror(me
):
41 try: C
.KeyFile("notexist", C
.KOPEN_NOFILE
).newkey(1, "foo")
42 except C
.KeyError: e
= SYS
.exc_info()[1]
43 else: me
.fail("expected `catacomb.KeyError'")
44 me
.assertEqual(e
.err
, C
.KERR_READONLY
)
45 me
.assertEqual(e
.errstring
, "Key file is read-only")
46 me
.assertEqual(e
.args
, (C
.KERR_READONLY
,))
47 me
.assertEqual(str(e
),
48 "KERR_READONLY (%d): Key file is read-only" %
51 me
.assertRaises(TypeError, C
.KeyError)
53 e
= C
.KeyError(C
.KERR_DUPID
, token
)
54 me
.assertEqual(e
.err
, C
.KERR_DUPID
)
55 me
.assertEqual(e
.errstring
, "Key id already exists")
56 me
.assertEqual(e
.args
, (C
.KERR_DUPID
, token
))
58 ###--------------------------------------------------------------------------
59 class TestKeyFile (U
.TestCase
):
63 kf
= C
.KeyFile("t/keyring")
65 ## Check basic attributes.
66 me
.assertEqual(kf
.name
, "t/keyring")
67 me
.assertEqual(kf
.modifiedp
, False)
68 me
.assertEqual(kf
.writep
, False)
69 me
.assertEqual(kf
.filep
, False)
72 me
.assertEqual(set(k
.type for k
in T
.itervalues(kf
)),
73 set(["rsa", "ec", "ec-param", "twofish"]))
74 me
.assertEqual(len(kf
), 4)
78 me
.assertEqual(k
.type, "rsa")
79 me
.assertEqual(k
.id, 0x8599dbab)
80 me
.assertEqual(type(k
.data
), C
.KeyDataStructured
)
81 me
.assertEqual(set(k
.data
), set(["e", "n", "private"]))
82 priv
= k
.data
["private"]
83 me
.assertEqual(type(priv
), C
.KeyDataEncrypted
)
84 me
.assertRaises(C
.KeyError, priv
.unlock
, T
.bin("wrong secret"))
85 priv
= priv
.unlock(T
.bin("very secret"))
86 me
.assertEqual(type(priv
), C
.KeyDataStructured
)
87 me
.assertEqual(set(priv
),
88 set(["p", "q", "d", "d-mod-p", "d-mod-q", "q-inv"]))
89 me
.assertEqual(k
.data
["n"].mp
, priv
["p"].mp
*priv
["q"].mp
)
91 ## This key has an attribute. Poke about at them.
93 me
.assertEqual(len(a
), 1)
94 me
.assertEqual(set(a
), set(["attr"]))
95 me
.assertEqual(a
["attr"], "value")
96 me
.assertRaises(KeyError, lambda: a
["notexist"])
97 me
.assertEqual(a
.get("attr"), "value")
98 me
.assertEqual(a
.get("notexist"), None)
100 ## Check fingerprinting while we're here.
101 for filter in ["-secret", "none"]:
102 h
= C
.sha256(); me
.assertTrue(k
.fingerprint(h
, filter)); fp0
= h
.done()
104 h
.hash(T
.bin("catacomb-key-fingerprint:")) \
106 .hashbuf8(T
.bin(k
.type))
107 h
.hash(k
.data
.encode(filter))
108 for a
in sorted(T
.iterkeys(k
.attr
)):
109 h
.hashbuf8(T
.bin(a
)).hashbuf16(T
.bin(k
.attr
[a
]))
111 me
.assertEqual(fp0
, fp1
)
113 ## Try `ec-param'. This should be fairly easy.
115 me
.assertEqual(k
.tag
, None)
116 me
.assertEqual(k
.id, 0x4a4e1ee7)
117 me
.assertEqual(type(k
.data
), C
.KeyDataStructured
)
118 me
.assertEqual(set(k
.data
), set(["curve"]))
119 curve
= k
.data
["curve"]
120 me
.assertEqual(type(curve
), C
.KeyDataString
)
121 me
.assertEqual(curve
.str, "nist-p256")
123 ## Check qualified-tag lookups.
124 me
.assertRaises(C
.KeyError, kf
.qtag
, "notexist.curve")
125 me
.assertRaises(C
.KeyError, kf
.qtag
, "ec-param.notexist")
126 t
, k
, kd
= kf
.qtag("ec-param.curve")
127 me
.assertEqual(t
, "4a4e1ee7:ec-param.curve")
128 me
.assertEqual(k
.type, "ec-param")
129 me
.assertEqual(type(kd
), C
.KeyDataString
)
130 me
.assertEqual(kd
.str, "nist-p256")
132 ## Try `ec'. A little trickier.
134 me
.assertEqual(k
.tag
, None)
135 me
.assertEqual(k
.id, 0xbd761d35)
136 me
.assertEqual(type(k
.data
), C
.KeyDataStructured
)
137 me
.assertEqual(set(k
.data
), set(["curve", "p", "private"]))
138 curve
= k
.data
["curve"]
139 me
.assertEqual(type(curve
), C
.KeyDataString
)
140 me
.assertEqual(curve
.str, "nist-p256")
141 einfo
= C
.eccurves
[curve
.str]
142 me
.assertEqual(type(k
.data
["p"]), C
.KeyDataECPt
)
144 priv
= k
.data
["private"]
145 me
.assertEqual(type(priv
), C
.KeyDataEncrypted
)
146 me
.assertRaises(C
.KeyError, priv
.unlock
, T
.bin("wrong secret"))
147 priv
= priv
.unlock(T
.bin("super secret"))
148 me
.assertEqual(type(priv
), C
.KeyDataStructured
)
149 me
.assertEqual(set(priv
), set(["x"]))
151 me
.assertEqual(x
*einfo
.G
, X
)
153 ## Finish with `twofish'.
154 k
= kf
.byid(0x60090be2)
155 me
.assertEqual(k
.tag
, None)
156 me
.assertEqual(k
.type, "twofish")
157 me
.assertEqual(type(k
.data
), C
.KeyDataEncrypted
)
158 me
.assertRaises(C
.KeyError, k
.data
.unlock
, T
.bin("wrong secret"))
159 kd
= k
.data
.unlock(T
.bin("not secret"))
160 me
.assertEqual(type(kd
), C
.KeyDataBinary
)
161 me
.assertEqual(kd
.bin
, C
.bytes("d337b98eea24425826df202a6a3d1ef8"
162 "377b71923fe1179451564776da29bb84"))
164 ## Check unsuccessful searches.
165 me
.assertRaises(KeyError, lambda: kf
["notexist"])
166 me
.assertEqual(kf
.bytag("notexist"), None)
167 me
.assertEqual(kf
.bytag(12345), None)
168 me
.assertEqual(kf
.bytype("notexist"), None)
169 me
.assertRaises(TypeError, kf
.bytype
, 12345)
170 me
.assertRaises(C
.KeyError, kf
.byid
, 0x12345678)
172 me
.assertRaises(C
.KeyError, kf
.mergeline
, "nowhere", 2, "")
174 ## The keyring should be readonly.
175 me
.assertRaises(C
.KeyError, kf
.newkey
, 0x12345678, "fail")
176 me
.assertRaises(C
.KeyError, setattr, k
, "tag", "foo")
177 me
.assertRaises(C
.KeyError, delattr, k
, "tag")
178 me
.assertRaises(C
.KeyError, kf
.mergeline
, "notexist", 1,
179 "22222222:test integer,public:32519164 forever forever -")
180 me
.assertRaises(C
.KeyError, setattr, k
, "data", C
.KeyDataString("foo"))
182 def test_keywrite(me
):
183 kf
= C
.KeyFile("test", C
.KOPEN_WRITE | C
.KOPEN_NOFILE
)
184 me
.assertEqual(kf
.modifiedp
, False)
188 k
= kf
.newkey(0x11111111, "first", exp
)
189 me
.assertEqual(kf
.modifiedp
, True)
191 me
.assertEqual(k
, kf
[0x11111111])
192 me
.assertEqual(k
.exptime
, exp
)
193 me
.assertEqual(k
.deltime
, exp
)
194 me
.assertRaises(ValueError, setattr, k
, "deltime", C
.KEXP_FOREVER
)
196 me
.assertEqual(k
.data
.str, "<unset>")
198 k
.data
= C
.KeyDataMP(n
)
199 me
.assertEqual(k
.data
.mp
, n
)
200 me
.assertEqual(k
.comment
, None)
203 me
.assertEqual(k
.comment
, c
)
205 me
.assertEqual(k
.comment
, None)
207 me
.assertEqual(k
.comment
, c
)
209 me
.assertEqual(k
.comment
, None)
211 kf
.mergeline("notexist", 1,
212 "22222222:test integer,public:32519164 forever forever -")
214 ###--------------------------------------------------------------------------
215 class TestKeyData (U
.TestCase
):
218 me
.assertEqual(C
.KeyData
.readflags("none"), (0, 0, ""))
219 me
.assertEqual(C
.KeyData
.readflags("ec,public:..."),
220 (C
.KENC_EC | C
.KCAT_PUB
,
221 C
.KF_ENCMASK | C
.KF_CATMASK
,
223 me
.assertEqual(C
.KeyData
.readflags("int,burn"),
224 (C
.KENC_MP | C
.KF_BURN
, C
.KF_ENCMASK | C
.KF_BURN
, ""))
225 me
.assertRaises(C
.KeyError, C
.KeyData
.readflags
, "int,burn?")
226 me
.assertRaises(C
.KeyError, C
.KeyData
.readflags
, "int,ec")
227 me
.assertRaises(C
.KeyError, C
.KeyData
.readflags
, "snork")
228 me
.assertEqual(C
.KeyData
.writeflags(0), "binary,symmetric")
229 me
.assertEqual(C
.KeyData
.writeflags(C
.KENC_EC | C
.KCAT_PUB
), "ec,public")
232 kd
= C
.KeyDataStructured({ "a": C
.KeyDataString("foo", "public"),
233 "b": C
.KeyDataMP(12345, "private"),
234 "c": C
.KeyDataString("bar", "public") })
237 me
.assertEqual(type(kd2
), C
.KeyDataStructured
)
238 me
.assertEqual(set(T
.iterkeys(kd2
)), set(["a", "b", "c"]))
240 kd2
= C
.KeyDataMP(12345, C
.KCAT_PRIV
).copy("private")
242 kd2
= kd
.copy("-secret")
243 me
.assertEqual(type(kd2
), C
.KeyDataStructured
)
244 me
.assertEqual(set(T
.iterkeys(kd2
)), set(["a", "c"]))
246 kd2
= kd
.copy((0, C
.KF_NONSECRET
))
247 me
.assertEqual(type(kd2
), C
.KeyDataStructured
)
248 me
.assertEqual(set(T
.iterkeys(kd2
)), set(["b"]))
250 def check_encode(me
, kd
):
251 me
.assertEqual(C
.KeyData
.decode(kd
.encode()), kd
)
252 me
.assertEqual(C
.KeyData
.read(kd
.write()), (kd
, ""))
255 rng
= T
.detrand("kd-bin")
257 kd
= C
.KeyDataBinary(by
, "symm,burn")
258 me
.assertEqual(kd
.bin
, by
)
262 rng
= T
.detrand("kd-mp")
264 kd
= C
.KeyDataMP(x
, "symm,burn")
265 me
.assertEqual(kd
.mp
, x
)
269 s
= "some random string"
270 kd
= C
.KeyDataString(s
, "symm,burn")
271 me
.assertEqual(kd
.str, s
)
275 rng
= T
.detrand("kd-enc")
277 kd
= C
.KeyDataEncrypted(ct
, "symm")
278 me
.assertEqual(kd
.ct
, ct
)
282 rng
= T
.detrand("kd-ec")
283 Q
= C
.ECPt(rng
.mp(128), rng
.mp(128))
284 kd
= C
.KeyDataECPt(Q
, "symm,burn")
285 me
.assertEqual(kd
.ecpt
, Q
)
289 rng
= T
.detrand("kd-struct")
290 kd
= C
.KeyDataStructured({ "a": C
.KeyDataString("a"),
291 "b": C
.KeyDataString("b"),
292 "c": C
.KeyDataString("c"),
293 "d": C
.KeyDataString("d") })
294 for i
in ["a", "b", "c", "d"]: me
.assertEqual(kd
[i
].str, i
)
295 me
.assertEqual(len(kd
), 4)
297 me
.assertRaises(TypeError, C
.KeyDataStructured
, { "a": "a" })
299 ###--------------------------------------------------------------------------
302 class TestKeyFileMapping (T
.ImmutableMappingTextMixin
):
303 def _mkkey(me
, i
): return i
304 def _getkey(me
, k
): return k
305 def _getvalue(me
, v
): return v
.data
.mp
307 def test_keyfile(me
):
308 kf
= C
.KeyFile("test", C
.KOPEN_WRITE | C
.KOPEN_NOFILE
)
312 kf
.newkey(i
, "k#%d" % i
).data
= C
.KeyDataMP(100 + i
)
314 me
.assertEqual(kf
[1], kf
[1])
316 me
.check_immutable_mapping(kf
, model
)
318 class TestKeyStructMapping (T
.MutableMappingTestMixin
):
319 def _mkvalue(me
, i
): return C
.KeyDataMP(i
)
320 def _getvalue(me
, v
): return v
.mp
322 def test_keystructmap(me
):
323 me
.check_mapping(C
.KeyDataStructured
)
325 class TestKeyAttrMapping (T
.MutableMappingTestMixin
):
327 def test_attrmap(me
):
329 kf
= C
.KeyFile("test", C
.KOPEN_WRITE | C
.KOPEN_NOFILE
)
330 k
= kf
.newkey(0x12345678, "test-key")
332 me
.check_mapping(mkmap
)
335 me
.assertRaises(TypeError, a
.update
, { 3: 3, 4: 5 })
337 ###----- That's all, folks --------------------------------------------------
339 if __name__
== "__main__": U
.main()