[prev in list] [next in list] [prev in thread] [next in thread]
List: pypy-svn
Subject: [pypy-commit] pypy stdlib-2.7.9: Add password parameter to ctx.load_cert_chain()
From: amauryfa <noreply () buildbot ! pypy ! org>
Date: 2015-01-30 23:45:13
Message-ID: 20150130234513.3D99C1C0FAB () cobra ! cs ! uni-duesseldorf ! de
[Download RAW message or body]
Author: Amaury Forgeot d'Arc <amauryfa@gmail.com>
Branch: stdlib-2.7.9
Changeset: r75593:ee52b4559ba7
Date: 2015-01-31 00:08 +0100
http://bitbucket.org/pypy/pypy/changeset/ee52b4559ba7/
Log: Add password parameter to ctx.load_cert_chain()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1,4 +1,4 @@
-from rpython.rlib import rpoll, rsocket
+from rpython.rlib import rpoll, rsocket, rthread
from rpython.rlib.rarithmetic import intmask, widen, r_uint
from rpython.rlib.ropenssl import *
from rpython.rlib.rposix import get_errno, set_errno
@@ -999,6 +999,39 @@
libssl_BIO_free(cert)
+# Data structure for the password callbacks
+class PasswordInfo(object):
+ w_callable = None
+ password = None
+ operationerror = None
+PWINFO_STORAGE = {}
+
+def _password_callback(buf, size, rwflag, userdata):
+ index = rffi.cast(lltype.Signed, userdata)
+ pw_info = PWINFO_STORAGE.get(index, None)
+ if not pw_info:
+ return rffi.cast(rffi.INT, -1)
+ space = pw_info.space
+ password = ""
+ if pw_info.w_callable:
+ try:
+ password = pw_info.space.str_w(
+ space.call_function(pw_info.w_callable))
+ except OperationError as e:
+ pw_info.operationerror = e
+ return rffi.cast(rffi.INT, -1)
+ else:
+ password = pw_info.password
+ size = widen(size)
+ if len(password) > size:
+ pw_info.operationerror = oefmt(
+ space.w_ValueError,
+ "password cannot be longer than %d bytes", size)
+ return rffi.cast(rffi.INT, -1)
+ for i, c in enumerate(password):
+ buf[i] = c
+ return rffi.cast(rffi.INT, len(password))
+
class _SSLContext(W_Root):
@staticmethod
@unwrap_spec(protocol=int)
@@ -1101,7 +1134,8 @@
"CERT_OPTIONAL or CERT_REQUIRED")
self.check_hostname = check_hostname
- def load_cert_chain_w(self, space, w_certfile, w_keyfile=None):
+ def load_cert_chain_w(self, space, w_certfile, w_keyfile=None,
+ w_password=None):
if space.is_none(w_certfile):
certfile = None
else:
@@ -1110,33 +1144,63 @@
keyfile = certfile
else:
keyfile = space.str_w(w_keyfile)
+ pw_info = PasswordInfo()
+ pw_info.space = space
+ index = -1
+ if not space.is_none(w_password):
+ index = rthread.get_ident()
+ PWINFO_STORAGE[index] = pw_info
- set_errno(0)
+ if space.is_true(space.callable(w_password)):
+ pw_info.w_callable = w_password
+ else:
+ pw_info.password = space.str_w(w_password)
- ret = libssl_SSL_CTX_use_certificate_chain_file(self.ctx, certfile)
- if ret != 1:
- errno = get_errno()
- if errno:
- libssl_ERR_clear_error()
- raise wrap_oserror(space, OSError(errno, ''),
- exception_name = 'w_IOError')
- else:
+ libssl_SSL_CTX_set_default_passwd_cb(
+ self.ctx, _password_callback)
+ libssl_SSL_CTX_set_default_passwd_cb_userdata(
+ self.ctx, rffi.cast(rffi.VOIDP, index))
+
+
+ try:
+ set_errno(0)
+ ret = libssl_SSL_CTX_use_certificate_chain_file(self.ctx, certfile)
+ if ret != 1:
+ if pw_info.operationerror:
+ libssl_ERR_clear_error()
+ raise pw_info.operationerror
+ errno = get_errno()
+ if errno:
+ libssl_ERR_clear_error()
+ raise wrap_oserror(space, OSError(errno, ''),
+ exception_name = 'w_IOError')
+ else:
+ raise _ssl_seterror(space, None, -1)
+
+ ret = libssl_SSL_CTX_use_PrivateKey_file(self.ctx, keyfile,
+ SSL_FILETYPE_PEM)
+ if ret != 1:
+ if pw_info.operationerror:
+ libssl_ERR_clear_error()
+ raise pw_info.operationerror
+ errno = get_errno()
+ if errno:
+ libssl_ERR_clear_error()
+ raise wrap_oserror(space, OSError(errno, ''),
+ exception_name = 'w_IOError')
+ else:
+ raise _ssl_seterror(space, None, -1)
+
+ ret = libssl_SSL_CTX_check_private_key(self.ctx)
+ if ret != 1:
raise _ssl_seterror(space, None, -1)
-
- ret = libssl_SSL_CTX_use_PrivateKey_file(self.ctx, keyfile,
- SSL_FILETYPE_PEM)
- if ret != 1:
- errno = get_errno()
- if errno:
- libssl_ERR_clear_error()
- raise wrap_oserror(space, OSError(errno, ''),
- exception_name = 'w_IOError')
- else:
- raise _ssl_seterror(space, None, -1)
-
- ret = libssl_SSL_CTX_check_private_key(self.ctx)
- if ret != 1:
- raise _ssl_seterror(space, None, -1)
+ finally:
+ if index >= 0:
+ del PWINFO_STORAGE[index]
+ libssl_SSL_CTX_set_default_passwd_cb(
+ self.ctx, lltype.nullptr(pem_password_cb.TO))
+ libssl_SSL_CTX_set_default_passwd_cb_userdata(
+ self.ctx, None)
@unwrap_spec(filepath=str)
def load_dh_params_w(self, space, filepath):
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -290,6 +290,9 @@
tmpfile = udir / "emptycert.pem"
tmpfile.write(SSL_EMPTYCERT)
cls.w_emptycert = cls.space.wrap(str(tmpfile))
+ tmpfile = udir / "cert.passwd.pem"
+ tmpfile.write(SSL_CERTIFICATE_PROTECTED)
+ cls.w_cert_protected = cls.space.wrap(str(tmpfile))
cls.w_dh512 = cls.space.wrap(os.path.join(
os.path.dirname(__file__), 'dh512.pem'))
@@ -301,6 +304,15 @@
raises(IOError, ctx.load_cert_chain, "inexistent.pem")
raises(_ssl.SSLError, ctx.load_cert_chain, self.badcert)
raises(_ssl.SSLError, ctx.load_cert_chain, self.emptycert)
+ # Password protected key and cert
+ raises(_ssl.SSLError, ctx.load_cert_chain, self.cert_protected,
+ password="badpass")
+ ctx.load_cert_chain(self.cert_protected, password="somepass")
+ ctx.load_cert_chain(self.cert_protected, password=lambda: "somepass")
+ raises(_ssl.SSLError, ctx.load_cert_chain, self.cert_protected,
+ password=lambda: "badpass")
+ raises(TypeError, ctx.load_cert_chain, self.cert_protected,
+ password=lambda: 3)
def test_load_verify_locations(self):
import _ssl
@@ -452,3 +464,38 @@
-----END CERTIFICATE-----
"""
SSL_EMPTYCERT = ""
+SSL_CERTIFICATE_PROTECTED = """
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
+
+kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
+u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
+AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
+Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
+YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
+6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
+noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
+94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
+7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
+cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
+zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
+L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
+2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
+MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
+Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
+YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
+6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
+pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
+FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
+BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
+lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
+CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
+-----END CERTIFICATE-----
+"""
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -261,6 +261,9 @@
ssl_external('SSL_CTX_load_verify_locations', [SSL_CTX, rffi.CCHARP, rffi.CCHARP], rffi.INT)
ssl_external('SSL_CTX_check_private_key', [SSL_CTX], rffi.INT)
ssl_external('SSL_CTX_set_session_id_context', [SSL_CTX, rffi.CCHARP, rffi.UINT], rffi.INT)
+pem_password_cb = lltype.Ptr(lltype.FuncType([rffi.CCHARP, rffi.INT, rffi.INT, rffi.VOIDP], rffi.INT))
+ssl_external('SSL_CTX_set_default_passwd_cb', [SSL_CTX, pem_password_cb], lltype.Void)
+ssl_external('SSL_CTX_set_default_passwd_cb_userdata', [SSL_CTX, rffi.VOIDP], lltype.Void)
SSL_CTX_STATS_NAMES = """
number connect connect_good connect_renegotiate accept accept_good
accept_renegotiate hits misses timeouts cache_full""".split()
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic