summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Paul Calderone <exarkun@divmod.com>2011-06-12 21:56:13 -0400
committerJean-Paul Calderone <exarkun@divmod.com>2011-06-12 21:56:13 -0400
commit042b66d4834b493ff82c9f2dc16aca09f39c9d8a (patch)
treebe63b6322b0a3a37825acede296483a5f38c47e1
parenteecb19801a9bd04f0993440711fa495eca07408a (diff)
parente81020e6e20988d97f1b7ad0f0d493b40a24dd09 (diff)
downloadpyopenssl-042b66d4834b493ff82c9f2dc16aca09f39c9d8a.tar.gz
Add PKey.check method
-rw-r--r--ChangeLog6
-rw-r--r--OpenSSL/crypto/pkey.c32
-rw-r--r--OpenSSL/test/test_crypto.py38
-rw-r--r--doc/pyOpenSSL.tex6
4 files changed, 82 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b8dea6..dffd05d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2011-06-12 Jean-Paul Calderone <exarkun@twistedmatrix.com>
+ * OpenSSL/crypto/pkey.c: Add the PKey.check method, mostly
+ implemented by Rick Dean, to verify the internal consistency of a
+ PKey instance.
+
+2011-06-12 Jean-Paul Calderone <exarkun@twistedmatrix.com>
+
* OpenSSL/crypto/crypto.c: Fix the sign and verify functions so
they handle data with embedded NULs. Fix by David Brodsky
<lp:~lihalla>.
diff --git a/OpenSSL/crypto/pkey.c b/OpenSSL/crypto/pkey.c
index 0a13aa3..1f78682 100644
--- a/OpenSSL/crypto/pkey.c
+++ b/OpenSSL/crypto/pkey.c
@@ -107,6 +107,37 @@ crypto_PKey_type(crypto_PKeyObj *self, PyObject *args)
return PyLong_FromLong(self->pkey->type);
}
+static char crypto_PKey_check_doc[] = "\n\
+Check the consistency of an RSA private key.\n\
+\n\
+@return: True if key is consistent.\n\
+@raise Error: if the key is inconsistent.\n\
+@raise TypeError: if the key is of a type which cannot be checked.\n\
+ Only RSA keys can currently be checked.\n\
+";
+
+static PyObject *
+crypto_PKey_check(crypto_PKeyObj *self, PyObject *args) {
+ int r;
+
+ if (!PyArg_ParseTuple(args, ":check")) {
+ return NULL;
+ }
+
+ if (self->pkey->type == EVP_PKEY_RSA) {
+ RSA *rsa;
+ rsa = EVP_PKEY_get1_RSA(self->pkey);
+ r = RSA_check_key(rsa);
+ if (r == 1) {
+ return PyBool_FromLong(1L);
+ } else {
+ FAIL();
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "key type unsupported");
+ return NULL;
+ }
+}
/*
* ADD_METHOD(name) expands to a correct PyMethodDef declaration
@@ -120,6 +151,7 @@ static PyMethodDef crypto_PKey_methods[] =
ADD_METHOD(generate_key),
ADD_METHOD(bits),
ADD_METHOD(type),
+ ADD_METHOD(check),
{ NULL, NULL }
};
#undef ADD_METHOD
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index 71da5c3..5cdcefb 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -207,6 +207,7 @@ MbzjS007Oe4qqBnCWaFPSnJX6uLApeTbqAxAeyCql56ULW5x6vDMNC3dwjvS/CEh
11n8RkgFIQA0AhuKSIg3CbuartRsJnWOLwgLTzsrKYL4yRog1RJrtw==
-----END RSA PRIVATE KEY-----
""")
+
encryptedPrivateKeyPEMPassphrase = b("foobar")
# Some PKCS#7 stuff. Generated with the openssl command line:
@@ -250,6 +251,21 @@ vrzEeLDRiiPl92dyyWmu
-----END X509 CRL-----
""")
+
+# A broken RSA private key which can be used to test the error path through
+# PKey.check.
+inconsistentPrivateKeyPEM = b("""-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh
+5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEaAQJBAIqm/bz4NA1H++Vx5Ewx
+OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT
+zIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4
+nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2
+HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNeH+vRWsAYU/gbx+OQB+7VOcBAiEA
+oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w=
+-----END RSA PRIVATE KEY-----
+""")
+
+
class X509ExtTests(TestCase):
"""
Tests for L{OpenSSL.crypto.X509Extension}.
@@ -512,11 +528,13 @@ class PKeyTests(TestCase):
def test_pregeneration(self):
"""
L{PKeyType.bits} and L{PKeyType.type} return C{0} before the key is
+ generated. L{PKeyType.check} raises L{TypeError} before the key is
generated.
"""
key = PKey()
self.assertEqual(key.type(), 0)
self.assertEqual(key.bits(), 0)
+ self.assertRaises(TypeError, key.check)
def test_failedGeneration(self):
@@ -564,6 +582,7 @@ class PKeyTests(TestCase):
key.generate_key(TYPE_RSA, bits)
self.assertEqual(key.type(), TYPE_RSA)
self.assertEqual(key.bits(), bits)
+ self.assertTrue(key.check())
def test_dsaGeneration(self):
@@ -579,6 +598,7 @@ class PKeyTests(TestCase):
key.generate_key(TYPE_DSA, bits)
self.assertEqual(key.type(), TYPE_DSA)
self.assertEqual(key.bits(), bits)
+ self.assertRaises(TypeError, key.check)
def test_regeneration(self):
@@ -593,6 +613,23 @@ class PKeyTests(TestCase):
self.assertEqual(key.bits(), bits)
+ def test_inconsistentKey(self):
+ """
+ L{PKeyType.check} returns C{False} if the key is not consistent.
+ """
+ key = load_privatekey(FILETYPE_PEM, inconsistentPrivateKeyPEM)
+ self.assertRaises(Error, key.check)
+
+
+ def test_check_wrong_args(self):
+ """
+ L{PKeyType.check} raises L{TypeError} if called with any arguments.
+ """
+ self.assertRaises(TypeError, PKey().check, None)
+ self.assertRaises(TypeError, PKey().check, object())
+ self.assertRaises(TypeError, PKey().check, 1)
+
+
class X509NameTests(TestCase):
"""
@@ -2077,6 +2114,7 @@ class FunctionTests(TestCase):
L{dump_privatekey} writes a PEM, DER, and text.
"""
key = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM)
+ self.assertTrue(key.check())
dumped_pem = dump_privatekey(FILETYPE_PEM, key)
self.assertEqual(dumped_pem, cleartextPrivateKeyPEM)
dumped_der = dump_privatekey(FILETYPE_ASN1, key)
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index 4e00c14..6a49748 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -555,6 +555,12 @@ Generate a public/private key pair of the type \var{type} (one of
Return the type of the key.
\end{methoddesc}
+\begin{methoddesc}[PKey]{check}{}
+Check the consistency of this key, returning True if it is consistent and
+raising an exception otherwise. This is only valid for RSA keys. See the
+OpenSSL RSA_check_key man page for further limitations.
+\end{methoddesc}
+
\subsubsection{PKCS7 objects \label{openssl-pkcs7}}
PKCS7 objects have the following methods: