components/python/pyopenssl/patches/3_add_if.patch
changeset 1456 b367e3ae9667
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/pyopenssl/patches/3_add_if.patch	Wed Aug 28 13:41:11 2013 -0700
@@ -0,0 +1,316 @@
+#
+# This patch adds a few more interfaces to OpenSSL functions required for IPS.
+# The additional interfaces are:
+#     pyOpenSSL                     -> OpenSSL
+#      crypto.CRL.verify()              X509_CRL_verify()
+#      crypto.CRL.get_issuer()          X509_CRL_get_issuer()
+#      crypto.CRL.get_next_update()     X509_CRL_get_nextUpdate()
+#      crypto.X509.verify()             X509_verify()
+#      crypto.X509.check_ca()           X509_check_ca()
+#
+# The patch also adds test cases to the pyOpenSSL test suite for the added
+# functions.
+#
+--- pyOpenSSL-0.13/OpenSSL/crypto/crl.c	2013-08-26 15:04:14.949389722 -0700
++++ pyOpenSSL-0.13/OpenSSL/crypto/crl.c	2013-08-26 15:05:00.183031221 -0700
+@@ -180,6 +180,84 @@
+     return buffer;
+ }
+ 
++static char crypto_CRL_verify_doc[] = "\n\
++Verifies the CRL using the supplied public key\n\
++\n\
++@param key: a public key\n\
++@type key: L{PKey}\n\
++@return: True if the signature is correct.\n\
++@raise OpenSSL.crypto.Error: If the signature is invalid or there is a\n\
++    problem verifying the signature.\n\
++";
++
++PyObject *
++crypto_CRL_verify(crypto_CRLObj *self, PyObject *args)
++{
++    PyObject *obj;
++    crypto_PKeyObj *key;
++    int answer;
++
++    if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &obj)) {
++        return NULL;
++    }
++
++    key = (crypto_PKeyObj *)obj;
++
++    if ((answer = X509_CRL_verify(self->crl, key->pkey)) <= 0) {
++        exception_from_error_queue(crypto_Error);
++        return NULL;
++    }
++
++    return PyLong_FromLong(answer);
++}
++
++static char crypto_CRL_get_issuer_doc[] = "\n\
++Create an X509Name object for the issuer of the certificate\n\
++\n\
++@return: An X509Name object\n\
++";
++
++static PyObject *
++crypto_CRL_get_issuer(crypto_CRLObj *self, PyObject *args)
++{
++    crypto_X509NameObj *pyname;
++    X509_NAME *name;
++
++    if (!PyArg_ParseTuple(args, ":get_issuer"))
++        return NULL;
++
++    name = X509_CRL_get_issuer(self->crl);
++    pyname = crypto_X509Name_New(name, 0);
++    if (pyname != NULL)
++    {
++        pyname->parent_cert = (PyObject *)self;
++        Py_INCREF(self);
++    }
++    return (PyObject *)pyname;
++}
++
++static char crypto_CRL_get_nextUpdate_doc[] = "\n\
++Retrieve the time stamp for when the CRL gets its next update\n\
++\n\
++@return: A string giving the timestamp, in the format:\n\
++\n\
++                 YYYYMMDDhhmmssZ\n\
++                 YYYYMMDDhhmmss+hhmm\n\
++                 YYYYMMDDhhmmss-hhmm\n\
++           or None if there is no value set.\n\
++";
++
++static PyObject*
++crypto_CRL_get_nextUpdate(crypto_CRLObj *self, PyObject *args)
++{
++	/*
++	 * X509_CRL_get_nextUpdate returns a borrowed reference.
++	 */
++	return _get_asn1_time(
++		":get_nextUpdate", X509_CRL_get_nextUpdate(self->crl), args);
++}
++
++
+ crypto_CRLObj *
+ crypto_CRL_New(X509_CRL *crl) {
+     crypto_CRLObj *self;
+@@ -205,6 +283,9 @@
+     ADD_KW_METHOD(add_revoked),
+     ADD_METHOD(get_revoked),
+     ADD_KW_METHOD(export),
++    ADD_KW_METHOD(verify),
++    ADD_KW_METHOD(get_issuer),
++    ADD_KW_METHOD(get_nextUpdate),
+     { NULL, NULL }
+ };
+ #undef ADD_METHOD
+--- pyOpenSSL-0.13/OpenSSL/crypto/x509.c	2013-08-26 15:04:14.943271276 -0700
++++ pyOpenSSL-0.13/OpenSSL/crypto/x509.c	2013-08-26 15:05:00.183501160 -0700
+@@ -761,6 +761,57 @@
+     return (PyObject*)extobj;
+ }
+ 
++static char crypto_X509_verify_doc[] = "\n\
++Verifies the certificate using the supplied public key\n\
++\n\
++@param key: a public key\n\
++@type key: L{PKey}\n\
++@return: True if the signature is correct.\n\
++@raise OpenSSL.crypto.Error: If the signature is invalid or there is a\n\
++    problem verifying the signature.\n\
++";
++
++PyObject *
++crypto_X509_verify(crypto_X509Obj *self, PyObject *args)
++{
++    PyObject *obj;
++    crypto_PKeyObj *key;
++    int answer;
++
++    if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &obj)) {
++        return NULL;
++    }
++
++    key = (crypto_PKeyObj *)obj;
++
++    if ((answer = X509_verify(self->x509, key->pkey)) <= 0) {
++        exception_from_error_queue(crypto_Error);
++        return NULL;
++    }
++
++    return PyLong_FromLong(answer);
++}
++
++
++static char crypto_X509_check_ca_doc[] = "\n\
++Checks if the certificate is a CA\n\
++\n\
++@return: 0 if not a CA, >0 if a CA\n\
++";
++
++PyObject *
++crypto_X509_check_ca(crypto_X509Obj *self, PyObject *args)
++{
++    int answer;
++
++    if (!PyArg_ParseTuple(args, ":check_ca"))
++        return NULL;
++
++    answer = X509_check_ca(self->x509);
++
++    return PyLong_FromLong(answer);
++}
++
+ /*
+  * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+  *   {  'name', (PyCFunction)crypto_X509_name, METH_VARARGS }
+@@ -794,6 +845,8 @@
+     ADD_METHOD(add_extensions),
+     ADD_METHOD(get_extension),
+     ADD_METHOD(get_extension_count),
++    ADD_METHOD(verify),
++    ADD_METHOD(check_ca),
+     { NULL, NULL }
+ };
+ #undef ADD_METHOD
+--- pyOpenSSL-0.13/OpenSSL/test/test_crypto.py	2013-08-26 15:04:14.951459483 -0700
++++ pyOpenSSL-0.13/OpenSSL/test/test_crypto.py	2013-08-26 15:14:40.335995703 -0700
+@@ -1090,6 +1090,18 @@
+ WpOdIpB8KksUTCzV591Nr1wd
+ -----END CERTIFICATE-----
+     """
++    def setUp(self):
++        # create new CA
++        self.ca_key = PKey()
++        self.ca_key.generate_key(TYPE_RSA, 384)
++     
++        self.ca = X509()
++        self.ca.get_subject().commonName = "Yoda root CA"
++        self.ca.set_issuer(self.ca.get_subject())
++        self.ca.set_pubkey(self.ca_key)
++        self.ca.sign(self.ca_key, "sha1")
++
++
+     def signable(self):
+         """
+         Create and return a new L{X509}.
+@@ -1620,6 +1632,51 @@
+         self.assertRaises(ValueError, cert.get_signature_algorithm)
+ 
+ 
++    def test_key_verify(self):
++        """
++        L{X509.verify} succeeds when passed a valid CA key, raises
++        L{OpenSSL.crypto.Error} otherwise.
++        """
++        key = PKey()
++        key.generate_key(TYPE_RSA, 384)
++        req = X509Req()
++        req.get_subject().commonName = "Master Luke"
++        req.set_pubkey(key)
++        req.sign(key, "sha1")
++        cert = X509()
++        cert.set_subject(req.get_subject())
++        cert.set_pubkey(key)
++        cert.set_issuer(self.ca.get_subject())
++        cert.sign(self.ca_key, "sha1")
++
++        self.assertTrue(cert.verify(self.ca_key))
++        self.assertRaises(Error, cert.verify, key)
++
++
++    def test_is_ca(self):
++        """
++        L{X509.check_ca} returns a value >0 if certificate is a CA, returns 0 
++        if not.
++        """
++        res = self.ca.check_ca()
++        self.assertTrue(res > 0)
++
++        # Try with a non-ca cert
++        key = PKey()
++        key.generate_key(TYPE_RSA, 384)
++        req = X509Req()
++        req.get_subject().commonName = "Master Luke"
++        req.set_pubkey(key)
++        req.sign(key, "sha1")
++        cert = X509()
++        cert.set_subject(req.get_subject())
++        cert.set_pubkey(key)
++        cert.set_issuer(self.ca.get_subject())
++        cert.sign(self.ca_key, "sha1")
++        res = cert.check_ca()
++        self.assertEqual(res, 0)
++
++
+ 
+ class PKCS12Tests(TestCase):
+     """
+@@ -2521,6 +2578,18 @@
+     cert = load_certificate(FILETYPE_PEM, cleartextCertificatePEM)
+     pkey = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM)
+ 
++    def setUp(self):
++        # create new CA
++        self.ca_key = PKey()
++        self.ca_key.generate_key(TYPE_RSA, 384)
++     
++        self.ca = X509()
++        self.ca.get_subject().commonName = "Yoda root CA"
++        self.ca.set_issuer(self.ca.get_subject())
++        self.ca.set_pubkey(self.ca_key)
++        self.ca.sign(self.ca_key, "sha1")
++
++
+     def test_construction(self):
+         """
+         Confirm we can create L{OpenSSL.crypto.CRL}.  Check
+@@ -2712,6 +2781,44 @@
+         self.assertRaises(Error, load_crl, FILETYPE_PEM, "hello, world")
+ 
+ 
++    def test_crl_verify(self):
++        """
++        Test that L{OpenSSL.CRL.verify} correctly verifies CRL with the
++        pubkey of the issuing CA, raises L{OpenSSL.crypto.Error} in case of
++        bogus key.
++        """
++        s = CRL().export(self.ca, self.ca_key)
++        crl = load_crl(FILETYPE_PEM, s)
++        res = crl.verify(self.ca_key)
++        self.assertTrue(res)
++
++        boguskey = PKey()
++        boguskey.generate_key(TYPE_RSA, 384)
++        self.assertRaises(Error, crl.verify, boguskey)
++
++
++    def test_crl_get_issuer(self):
++        """
++        Test that L{OpenSSL.CRL.get_issuer} returns a L{OpenSSL.X509Name} object
++        with the correct issuer information.
++         """
++        s = CRL().export(self.ca, self.ca_key)
++        crl = load_crl(FILETYPE_PEM, s)
++        issuer = crl.get_issuer()
++        self.assertTrue(isinstance(issuer, X509Name))
++        self.assertTrue(issuer.commonName == self.ca.get_subject().commonName)
++
++
++    def test_crl_get_nextUpdate(self):
++        """
++        Test that L{OpenSSL.CRL.get_nextUpdate} returns the correct date and
++        time of next update.
++         """
++        crl = load_crl(FILETYPE_PEM, crlData)
++        self.assertEqual(crl.get_nextUpdate(), "20120927024152Z")
++
++
++
+ class SignVerifyTests(TestCase):
+     """
+     Tests for L{OpenSSL.crypto.sign} and L{OpenSSL.crypto.verify}.