Merge branch 'master' of github.com:dnsviz/dnsviz
Casey Deccio
8 years ago
37 | 37 | Note that support for the following DNSSEC algorithms is not yet available in |
38 | 38 | stock releases of M2Crypto: 3 (DSA-SHA1), 6 (DSA-NSEC3-SHA1), |
39 | 39 | 12 (GOST R 34.10-2001), 13 (ECDSA Curve P-256 with SHA-256), 14 (ECDSA Curve |
40 | P-384 with SHA-384). However, the patch included in "contrib/m2crypto.patch" | |
41 | can be applied to M2Crypto 0.21.1 or M2Crypto 0.22.3 to support these | |
42 | algorithms: | |
40 | P-384 with SHA-384). However, there are two patches included in the | |
41 | `contrib` directory that can be applied to M2Crypto 0.21.1, M2Crypto 0.22.3 | |
42 | (`config/m2crypto-pre0.26.patch`), or M2Crypto 0.26 | |
43 | (`config/m2crypto-0.26.patch`). For example: | |
43 | 44 | |
44 | 45 | ``` |
45 | $ patch -p1 < /path/to/dnsviz-source/contrib/m2crypto.patch | |
46 | $ patch -p1 < /path/to/dnsviz-source/contrib/m2crypto-pre0.26.patch | |
46 | 47 | ``` |
47 | 48 | |
48 | 49 | ### Build and Install |
0 | diff --git a/M2Crypto/DSA.py b/M2Crypto/DSA.py | |
1 | index 57d123b..325e418 100644 | |
2 | --- a/M2Crypto/DSA.py | |
3 | +++ b/M2Crypto/DSA.py | |
4 | @@ -396,6 +396,29 @@ def load_key_bio(bio, callback=util.passphrase_callback): | |
5 | raise DSAError('problem loading DSA key pair') | |
6 | return DSA(dsa, 1) | |
7 | ||
8 | +def pub_key_from_params(p, q, g, pub): | |
9 | + """ | |
10 | + Factory function that instantiates a DSA_pub object using | |
11 | + the parameters and public key specified. | |
12 | + | |
13 | + @type p: str | |
14 | + @param p: value of p, a "byte string" | |
15 | + @type q: str | |
16 | + @param q: value of q, a "byte string" | |
17 | + @type g: str | |
18 | + @param g: value of g, a "byte string" | |
19 | + @type pub: str | |
20 | + @param pub: value of the public key, a "byte string" | |
21 | + @rtype: DSA_pub | |
22 | + @return: instance of DSA_pub. | |
23 | + """ | |
24 | + dsa = m2.dsa_new() | |
25 | + m2.dsa_set_p(dsa, p) | |
26 | + m2.dsa_set_q(dsa, q) | |
27 | + m2.dsa_set_g(dsa, g) | |
28 | + m2.dsa_set_pub(dsa, pub) | |
29 | + return DSA_pub(dsa, 1) | |
30 | + | |
31 | ||
32 | def load_pub_key(file, callback=util.passphrase_callback): | |
33 | """ | |
34 | diff --git a/M2Crypto/EC.py b/M2Crypto/EC.py | |
35 | index a4a9faf..800a705 100644 | |
36 | --- a/M2Crypto/EC.py | |
37 | +++ b/M2Crypto/EC.py | |
38 | @@ -254,6 +254,13 @@ class EC_pub(EC): | |
39 | self.der = m2.ec_key_get_public_der(self.ec) | |
40 | return self.der | |
41 | ||
42 | + def get_key(self): | |
43 | + """ | |
44 | + Returns the public key as a byte string. | |
45 | + """ | |
46 | + assert self.check_key(), 'key is not initialised' | |
47 | + return m2.ec_key_get_public_key(self.ec) | |
48 | + | |
49 | save_key = EC.save_pub_key | |
50 | ||
51 | save_key_bio = EC.save_pub_key_bio | |
52 | @@ -333,3 +340,9 @@ def pub_key_from_der(der): | |
53 | Create EC_pub from DER. | |
54 | """ | |
55 | return EC_pub(m2.ec_key_from_pubkey_der(der), 1) | |
56 | + | |
57 | +def pub_key_from_params(curve, bytes): | |
58 | + """ | |
59 | + Create EC_pub from curve name and octet string. | |
60 | + """ | |
61 | + return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1) | |
62 | diff --git a/M2Crypto/EVP.py b/M2Crypto/EVP.py | |
63 | index 12618a2..28303bd 100644 | |
64 | --- a/M2Crypto/EVP.py | |
65 | +++ b/M2Crypto/EVP.py | |
66 | @@ -40,8 +40,13 @@ class MessageDigest: | |
67 | def __init__(self, algo): | |
68 | md = getattr(m2, algo, None) | |
69 | if md is None: | |
70 | - raise ValueError('unknown algorithm', algo) | |
71 | - self.md = md() | |
72 | + # if the digest algorithm isn't found as an attribute of the m2 | |
73 | + # module, try to look up the digest using get_digestbyname() | |
74 | + self.md = m2.get_digestbyname(algo) | |
75 | + if self.md is None: | |
76 | + raise ValueError('unknown algorithm', algo) | |
77 | + else: | |
78 | + self.md = md() | |
79 | self.ctx = m2.md_ctx_new() | |
80 | m2.digest_init(self.ctx, self.md) | |
81 | ||
82 | @@ -389,6 +394,25 @@ def load_key_bio(bio, callback=util.passphrase_callback): | |
83 | raise EVPError(Err.get_error()) | |
84 | return PKey(cptr, 1) | |
85 | ||
86 | +def load_key_bio_pubkey(bio, callback=util.passphrase_callback): | |
87 | + """ | |
88 | + Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. | |
89 | + | |
90 | + @type bio: M2Crypto.BIO | |
91 | + @param bio: M2Crypto.BIO object containing the key in PEM format. | |
92 | + | |
93 | + @type callback: Python callable | |
94 | + @param callback: A Python callable object that is invoked | |
95 | + to acquire a passphrase with which to protect the key. | |
96 | + | |
97 | + @rtype: M2Crypto.EVP.PKey | |
98 | + @return: M2Crypto.EVP.PKey object. | |
99 | + """ | |
100 | + cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) | |
101 | + if cptr is None: | |
102 | + raise EVPError(Err.get_error()) | |
103 | + return PKey(cptr, 1) | |
104 | + | |
105 | def load_key_string(string, callback=util.passphrase_callback): | |
106 | """ | |
107 | Load an M2Crypto.EVP.PKey from a string. | |
108 | @@ -405,3 +429,20 @@ def load_key_string(string, callback=util.passphrase_callback): | |
109 | """ | |
110 | bio = BIO.MemoryBuffer(string) | |
111 | return load_key_bio(bio, callback) | |
112 | + | |
113 | +def load_key_string_pubkey(string, callback=util.passphrase_callback): | |
114 | + """ | |
115 | + Load an M2Crypto.EVP.PKey from a public key as a string. | |
116 | + | |
117 | + @type string: string | |
118 | + @param string: String containing the key in PEM format. | |
119 | + | |
120 | + @type callback: Python callable | |
121 | + @param callback: A Python callable object that is invoked | |
122 | + to acquire a passphrase with which to protect the key. | |
123 | + | |
124 | + @rtype: M2Crypto.EVP.PKey | |
125 | + @return: M2Crypto.EVP.PKey object. | |
126 | + """ | |
127 | + bio = BIO.MemoryBuffer(string) | |
128 | + return load_key_bio_pubkey(bio, callback) | |
129 | diff --git a/SWIG/_dsa.i b/SWIG/_dsa.i | |
130 | index a35dd88..a6da42d 100644 | |
131 | --- a/SWIG/_dsa.i | |
132 | +++ b/SWIG/_dsa.i | |
133 | @@ -153,6 +153,25 @@ PyObject *dsa_set_g(DSA *dsa, PyObject *value) { | |
134 | Py_INCREF(Py_None); | |
135 | return Py_None; | |
136 | } | |
137 | + | |
138 | +PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { | |
139 | + BIGNUM *bn; | |
140 | + const void *vbuf; | |
141 | + int vlen; | |
142 | + | |
143 | + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) | |
144 | + return NULL; | |
145 | + | |
146 | + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { | |
147 | + PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); | |
148 | + return NULL; | |
149 | + } | |
150 | + if (dsa->pub_key) | |
151 | + BN_free(dsa->pub_key); | |
152 | + dsa->pub_key = bn; | |
153 | + Py_INCREF(Py_None); | |
154 | + return Py_None; | |
155 | +} | |
156 | %} | |
157 | ||
158 | %inline %{ | |
159 | diff --git a/SWIG/_ec.i b/SWIG/_ec.i | |
160 | index f0e52bd..9065c10 100644 | |
161 | --- a/SWIG/_ec.i | |
162 | +++ b/SWIG/_ec.i | |
163 | @@ -189,6 +189,43 @@ PyObject *ec_key_get_public_der(EC_KEY *key) { | |
164 | ||
165 | return pyo; | |
166 | } | |
167 | + | |
168 | +PyObject *ec_key_get_public_key(EC_KEY *key) { | |
169 | + | |
170 | + unsigned char *src=NULL; | |
171 | + void *dst=NULL; | |
172 | + int src_len=0; | |
173 | + Py_ssize_t dst_len=0; | |
174 | + PyObject *pyo=NULL; | |
175 | + int ret=0; | |
176 | + | |
177 | + /* Convert to binary */ | |
178 | + src_len = i2o_ECPublicKey(key, &src); | |
179 | + if (src_len < 0) | |
180 | + { | |
181 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
182 | + return NULL; | |
183 | + } | |
184 | + | |
185 | + /* Create a PyBuffer containing a copy of the binary, | |
186 | + * to simplify memory deallocation | |
187 | + */ | |
188 | + pyo = PyBuffer_New( src_len ); | |
189 | + ret = PyObject_AsWriteBuffer( pyo, &dst, &dst_len ); | |
190 | + assert( src_len == dst_len ); | |
191 | + if (ret < 0) | |
192 | + { | |
193 | + Py_DECREF(pyo); | |
194 | + OPENSSL_free(src); | |
195 | + PyErr_SetString(_ec_err, "cannot get write buffer"); | |
196 | + return NULL; | |
197 | + } | |
198 | + memcpy( dst, src, src_len ); | |
199 | + OPENSSL_free(src); | |
200 | + | |
201 | + return pyo; | |
202 | +} | |
203 | + | |
204 | %} | |
205 | ||
206 | %threadallow ec_key_read_pubkey; | |
207 | @@ -404,6 +441,32 @@ EC_KEY* ec_key_from_pubkey_der(PyObject *pubkey) { | |
208 | return keypair; | |
209 | } | |
210 | ||
211 | +EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { | |
212 | + const void *keypairbuf; | |
213 | + Py_ssize_t keypairbuflen; | |
214 | + const unsigned char *tempBuf; | |
215 | + EC_KEY *keypair; | |
216 | + | |
217 | + if (PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) | |
218 | + { | |
219 | + return NULL; | |
220 | + } | |
221 | + | |
222 | + keypair = ec_key_new_by_curve_name(nid); | |
223 | + if (!keypair) { | |
224 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
225 | + return NULL; | |
226 | + } | |
227 | + | |
228 | + tempBuf = (const unsigned char *)keypairbuf; | |
229 | + if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0) | |
230 | + { | |
231 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
232 | + return NULL; | |
233 | + } | |
234 | + return keypair; | |
235 | +} | |
236 | + | |
237 | ||
238 | // According to [SEC2] the degree of the group is defined as EC key length | |
239 | int ec_key_keylen(EC_KEY *key) { | |
240 | diff --git a/SWIG/_evp.i b/SWIG/_evp.i | |
241 | index 85382db..033897b 100644 | |
242 | --- a/SWIG/_evp.i | |
243 | +++ b/SWIG/_evp.i | |
244 | @@ -49,6 +49,9 @@ extern const EVP_MD *EVP_sha512(void); | |
245 | %rename(digest_init) EVP_DigestInit; | |
246 | extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *); | |
247 | ||
248 | +%rename(get_digestbyname) EVP_get_digestbyname; | |
249 | +extern EVP_MD *EVP_get_digestbyname(const char * name); | |
250 | + | |
251 | %rename(des_ecb) EVP_des_ecb; | |
252 | extern const EVP_CIPHER *EVP_des_ecb(void); | |
253 | %rename(des_ede_ecb) EVP_des_ede; | |
254 | @@ -519,6 +522,17 @@ EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) { | |
255 | return pk; | |
256 | } | |
257 | ||
258 | +EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { | |
259 | + EVP_PKEY *pk; | |
260 | + | |
261 | + Py_INCREF(pyfunc); | |
262 | + Py_BEGIN_ALLOW_THREADS | |
263 | + pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); | |
264 | + Py_END_ALLOW_THREADS | |
265 | + Py_DECREF(pyfunc); | |
266 | + return pk; | |
267 | +} | |
268 | + | |
269 | int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { | |
270 | return EVP_PKEY_assign_RSA(pkey, rsa); | |
271 | } | |
272 | diff --git a/tests/test_dsa.py b/tests/test_dsa.py | |
273 | index 27d1f61..c224a53 100644 | |
274 | --- a/tests/test_dsa.py | |
275 | +++ b/tests/test_dsa.py | |
276 | @@ -99,6 +99,19 @@ class DSATestCase(unittest.TestCase): | |
277 | r, s = dsa2.sign(self.data) | |
278 | assert dsa2.verify(self.data, r, s) | |
279 | ||
280 | + def test_pub_key_from_params(self): | |
281 | + dsa = DSA.gen_params(1024, self.callback) | |
282 | + dsa.gen_key() | |
283 | + assert len(dsa) == 1024 | |
284 | + p = dsa.p | |
285 | + q = dsa.q | |
286 | + g = dsa.g | |
287 | + pub = dsa.pub | |
288 | + dsa2 = DSA.pub_key_from_params(p,q,g,pub) | |
289 | + assert dsa2.check_key() | |
290 | + r,s = dsa.sign(self.data) | |
291 | + assert dsa2.verify(self.data, r, s) | |
292 | + | |
293 | def suite(): | |
294 | return unittest.makeSuite(DSATestCase) | |
295 | ||
296 | diff --git a/tests/test_ecdsa.py b/tests/test_ecdsa.py | |
297 | index d6c75d1..d28be96 100644 | |
298 | --- a/tests/test_ecdsa.py | |
299 | +++ b/tests/test_ecdsa.py | |
300 | @@ -70,6 +70,16 @@ class ECDSATestCase(unittest.TestCase): | |
301 | ec = EC.gen_params(EC.NID_sect233k1) | |
302 | self.assertEqual(len(ec), 233) | |
303 | ||
304 | + def test_pub_key_from_params(self): | |
305 | + curve = EC.NID_X9_62_prime256v1 | |
306 | + ec = EC.gen_params(curve) | |
307 | + ec.gen_key() | |
308 | + ec_pub = ec.pub() | |
309 | + k = ec_pub.get_key() | |
310 | + ec2 = EC.pub_key_from_params(curve, k) | |
311 | + assert ec2.check_key() | |
312 | + r, s = ec.sign_dsa(self.data) | |
313 | + assert ec2.verify_dsa(self.data, r, s) | |
314 | ||
315 | def suite(): | |
316 | return unittest.makeSuite(ECDSATestCase) | |
317 | diff --git a/tests/test_evp.py b/tests/test_evp.py | |
318 | index 8cf7d12..bddec84 100644 | |
319 | --- a/tests/test_evp.py | |
320 | +++ b/tests/test_evp.py | |
321 | @@ -58,6 +58,9 @@ class EVPTestCase(unittest.TestCase): | |
322 | # A quick but not thorough sanity check | |
323 | self.assertEqual(len(der_blob), 160) | |
324 | ||
325 | + def test_get_digestbyname(self): | |
326 | + self.assertEqual(m2.get_digestbyname('sha513'), None) | |
327 | + self.assertNotEqual(m2.get_digestbyname('sha1'), None) | |
328 | ||
329 | def test_MessageDigest(self): | |
330 | with self.assertRaises(ValueError): | |
331 | @@ -66,6 +69,19 @@ class EVPTestCase(unittest.TestCase): | |
332 | self.assertEqual(md.update('Hello'), 1) | |
333 | self.assertEqual(util.octx_to_num(md.final()), 1415821221623963719413415453263690387336440359920) | |
334 | ||
335 | + # temporarily remove sha1 from m2 | |
336 | + old_sha1 = m2.sha1 | |
337 | + del m2.sha1 | |
338 | + | |
339 | + # now run the same test again, relying on EVP.MessageDigest() to call | |
340 | + # get_digestbyname() under the hood | |
341 | + md = EVP.MessageDigest('sha1') | |
342 | + self.assertEqual(md.update('Hello'), 1) | |
343 | + self.assertEqual(util.octx_to_num(md.final()), 1415821221623963719413415453263690387336440359920) | |
344 | + | |
345 | + # put sha1 back in place | |
346 | + m2.sha1 = old_sha1 | |
347 | + | |
348 | def test_as_der_capture_key(self): | |
349 | """ | |
350 | Test DER encoding the PKey instance after assigning | |
351 | @@ -140,6 +156,26 @@ class EVPTestCase(unittest.TestCase): | |
352 | rsa3 = RSA.gen_key(1024, 3, callback=self._gen_callback) | |
353 | self.assertNotEqual(rsa.sign(digest), rsa3.sign(digest)) | |
354 | ||
355 | + def test_load_key_string_pubkey(self): | |
356 | + """ | |
357 | + Testing creating a PKey instance from PEM string. | |
358 | + """ | |
359 | + rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) | |
360 | + self.assertIsInstance(rsa, RSA.RSA) | |
361 | + | |
362 | + rsa_pem = BIO.MemoryBuffer() | |
363 | + rsa.save_pub_key_bio(rsa_pem) | |
364 | + pkey = EVP.load_key_string_pubkey(rsa_pem.read()) | |
365 | + rsa2 = pkey.get_rsa() | |
366 | + self.assertIsInstance(rsa2, RSA.RSA_pub) | |
367 | + self.assertEqual(rsa.e, rsa2.e) | |
368 | + self.assertEqual(rsa.n, rsa2.n) | |
369 | + pem = rsa.as_pem(callback=self._pass_callback) | |
370 | + pem2 = rsa2.as_pem() | |
371 | + assert pem | |
372 | + assert pem2 | |
373 | + self.assertNotEqual(pem, pem2) | |
374 | + | |
375 | def test_get_rsa_fail(self): | |
376 | """ | |
377 | Testing trying to retrieve the RSA key from the PKey instance |
0 | diff -ur M2Crypto-0.22.3/M2Crypto/DSA.py M2Crypto-0.22.3.new/M2Crypto/DSA.py | |
1 | --- M2Crypto-0.22.3/M2Crypto/DSA.py 2014-01-22 14:37:01.000000000 -0500 | |
2 | +++ M2Crypto-0.22.3.new/M2Crypto/DSA.py 2016-01-12 19:25:07.000000000 -0500 | |
3 | @@ -394,6 +394,29 @@ | |
4 | raise DSAError('problem loading DSA key pair') | |
5 | return DSA(dsa, 1) | |
6 | ||
7 | +def pub_key_from_params(p, q, g, pub): | |
8 | + """ | |
9 | + Factory function that instantiates a DSA_pub object using | |
10 | + the parameters and public key specified. | |
11 | + | |
12 | + @type p: str | |
13 | + @param p: value of p, a "byte string" | |
14 | + @type q: str | |
15 | + @param q: value of q, a "byte string" | |
16 | + @type g: str | |
17 | + @param g: value of g, a "byte string" | |
18 | + @type pub: str | |
19 | + @param pub: value of the public key, a "byte string" | |
20 | + @rtype: DSA_pub | |
21 | + @return: instance of DSA_pub. | |
22 | + """ | |
23 | + dsa = m2.dsa_new() | |
24 | + m2.dsa_set_p(dsa, p) | |
25 | + m2.dsa_set_q(dsa, q) | |
26 | + m2.dsa_set_g(dsa, g) | |
27 | + m2.dsa_set_pub(dsa, pub) | |
28 | + return DSA_pub(dsa, 1) | |
29 | + | |
30 | ||
31 | def load_pub_key(file, callback=util.passphrase_callback): | |
32 | """ | |
33 | diff -ur M2Crypto-0.22.3/M2Crypto/EC.py M2Crypto-0.22.3.new/M2Crypto/EC.py | |
34 | --- M2Crypto-0.22.3/M2Crypto/EC.py 2014-01-22 14:37:01.000000000 -0500 | |
35 | +++ M2Crypto-0.22.3.new/M2Crypto/EC.py 2016-01-12 19:25:07.000000000 -0500 | |
36 | @@ -254,6 +254,13 @@ | |
37 | self.der = m2.ec_key_get_public_der(self.ec) | |
38 | return self.der | |
39 | ||
40 | + def get_key(self): | |
41 | + """ | |
42 | + Returns the public key as a byte string. | |
43 | + """ | |
44 | + assert self.check_key(), 'key is not initialised' | |
45 | + return m2.ec_key_get_public_key(self.ec) | |
46 | + | |
47 | save_key = EC.save_pub_key | |
48 | ||
49 | save_key_bio = EC.save_pub_key_bio | |
50 | @@ -333,3 +340,9 @@ | |
51 | Create EC_pub from DER. | |
52 | """ | |
53 | return EC_pub(m2.ec_key_from_pubkey_der(der), 1) | |
54 | + | |
55 | +def pub_key_from_params(curve, bytes): | |
56 | + """ | |
57 | + Create EC_pub from curve name and octet string. | |
58 | + """ | |
59 | + return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1) | |
60 | diff -ur M2Crypto-0.22.3/M2Crypto/EVP.py M2Crypto-0.22.3.new/M2Crypto/EVP.py | |
61 | --- M2Crypto-0.22.3/M2Crypto/EVP.py 2014-01-22 14:37:01.000000000 -0500 | |
62 | +++ M2Crypto-0.22.3.new/M2Crypto/EVP.py 2016-01-12 21:11:36.000000000 -0500 | |
63 | @@ -40,8 +40,13 @@ | |
64 | def __init__(self, algo): | |
65 | md = getattr(m2, algo, None) | |
66 | if md is None: | |
67 | - raise ValueError, ('unknown algorithm', algo) | |
68 | - self.md=md() | |
69 | + # if the digest algorithm isn't found as an attribute of the m2 | |
70 | + # module, try to look up the digest using get_digestbyname() | |
71 | + self.md = m2.get_digestbyname(algo) | |
72 | + if self.md is None: | |
73 | + raise ValueError('unknown algorithm', algo) | |
74 | + else: | |
75 | + self.md = md() | |
76 | self.ctx=m2.md_ctx_new() | |
77 | m2.digest_init(self.ctx, self.md) | |
78 | ||
79 | @@ -389,6 +394,25 @@ | |
80 | raise EVPError(Err.get_error()) | |
81 | return PKey(cptr, 1) | |
82 | ||
83 | +def load_key_bio_pubkey(bio, callback=util.passphrase_callback): | |
84 | + """ | |
85 | + Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. | |
86 | + | |
87 | + @type bio: M2Crypto.BIO | |
88 | + @param bio: M2Crypto.BIO object containing the key in PEM format. | |
89 | + | |
90 | + @type callback: Python callable | |
91 | + @param callback: A Python callable object that is invoked | |
92 | + to acquire a passphrase with which to protect the key. | |
93 | + | |
94 | + @rtype: M2Crypto.EVP.PKey | |
95 | + @return: M2Crypto.EVP.PKey object. | |
96 | + """ | |
97 | + cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) | |
98 | + if cptr is None: | |
99 | + raise EVPError(Err.get_error()) | |
100 | + return PKey(cptr, 1) | |
101 | + | |
102 | def load_key_string(string, callback=util.passphrase_callback): | |
103 | """ | |
104 | Load an M2Crypto.EVP.PKey from a string. | |
105 | @@ -406,3 +430,19 @@ | |
106 | bio = BIO.MemoryBuffer(string) | |
107 | return load_key_bio( bio, callback) | |
108 | ||
109 | +def load_key_string_pubkey(string, callback=util.passphrase_callback): | |
110 | + """ | |
111 | + Load an M2Crypto.EVP.PKey from a public key as a string. | |
112 | + | |
113 | + @type string: string | |
114 | + @param string: String containing the key in PEM format. | |
115 | + | |
116 | + @type callback: Python callable | |
117 | + @param callback: A Python callable object that is invoked | |
118 | + to acquire a passphrase with which to protect the key. | |
119 | + | |
120 | + @rtype: M2Crypto.EVP.PKey | |
121 | + @return: M2Crypto.EVP.PKey object. | |
122 | + """ | |
123 | + bio = BIO.MemoryBuffer(string) | |
124 | + return load_key_bio_pubkey(bio, callback) | |
125 | diff -ur M2Crypto-0.22.3/SWIG/_dsa.i M2Crypto-0.22.3.new/SWIG/_dsa.i | |
126 | --- M2Crypto-0.22.3/SWIG/_dsa.i 2014-01-22 14:37:01.000000000 -0500 | |
127 | +++ M2Crypto-0.22.3.new/SWIG/_dsa.i 2016-01-12 19:25:07.000000000 -0500 | |
128 | @@ -153,6 +153,25 @@ | |
129 | Py_INCREF(Py_None); | |
130 | return Py_None; | |
131 | } | |
132 | + | |
133 | +PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { | |
134 | + BIGNUM *bn; | |
135 | + const void *vbuf; | |
136 | + int vlen; | |
137 | + | |
138 | + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) | |
139 | + return NULL; | |
140 | + | |
141 | + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { | |
142 | + PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); | |
143 | + return NULL; | |
144 | + } | |
145 | + if (dsa->pub_key) | |
146 | + BN_free(dsa->pub_key); | |
147 | + dsa->pub_key = bn; | |
148 | + Py_INCREF(Py_None); | |
149 | + return Py_None; | |
150 | +} | |
151 | %} | |
152 | ||
153 | %inline %{ | |
154 | diff -ur M2Crypto-0.22.3/SWIG/_ec.i M2Crypto-0.22.3.new/SWIG/_ec.i | |
155 | --- M2Crypto-0.22.3/SWIG/_ec.i 2014-01-22 14:37:01.000000000 -0500 | |
156 | +++ M2Crypto-0.22.3.new/SWIG/_ec.i 2016-01-12 19:25:07.000000000 -0500 | |
157 | @@ -189,6 +189,43 @@ | |
158 | ||
159 | return pyo; | |
160 | } | |
161 | + | |
162 | +PyObject *ec_key_get_public_key(EC_KEY *key) { | |
163 | + | |
164 | + unsigned char *src=NULL; | |
165 | + void *dst=NULL; | |
166 | + int src_len=0; | |
167 | + Py_ssize_t dst_len=0; | |
168 | + PyObject *pyo=NULL; | |
169 | + int ret=0; | |
170 | + | |
171 | + /* Convert to binary */ | |
172 | + src_len = i2o_ECPublicKey(key, &src); | |
173 | + if (src_len < 0) | |
174 | + { | |
175 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
176 | + return NULL; | |
177 | + } | |
178 | + | |
179 | + /* Create a PyBuffer containing a copy of the binary, | |
180 | + * to simplify memory deallocation | |
181 | + */ | |
182 | + pyo = PyBuffer_New( src_len ); | |
183 | + ret = PyObject_AsWriteBuffer( pyo, &dst, &dst_len ); | |
184 | + assert( src_len == dst_len ); | |
185 | + if (ret < 0) | |
186 | + { | |
187 | + Py_DECREF(pyo); | |
188 | + OPENSSL_free(src); | |
189 | + PyErr_SetString(_ec_err, "cannot get write buffer"); | |
190 | + return NULL; | |
191 | + } | |
192 | + memcpy( dst, src, src_len ); | |
193 | + OPENSSL_free(src); | |
194 | + | |
195 | + return pyo; | |
196 | +} | |
197 | + | |
198 | %} | |
199 | ||
200 | %threadallow ec_key_read_pubkey; | |
201 | @@ -404,6 +441,32 @@ | |
202 | return keypair; | |
203 | } | |
204 | ||
205 | +EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { | |
206 | + const void *keypairbuf; | |
207 | + Py_ssize_t keypairbuflen; | |
208 | + const unsigned char *tempBuf; | |
209 | + EC_KEY *keypair; | |
210 | + | |
211 | + if (PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) | |
212 | + { | |
213 | + return NULL; | |
214 | + } | |
215 | + | |
216 | + keypair = ec_key_new_by_curve_name(nid); | |
217 | + if (!keypair) { | |
218 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
219 | + return NULL; | |
220 | + } | |
221 | + | |
222 | + tempBuf = (const unsigned char *)keypairbuf; | |
223 | + if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0) | |
224 | + { | |
225 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
226 | + return NULL; | |
227 | + } | |
228 | + return keypair; | |
229 | +} | |
230 | + | |
231 | ||
232 | // According to [SEC2] the degree of the group is defined as EC key length | |
233 | int ec_key_keylen(EC_KEY *key) { | |
234 | diff -ur M2Crypto-0.22.3/SWIG/_evp.i M2Crypto-0.22.3.new/SWIG/_evp.i | |
235 | --- M2Crypto-0.22.3/SWIG/_evp.i 2014-01-22 14:37:01.000000000 -0500 | |
236 | +++ M2Crypto-0.22.3.new/SWIG/_evp.i 2016-01-12 19:25:07.000000000 -0500 | |
237 | @@ -49,6 +49,9 @@ | |
238 | %rename(digest_init) EVP_DigestInit; | |
239 | extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *); | |
240 | ||
241 | +%rename(get_digestbyname) EVP_get_digestbyname; | |
242 | +extern EVP_MD *EVP_get_digestbyname(const char * name); | |
243 | + | |
244 | %rename(des_ecb) EVP_des_ecb; | |
245 | extern const EVP_CIPHER *EVP_des_ecb(void); | |
246 | %rename(des_ede_ecb) EVP_des_ede; | |
247 | @@ -506,6 +509,17 @@ | |
248 | return pk; | |
249 | } | |
250 | ||
251 | +EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { | |
252 | + EVP_PKEY *pk; | |
253 | + | |
254 | + Py_INCREF(pyfunc); | |
255 | + Py_BEGIN_ALLOW_THREADS | |
256 | + pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); | |
257 | + Py_END_ALLOW_THREADS | |
258 | + Py_DECREF(pyfunc); | |
259 | + return pk; | |
260 | +} | |
261 | + | |
262 | int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { | |
263 | return EVP_PKEY_assign_RSA(pkey, rsa); | |
264 | } | |
265 | diff -ur M2Crypto-0.22.3/tests/test_dsa.py M2Crypto-0.22.3.new/tests/test_dsa.py | |
266 | --- M2Crypto-0.22.3/tests/test_dsa.py 2014-01-22 14:37:01.000000000 -0500 | |
267 | +++ M2Crypto-0.22.3.new/tests/test_dsa.py 2016-01-12 19:25:07.000000000 -0500 | |
268 | @@ -87,6 +87,19 @@ | |
269 | r,s = dsa2.sign(self.data) | |
270 | assert dsa2.verify(self.data, r, s) | |
271 | ||
272 | + def test_pub_key_from_params(self): | |
273 | + dsa = DSA.gen_params(1024, self.callback) | |
274 | + dsa.gen_key() | |
275 | + assert len(dsa) == 1024 | |
276 | + p = dsa.p | |
277 | + q = dsa.q | |
278 | + g = dsa.g | |
279 | + pub = dsa.pub | |
280 | + dsa2 = DSA.pub_key_from_params(p,q,g,pub) | |
281 | + assert dsa2.check_key() | |
282 | + r,s = dsa.sign(self.data) | |
283 | + assert dsa2.verify(self.data, r, s) | |
284 | + | |
285 | def suite(): | |
286 | return unittest.makeSuite(DSATestCase) | |
287 | ||
288 | diff -ur M2Crypto-0.22.3/tests/test_ecdsa.py M2Crypto-0.22.3.new/tests/test_ecdsa.py | |
289 | --- M2Crypto-0.22.3/tests/test_ecdsa.py 2014-01-22 14:37:01.000000000 -0500 | |
290 | +++ M2Crypto-0.22.3.new/tests/test_ecdsa.py 2016-01-12 19:25:07.000000000 -0500 | |
291 | @@ -63,6 +63,16 @@ | |
292 | ec = EC.gen_params(EC.NID_sect233k1) | |
293 | assert len(ec) == 233 | |
294 | ||
295 | + def test_pub_key_from_params(self): | |
296 | + curve = EC.NID_X9_62_prime256v1 | |
297 | + ec = EC.gen_params(curve) | |
298 | + ec.gen_key() | |
299 | + ec_pub = ec.pub() | |
300 | + k = ec_pub.get_key() | |
301 | + ec2 = EC.pub_key_from_params(curve, k) | |
302 | + assert ec2.check_key() | |
303 | + r, s = ec.sign_dsa(self.data) | |
304 | + assert ec2.verify_dsa(self.data, r, s) | |
305 | ||
306 | def suite(): | |
307 | return unittest.makeSuite(ECDSATestCase) | |
308 | diff -ur M2Crypto-0.22.3/tests/test_evp.py M2Crypto-0.22.3.new/tests/test_evp.py | |
309 | --- M2Crypto-0.22.3/tests/test_evp.py 2014-01-22 14:37:01.000000000 -0500 | |
310 | +++ M2Crypto-0.22.3.new/tests/test_evp.py 2016-01-12 21:05:53.000000000 -0500 | |
311 | @@ -52,13 +52,25 @@ | |
312 | #A quick but not thorough sanity check | |
313 | assert len(der_blob) == 160 | |
314 | ||
315 | - | |
316 | def test_MessageDigest(self): | |
317 | self.assertRaises(ValueError, EVP.MessageDigest, 'sha513') | |
318 | md = EVP.MessageDigest('sha1') | |
319 | assert md.update('Hello') == 1 | |
320 | assert util.octx_to_num(md.final()) == 1415821221623963719413415453263690387336440359920 | |
321 | ||
322 | + # temporarily remove sha1 from m2 | |
323 | + old_sha1 = m2.sha1 | |
324 | + del m2.sha1 | |
325 | + | |
326 | + # now run the same test again, relying on EVP.MessageDigest() to call | |
327 | + # get_digestbyname() under the hood | |
328 | + md = EVP.MessageDigest('sha1') | |
329 | + self.assertEqual(md.update('Hello'), 1) | |
330 | + self.assertEqual(util.octx_to_num(md.final()), 1415821221623963719413415453263690387336440359920) | |
331 | + | |
332 | + # put sha1 back in place | |
333 | + m2.sha1 = old_sha1 | |
334 | + | |
335 | def test_as_der_capture_key(self): | |
336 | """ | |
337 | Test DER encoding the PKey instance after assigning | |
338 | @@ -92,6 +104,9 @@ | |
339 | ||
340 | self.assertRaises(ValueError, EVP.hmac, 'key', 'data', algo='sha513') | |
341 | ||
342 | + def test_get_digestbyname(self): | |
343 | + self.assertEqual(m2.get_digestbyname('sha513'), None) | |
344 | + self.assertNotEqual(m2.get_digestbyname('sha1'), None) | |
345 | ||
346 | def test_get_rsa(self): | |
347 | """ | |
348 | @@ -117,7 +132,27 @@ | |
349 | ||
350 | rsa3 = RSA.gen_key(1024, 3, callback=self._gen_callback) | |
351 | assert rsa.sign(digest) != rsa3.sign(digest) | |
352 | - | |
353 | + | |
354 | + def test_load_key_string_pubkey(self): | |
355 | + """ | |
356 | + Testing creating a PKey instance from PEM string. | |
357 | + """ | |
358 | + rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) | |
359 | + self.assertIsInstance(rsa, RSA.RSA) | |
360 | + | |
361 | + rsa_pem = BIO.MemoryBuffer() | |
362 | + rsa.save_pub_key_bio(rsa_pem) | |
363 | + pkey = EVP.load_key_string_pubkey(rsa_pem.read()) | |
364 | + rsa2 = pkey.get_rsa() | |
365 | + self.assertIsInstance(rsa2, RSA.RSA_pub) | |
366 | + self.assertEqual(rsa.e, rsa2.e) | |
367 | + self.assertEqual(rsa.n, rsa2.n) | |
368 | + pem = rsa.as_pem(callback=self._pass_callback) | |
369 | + pem2 = rsa2.as_pem() | |
370 | + assert pem | |
371 | + assert pem2 | |
372 | + self.assertNotEqual(pem, pem2) | |
373 | + | |
374 | def test_get_rsa_fail(self): | |
375 | """ | |
376 | Testing trying to retrieve the RSA key from the PKey instance |
0 | diff -uar m2crypto-0.21.1/M2Crypto/DSA.py m2crypto-0.21.1.new/M2Crypto/DSA.py | |
1 | --- m2crypto-0.21.1/M2Crypto/DSA.py 2011-01-15 11:10:05.000000000 -0800 | |
2 | +++ m2crypto-0.21.1.new/M2Crypto/DSA.py 2013-05-16 13:32:43.100275223 -0700 | |
3 | @@ -394,6 +394,29 @@ | |
4 | raise DSAError('problem loading DSA key pair') | |
5 | return DSA(dsa, 1) | |
6 | ||
7 | +def pub_key_from_params(p, q, g, pub): | |
8 | + """ | |
9 | + Factory function that instantiates a DSA_pub object using | |
10 | + the parameters and public key specified. | |
11 | + | |
12 | + @type p: str | |
13 | + @param p: value of p, a "byte string" | |
14 | + @type q: str | |
15 | + @param q: value of q, a "byte string" | |
16 | + @type g: str | |
17 | + @param g: value of g, a "byte string" | |
18 | + @type pub: str | |
19 | + @param pub: value of the public key, a "byte string" | |
20 | + @rtype: DSA_pub | |
21 | + @return: instance of DSA_pub. | |
22 | + """ | |
23 | + dsa = m2.dsa_new() | |
24 | + m2.dsa_set_p(dsa, p) | |
25 | + m2.dsa_set_q(dsa, q) | |
26 | + m2.dsa_set_g(dsa, g) | |
27 | + m2.dsa_set_pub(dsa, pub) | |
28 | + return DSA_pub(dsa, 1) | |
29 | + | |
30 | ||
31 | def load_pub_key(file, callback=util.passphrase_callback): | |
32 | """ | |
33 | diff -uar m2crypto-0.21.1/M2Crypto/EC.py m2crypto-0.21.1.new/M2Crypto/EC.py | |
34 | --- m2crypto-0.21.1/M2Crypto/EC.py 2011-01-15 11:10:05.000000000 -0800 | |
35 | +++ m2crypto-0.21.1.new/M2Crypto/EC.py 2013-05-16 13:32:43.100275223 -0700 | |
36 | @@ -333,3 +333,9 @@ | |
37 | Create EC_pub from DER. | |
38 | """ | |
39 | return EC_pub(m2.ec_key_from_pubkey_der(der), 1) | |
40 | + | |
41 | +def pub_key_from_params(curve, bytes): | |
42 | + """ | |
43 | + Create EC_pub from curve name and octet string. | |
44 | + """ | |
45 | + return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1) | |
46 | diff -uar m2crypto-0.21.1/M2Crypto/EVP.py m2crypto-0.21.1.new/M2Crypto/EVP.py | |
47 | --- m2crypto-0.21.1/M2Crypto/EVP.py 2011-01-15 11:10:05.000000000 -0800 | |
48 | +++ m2crypto-0.21.1.new/M2Crypto/EVP.py 2013-05-16 13:32:43.100275223 -0700 | |
49 | @@ -389,6 +389,25 @@ | |
50 | raise EVPError(Err.get_error()) | |
51 | return PKey(cptr, 1) | |
52 | ||
53 | +def load_key_bio_pubkey(bio, callback=util.passphrase_callback): | |
54 | + """ | |
55 | + Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. | |
56 | + | |
57 | + @type bio: M2Crypto.BIO | |
58 | + @param bio: M2Crypto.BIO object containing the key in PEM format. | |
59 | + | |
60 | + @type callback: Python callable | |
61 | + @param callback: A Python callable object that is invoked | |
62 | + to acquire a passphrase with which to protect the key. | |
63 | + | |
64 | + @rtype: M2Crypto.EVP.PKey | |
65 | + @return: M2Crypto.EVP.PKey object. | |
66 | + """ | |
67 | + cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) | |
68 | + if cptr is None: | |
69 | + raise EVPError(Err.get_error()) | |
70 | + return PKey(cptr, 1) | |
71 | + | |
72 | def load_key_string(string, callback=util.passphrase_callback): | |
73 | """ | |
74 | Load an M2Crypto.EVP.PKey from a string. | |
75 | @@ -406,3 +425,20 @@ | |
76 | bio = BIO.MemoryBuffer(string) | |
77 | return load_key_bio( bio, callback) | |
78 | ||
79 | +def load_key_string_pubkey(string, callback=util.passphrase_callback): | |
80 | + """ | |
81 | + Load an M2Crypto.EVP.PKey from a public key as a string. | |
82 | + | |
83 | + @type string: string | |
84 | + @param string: String containing the key in PEM format. | |
85 | + | |
86 | + @type callback: Python callable | |
87 | + @param callback: A Python callable object that is invoked | |
88 | + to acquire a passphrase with which to protect the key. | |
89 | + | |
90 | + @rtype: M2Crypto.EVP.PKey | |
91 | + @return: M2Crypto.EVP.PKey object. | |
92 | + """ | |
93 | + bio = BIO.MemoryBuffer(string) | |
94 | + return load_key_bio_pubkey( bio, callback) | |
95 | + | |
96 | diff -uar m2crypto-0.21.1/SWIG/_dsa.i m2crypto-0.21.1.new/SWIG/_dsa.i | |
97 | --- m2crypto-0.21.1/SWIG/_dsa.i 2011-01-15 11:10:06.000000000 -0800 | |
98 | +++ m2crypto-0.21.1.new/SWIG/_dsa.i 2013-05-16 13:32:43.100275223 -0700 | |
99 | @@ -153,6 +153,25 @@ | |
100 | Py_INCREF(Py_None); | |
101 | return Py_None; | |
102 | } | |
103 | + | |
104 | +PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { | |
105 | + BIGNUM *bn; | |
106 | + const void *vbuf; | |
107 | + int vlen; | |
108 | + | |
109 | + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) | |
110 | + return NULL; | |
111 | + | |
112 | + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { | |
113 | + PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); | |
114 | + return NULL; | |
115 | + } | |
116 | + if (dsa->pub_key) | |
117 | + BN_free(dsa->pub_key); | |
118 | + dsa->pub_key = bn; | |
119 | + Py_INCREF(Py_None); | |
120 | + return Py_None; | |
121 | +} | |
122 | %} | |
123 | ||
124 | %inline %{ | |
125 | diff -uar m2crypto-0.21.1/SWIG/_ec.i m2crypto-0.21.1.new/SWIG/_ec.i | |
126 | --- m2crypto-0.21.1/SWIG/_ec.i 2011-01-15 11:10:06.000000000 -0800 | |
127 | +++ m2crypto-0.21.1.new/SWIG/_ec.i 2013-05-16 13:32:43.100275223 -0700 | |
128 | @@ -404,6 +404,46 @@ | |
129 | return keypair; | |
130 | } | |
131 | ||
132 | +EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { | |
133 | + const void *pubkeybuf; | |
134 | + Py_ssize_t pubkeybuflen; | |
135 | + const unsigned char *tempBuf; | |
136 | + unsigned char *buf; | |
137 | + EC_KEY *eckey; | |
138 | + EC_KEY *neweckey; | |
139 | + | |
140 | + if (PyObject_AsReadBuffer(pubkey, &pubkeybuf, &pubkeybuflen) == -1) | |
141 | + { | |
142 | + return NULL; | |
143 | + } | |
144 | + | |
145 | + eckey = EC_KEY_new_by_curve_name(nid); | |
146 | + if (!eckey) { | |
147 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
148 | + return NULL; | |
149 | + } | |
150 | + | |
151 | + buf = (unsigned char*)OPENSSL_malloc(pubkeybuflen+1); | |
152 | + if (!buf) { | |
153 | + PyErr_SetString(PyExc_MemoryError, "ec_key_from_pubkey_bytes"); | |
154 | + return NULL; | |
155 | + } | |
156 | + buf[0] = POINT_CONVERSION_UNCOMPRESSED; | |
157 | + memcpy(buf + 1, pubkeybuf, pubkeybuflen); | |
158 | + | |
159 | + tempBuf = (const unsigned char *)buf; | |
160 | + if ((neweckey = o2i_ECPublicKey( &eckey, &tempBuf, pubkeybuflen+1)) == 0) | |
161 | + { | |
162 | + OPENSSL_cleanse(buf, pubkeybuflen+1); | |
163 | + OPENSSL_free(buf); | |
164 | + PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); | |
165 | + return NULL; | |
166 | + } | |
167 | + OPENSSL_cleanse(buf, pubkeybuflen+1); | |
168 | + OPENSSL_free(buf); | |
169 | + return neweckey; | |
170 | +} | |
171 | + | |
172 | ||
173 | // According to [SEC2] the degree of the group is defined as EC key length | |
174 | int ec_key_keylen(EC_KEY *key) { | |
175 | diff -uar m2crypto-0.21.1/SWIG/_evp.i m2crypto-0.21.1.new/SWIG/_evp.i | |
176 | --- m2crypto-0.21.1/SWIG/_evp.i 2011-01-15 11:10:06.000000000 -0800 | |
177 | +++ m2crypto-0.21.1.new/SWIG/_evp.i 2013-05-16 13:32:43.104275275 -0700 | |
178 | @@ -49,6 +49,9 @@ | |
179 | %rename(digest_init) EVP_DigestInit; | |
180 | extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *); | |
181 | ||
182 | +%rename(get_digestbyname) EVP_get_digestbyname; | |
183 | +extern EVP_MD *EVP_get_digestbyname(const char * name); | |
184 | + | |
185 | %rename(des_ecb) EVP_des_ecb; | |
186 | extern const EVP_CIPHER *EVP_des_ecb(void); | |
187 | %rename(des_ede_ecb) EVP_des_ede; | |
188 | @@ -504,6 +507,17 @@ | |
189 | Py_END_ALLOW_THREADS | |
190 | Py_DECREF(pyfunc); | |
191 | return pk; | |
192 | +} | |
193 | + | |
194 | +EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { | |
195 | + EVP_PKEY *pk; | |
196 | + | |
197 | + Py_INCREF(pyfunc); | |
198 | + Py_BEGIN_ALLOW_THREADS | |
199 | + pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); | |
200 | + Py_END_ALLOW_THREADS | |
201 | + Py_DECREF(pyfunc); | |
202 | + return pk; | |
203 | } | |
204 | ||
205 | int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { | |
206 | diff -uar m2crypto-0.21.1/tests/test_dsa.py m2crypto-0.21.1.new/tests/test_dsa.py | |
207 | --- m2crypto-0.21.1/tests/test_dsa.py 2011-01-15 11:10:05.000000000 -0800 | |
208 | +++ m2crypto-0.21.1.new/tests/test_dsa.py 2013-05-16 13:32:43.104275275 -0700 | |
209 | @@ -87,6 +87,19 @@ | |
210 | r,s = dsa2.sign(self.data) | |
211 | assert dsa2.verify(self.data, r, s) | |
212 | ||
213 | + def test_pub_key_from_params(self): | |
214 | + dsa = DSA.gen_params(1024, self.callback) | |
215 | + dsa.gen_key() | |
216 | + assert len(dsa) == 1024 | |
217 | + p = dsa.p | |
218 | + q = dsa.q | |
219 | + g = dsa.g | |
220 | + pub = dsa.pub | |
221 | + dsa2 = DSA.pub_key_from_params(p,q,g,pub) | |
222 | + assert dsa2.check_key() | |
223 | + r,s = dsa.sign(self.data) | |
224 | + assert dsa2.verify(self.data, r, s) | |
225 | + | |
226 | def suite(): | |
227 | return unittest.makeSuite(DSATestCase) | |
228 |
24 | 24 | JQUERY_UI_PATH = __JQUERY_UI_PATH__ |
25 | 25 | JQUERY_UI_CSS_PATH = __JQUERY_UI_CSS_PATH__ |
26 | 26 | RAPHAEL_PATH = __RAPHAEL_PATH__ |
27 | GOST_PATH = __GOST_PATH__ |
27 | 27 | import base64 |
28 | 28 | import struct |
29 | 29 | import hashlib |
30 | ||
31 | from dnsviz.config import GOST_PATH | |
30 | 32 | |
31 | 33 | try: |
32 | 34 | from M2Crypto import EVP, RSA |
43 | 45 | GOST_PREFIX = '\x30\x63\x30\x1c\x06\x06\x2a\x85\x03\x02\x02\x13\x30\x12\x06\x07\x2a\x85\x03\x02\x02\x23\x01\x06\x07\x2a\x85\x03\x02\x02\x1e\x01\x03\x43\x00\x04\x40' |
44 | 46 | GOST_DIGEST_NAME = 'GOST R 34.11-94' |
45 | 47 | |
48 | EC_NOCOMPRESSION = '\x04' | |
49 | ||
46 | 50 | def _check_dsa_support(): |
47 | 51 | try: |
48 | 52 | DSA.pub_key_from_params |
51 | 55 | pass |
52 | 56 | |
53 | 57 | def _check_gost_support(): |
54 | try: | |
55 | _gost_init() | |
58 | if GOST_PATH is not None: | |
56 | 59 | try: |
57 | m2.get_digestbyname(GOST_DIGEST_NAME) | |
58 | except AttributeError: | |
60 | _gost_init() | |
61 | try: | |
62 | md = EVP.MessageDigest(GOST_DIGEST_NAME) | |
63 | except ValueError: | |
64 | pass | |
65 | else: | |
66 | _supported_algs.add(12) | |
67 | _supported_digest_algs.add(3) | |
68 | _gost_cleanup() | |
69 | except Engine.EngineError: | |
59 | 70 | pass |
60 | else: | |
61 | _supported_algs.add(12) | |
62 | _supported_digest_algs.add(3) | |
63 | _gost_cleanup() | |
64 | except Engine.EngineError: | |
65 | pass | |
66 | 71 | |
67 | 72 | def _check_ec_support(): |
68 | 73 | try: |
81 | 86 | return alg in _supported_nsec3_algs |
82 | 87 | |
83 | 88 | def _gost_init(): |
84 | gost = Engine.load_dynamic_engine('gost', '/usr/lib/x86_64-linux-gnu/openssl-1.0.0/engines/libgost.so') | |
89 | gost = Engine.load_dynamic_engine('gost', GOST_PATH) | |
85 | 90 | gost.init() |
86 | 91 | gost.set_default() |
87 | 92 | |
104 | 109 | pass |
105 | 110 | else: |
106 | 111 | _check_gost_support() |
107 | ||
108 | class GostMessageDigest(EVP.MessageDigest): | |
109 | def __init__(self, md): | |
110 | self.md=md | |
111 | self.ctx=m2.md_ctx_new() | |
112 | m2.digest_init(self.ctx, self.md) | |
113 | 112 | |
114 | 113 | try: |
115 | 114 | from M2Crypto import EC |
133 | 132 | elif digest_alg == 3: |
134 | 133 | _gost_init() |
135 | 134 | try: |
136 | mdgost = m2.get_digestbyname(GOST_DIGEST_NAME) | |
137 | md = GostMessageDigest(mdgost) | |
135 | md = EVP.MessageDigest(GOST_DIGEST_NAME) | |
138 | 136 | md.update(dnskey_msg) |
139 | 137 | return md.final() == digest |
140 | 138 | finally: |
230 | 228 | else: |
231 | 229 | raise ValueError('Algorithm not supported') |
232 | 230 | |
233 | return EC.pub_key_from_params(curve, key) | |
231 | return EC.pub_key_from_params(curve, EC_NOCOMPRESSION + key) | |
234 | 232 | |
235 | 233 | def _validate_rrsig_rsa(alg, sig, msg, key): |
236 | 234 | pubkey = _dnskey_to_rsa(key) |
13 | 13 | JQUERY_UI_CSS_PATH = "'http://code.jquery.com/ui/1.11.4/themes/redmond/jquery-ui.css'" |
14 | 14 | JQUERY_PATH = "'http://code.jquery.com/jquery-1.11.3.min.js'" |
15 | 15 | RAPHAEL_PATH = "'http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js'" |
16 | GOST_PATH = "'/usr/lib/x86_64-linux-gnu/openssl-1.0.0/engines/libgost.so'" | |
16 | 17 | |
17 | 18 | def apply_substitutions(filename, install_prefix): |
18 | 19 | assert filename.endswith('.in'), 'Filename supplied for customization must end with \'.in\': %s' % (filename) |
30 | 31 | s = s.replace('__JQUERY_UI_PATH__', JQUERY_UI_PATH) |
31 | 32 | s = s.replace('__JQUERY_UI_CSS_PATH__', JQUERY_UI_CSS_PATH) |
32 | 33 | s = s.replace('__RAPHAEL_PATH__', RAPHAEL_PATH) |
34 | s = s.replace('__GOST_PATH__', GOST_PATH) | |
33 | 35 | out_fh.write(s) |
34 | 36 | in_fh.close() |
35 | 37 | out_fh.close() |