diff --git a/SOURCES/00055-systemtap.patch b/SOURCES/00055-systemtap.patch index 0ab03874..67ec005d 100644 --- a/SOURCES/00055-systemtap.patch +++ b/SOURCES/00055-systemtap.patch @@ -1,822 +1,198 @@ -diff -up Python-3.3.0rc2/configure.ac.systemtap Python-3.3.0rc2/configure.ac ---- Python-3.3.0rc2/configure.ac.systemtap 2012-09-09 05:11:14.000000000 -0400 -+++ Python-3.3.0rc2/configure.ac 2012-09-10 09:17:21.114511781 -0400 -@@ -2678,6 +2678,23 @@ if test "$with_valgrind" != no; then - OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" +diff -up Python-2.7rc1/configure.ac.systemtap Python-2.7rc1/configure.ac +--- Python-2.7rc1/configure.ac.systemtap 2010-06-06 10:53:15.514975012 -0400 ++++ Python-2.7rc1/configure.ac 2010-06-06 10:53:15.520974361 -0400 +@@ -2616,6 +2616,38 @@ if test "$with_valgrind" != no; then + ) fi -+# Check for systemtap support -+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap -+AC_MSG_CHECKING([for --with-systemtap]) -+AC_ARG_WITH([systemtap], -+ AC_HELP_STRING([--with(out)-systemtap], [disable/enable SystemTap support]),, -+ with_systemtap=no) -+AC_MSG_RESULT([$with_systemtap]) -+if test "$with_systemtap" != no; then -+ AC_DEFINE(WITH_SYSTEMTAP, 1, -+ [Define if you want to compile in SystemTap support]) -+ SYSTEMTAPOBJS="Python/pysystemtap.o" -+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h" -+fi -+ -+AC_SUBST(SYSTEMTAPOBJS) -+AC_SUBST(SYSTEMTAPDEPS) -+ - # -I${DLINCLDIR} is added to the compile rule for importdl.o - AC_SUBST(DLINCLDIR) - DLINCLDIR=. -diff -up Python-3.3.0rc2/configure.systemtap Python-3.3.0rc2/configure ---- Python-3.3.0rc2/configure.systemtap 2012-09-09 05:11:14.000000000 -0400 -+++ Python-3.3.0rc2/configure 2012-09-10 09:17:21.116511780 -0400 -@@ -618,6 +618,8 @@ TRUE - MACHDEP_OBJS - DYNLOADFILE - DLINCLDIR -+SYSTEMTAPDEPS -+SYSTEMTAPOBJS - THREADOBJ - LDLAST - USE_THREAD_MODULE -@@ -779,6 +781,7 @@ with_doc_strings - with_tsc - with_pymalloc - with_valgrind -+with_systemtap - with_fpectl - with_libm - with_libc -@@ -1456,6 +1459,7 @@ Optional Packages: - --with(out)-tsc enable/disable timestamp counter profile - --with(out)-pymalloc disable/enable specialized mallocs - --with-valgrind Enable Valgrind support -+ --with(out)-systemtap disable/enable SystemTap support - --with-fpectl enable SIGFPE catching - --with-libm=STRING math library - --with-libc=STRING C library -@@ -10065,6 +10069,31 @@ fi - OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" - fi - -+# Check for systemtap support -+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-systemtap" >&5 -+$as_echo_n "checking for --with-systemtap... " >&6; } -+ -+# Check whether --with-systemtap was given. -+if test "${with_systemtap+set}" = set; then : -+ withval=$with_systemtap; ++# Check for dtrace support ++AC_MSG_CHECKING(for --with-dtrace) ++AC_ARG_WITH(dtrace, ++ AC_HELP_STRING(--with(out)-dtrace, disable/enable dtrace support)) ++ ++if test ! -z "$with_dtrace" ++then ++ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null ++ then ++ AC_DEFINE(WITH_DTRACE, 1, ++ [Define if you want to compile in Dtrace support]) ++ with_dtrace="Sun" ++ DTRACEOBJS="Python/dtrace.o" ++ DTRADEHDRS="" ++ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d ++ then ++ AC_DEFINE(WITH_DTRACE, 1, ++ [Define if you want to compile in Dtrace support]) ++ with_dtrace="Apple" ++ DTRACEOBJS="" ++ DTRADEHDRS="pydtrace.h" ++ else ++ with_dtrace="no" ++ fi +else -+ with_systemtap=no -+fi -+ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_systemtap" >&5 -+$as_echo "$with_systemtap" >&6; } -+if test "$with_systemtap" != no; then -+ -+$as_echo "#define WITH_SYSTEMTAP 1" >>confdefs.h -+ -+ SYSTEMTAPOBJS="Python/pysystemtap.o" -+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h" ++ with_dtrace="no" +fi + ++AC_MSG_RESULT($with_dtrace) ++AC_SUBST(DTRACEOBJS) ++AC_SUBST(DTRACEHDRS) ++ + # Check for --with-wctype-functions + AC_MSG_CHECKING(for --with-wctype-functions) + AC_ARG_WITH(wctype-functions, +diff -up Python-2.7rc1/Include/pydtrace.d.systemtap Python-2.7rc1/Include/pydtrace.d +--- Python-2.7rc1/Include/pydtrace.d.systemtap 2010-06-06 10:53:15.520974361 -0400 ++++ Python-2.7rc1/Include/pydtrace.d 2010-06-06 10:53:15.520974361 -0400 +@@ -0,0 +1,10 @@ ++provider python { ++ probe function__entry(const char *, const char *, int); ++ probe function__return(const char *, const char *, int); ++}; + -+ -+ - # -I${DLINCLDIR} is added to the compile rule for importdl.o - - DLINCLDIR=. -diff -up Python-3.3.0rc2/Doc/howto/index.rst.systemtap Python-3.3.0rc2/Doc/howto/index.rst ---- Python-3.3.0rc2/Doc/howto/index.rst.systemtap 2012-09-09 05:10:51.000000000 -0400 -+++ Python-3.3.0rc2/Doc/howto/index.rst 2012-09-10 09:17:21.117511779 -0400 -@@ -29,4 +29,5 @@ Currently, the HOWTOs are: - argparse.rst - ipaddress.rst - clinic.rst -+ instrumentation.rst - -diff -up Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap Python-3.3.0rc2/Doc/howto/instrumentation.rst ---- Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap 2012-09-10 09:17:21.117511779 -0400 -+++ Python-3.3.0rc2/Doc/howto/instrumentation.rst 2012-09-10 09:17:21.117511779 -0400 -@@ -0,0 +1,295 @@ -+.. _instrumentation: -+ -+==================================== -+Instrumenting CPython with SystemTap -+==================================== -+ -+:author: David Malcolm -+ -+DTrace and SystemTap are monitoring tools, each providing a way to inspect -+what the processes on a computer system are doing. They both use -+domain-specific languages allowing a user to write scripts which: -+ -+ - filter which processes are to be observed -+ - gather data from the processes of interest -+ - generate reports on the data -+ -+As of Python 3.3, CPython can be built with embedded "markers" that can be -+observed by a SystemTap script, making it easier to monitor what the CPython -+processes on a system are doing. -+ -+.. Potentially this document could be expanded to also cover DTrace markers. -+ However, I'm not a DTrace expert. -+ -+.. I'm using ".. code-block:: c" for SystemTap scripts, as "c" is syntactically -+ the closest match that Sphinx supports -+ -+ -+Enabling the static markers -+--------------------------- -+ -+In order to build CPython with the embedded markers for SystemTap, the -+SystemTap development tools must be installed. -+ -+On a Fedora or Red Hat Enterprise Linux machine, this can be done via:: -+ -+ yum install systemtap-sdt-devel -+ -+CPython must then be configured `--with-systemtap`:: -+ -+ checking for --with-systemtap... yes -+ -+You can verify if the SystemTap static markers are present in the built -+binary by seeing if it contains a ".note.stapsdt" section. -+ -+.. code-block:: bash -+ -+ $ eu-readelf -S ./python | grep .note.stapsdt -+ [29] .note.stapsdt NOTE 0000000000000000 00308d78 000000b8 0 0 0 4 -+ -+If you've built python as a shared library (with --enable-shared), you need -+to look instead within the shared library. For example: -+ -+.. code-block:: bash -+ -+ $ eu-readelf -S libpython3.3dm.so.1.0 | grep .note.stapsdt -+ [28] .note.stapsdt NOTE 0000000000000000 00365b68 000000b8 0 0 0 4 -+ -+Earlier versions of SystemTap stored the markers in a ".probes" section. -+ -+For the curious, you can see the metadata for the static markers using this -+invocation. -+ -+.. code-block:: bash -+ -+ $ eu-readelf -x .note.stapsdt ./python -+ -+ Hex dump of section [29] '.note.stapsdt', 184 bytes at offset 0x308d78: -+ 0x00000000 08000000 45000000 03000000 73746170 ....E.......stap -+ 0x00000010 73647400 d4664b00 00000000 4fc36600 sdt..fK.....O.f. -+ 0x00000020 00000000 488d9000 00000000 70797468 ....H.......pyth -+ 0x00000030 6f6e0066 756e6374 696f6e5f 5f656e74 on.function__ent -+ 0x00000040 72790038 40257261 78203840 25726478 ry.8@%rax 8@%rdx -+ 0x00000050 202d3440 25656378 00000000 08000000 -4@%ecx........ -+ 0x00000060 46000000 03000000 73746170 73647400 F.......stapsdt. -+ 0x00000070 0d674b00 00000000 4fc36600 00000000 .gK.....O.f..... -+ 0x00000080 4a8d9000 00000000 70797468 6f6e0066 J.......python.f -+ 0x00000090 756e6374 696f6e5f 5f726574 75726e00 unction__return. -+ 0x000000a0 38402572 61782038 40257264 78202d34 8@%rax 8@%rdx -4 -+ 0x000000b0 40256563 78000000 @%ecx... -+ -+and a sufficiently modern eu-readelf can print the metadata: -+ -+.. code-block:: bash -+ -+ $ eu-readelf -n ./python -+ -+ Note section [ 1] '.note.gnu.build-id' of 36 bytes at offset 0x190: -+ Owner Data size Type -+ GNU 20 GNU_BUILD_ID -+ Build ID: a28f8db1b224530b0d38ad7b82a249cf7c3f18d6 -+ -+ Note section [27] '.note.stapsdt' of 184 bytes at offset 0x1ae884: -+ Owner Data size Type -+ stapsdt 70 Version: 3 -+ PC: 0xe0d3a, Base: 0x14b150, Semaphore: 0x3ae882 -+ Provider: python, Name: function__return, Args: '8@%rbx 8@%r13 -4@%eax' -+ stapsdt 69 Version: 3 -+ PC: 0xe0f37, Base: 0x14b150, Semaphore: 0x3ae880 -+ Provider: python, Name: function__entry, Args: '8@%rbx 8@%r13 -4@%eax' -+ -+The above metadata contains information for SystemTap describing how it can -+patch strategically-placed machine code instructions to enable the tracing -+hooks used by a SystemTap script. -+ -+ -+Static markers -+-------------- -+ -+The low-level way to use the SystemTap integration is to use the static -+markers directly. This requires you to explicitly state the binary file -+containing them. -+ -+For example, this script can be used to show the call/return hierarchy of a -+Python script: -+ -+.. code-block:: c -+ -+ probe process('python').mark("function__entry") { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ -+ printf("%s => %s in %s:%d\\n", -+ thread_indent(1), funcname, filename, lineno); -+ } -+ -+ probe process('python').mark("function__return") { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ -+ printf("%s <= %s in %s:%d\\n", -+ thread_indent(-1), funcname, filename, lineno); -+ } -+ -+It can be invoked like this: -+ -+.. code-block:: bash -+ -+ $ stap \ -+ show-call-hierarchy.stp \ -+ -c ./python test.py -+ -+The output looks like this:: -+ -+ 11408 python(8274): => __contains__ in Lib/_abcoll.py:362 -+ 11414 python(8274): => __getitem__ in Lib/os.py:425 -+ 11418 python(8274): => encode in Lib/os.py:490 -+ 11424 python(8274): <= encode in Lib/os.py:493 -+ 11428 python(8274): <= __getitem__ in Lib/os.py:426 -+ 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366 -+ -+where the columns are: -+ -+ - time in microseconds since start of script -+ -+ - name of executable -+ -+ - PID of process -+ -+and the remainder indicates the call/return hierarchy as the script executes. -+ -+For a `--enable-shared` build of CPython, the markers are contained within the -+libpython shared library, and the probe's dotted path needs to reflect this. For -+example, this line from the above example:: -+ -+ probe process('python').mark("function__entry") { -+ -+should instead read:: -+ -+ probe process('python').library("libpython3.3dm.so.1.0").mark("function__entry") { -+ -+(assuming a debug build of CPython 3.3) -+ -+.. I'm reusing the "c:function" type for markers -+ -+.. c:function:: function__entry(str filename, str funcname, int lineno) -+ -+ This marker indicates that execution of a Python function has begun. It is -+ only triggered for pure-python (bytecode) functions. -+ -+ The filename, function name, and line number are provided back to the -+ tracing script as positional arguments, which must be accessed using -+ `$arg1`, `$arg2`: -+ -+ * `$arg1` : `(const char *)` filename, accessible using `user_string($arg1)` -+ -+ * `$arg2` : `(const char *)` function name, accessible using -+ `user_string($arg2)` -+ -+ * `$arg3` : `int` line number -+ -+ * `$arg4` : `(PyFrameObject *)`, the frame being executed -+ -+.. c:function:: function__return(str filename, str funcname, int lineno) -+ -+ This marker is the converse of `function__entry`, and indicates that -+ execution of a Python function has ended (either via ``return``, or via an -+ exception). It is only triggered for pure-python (bytecode) functions. -+ -+ The arguments are the same as for `function__entry` -+ -+ -+Tapsets -+------- -+ -+The higher-level way to use the SystemTap integration is to use a "tapset": -+SystemTap's equivalent of a library, which hides some of the lower-level -+details of the static markers. -+ -+Here is a tapset file, based on a non-shared build of CPython: -+ -+.. code-block:: c -+ -+ /* -+ Provide a higher-level wrapping around the function__entry and -+ function__return markers: -+ */ -+ probe python.function.entry = process("python").mark("function__entry") -+ { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ frameptr = $arg4 -+ } -+ probe python.function.return = process("python").mark("function__return") -+ { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ frameptr = $arg4 -+ } -+ -+If this file is installed in SystemTap's tapset directory (e.g. -+`/usr/share/systemtap/tapset`), then these additional probepoints become -+available: -+ -+.. c:function:: python.function.entry(str filename, str funcname, int lineno, frameptr) -+ -+ This probe point indicates that execution of a Python function has begun. -+ It is only triggered for pure-python (bytecode) functions. -+ -+.. c:function:: python.function.return(str filename, str funcname, int lineno, frameptr) -+ -+ This probe point is the converse of `python.function.return`, and indicates -+ that execution of a Python function has ended (either via ``return``, or -+ via an exception). It is only triggered for pure-python (bytecode) functions. -+ -+ -+Examples -+-------- -+This SystemTap script uses the tapset above to more cleanly implement the -+example given above of tracing the Python function-call hierarchy, without -+needing to directly name the static markers: -+ -+.. code-block:: c -+ -+ probe python.function.entry -+ { -+ printf("%s => %s in %s:%d\n", -+ thread_indent(1), funcname, filename, lineno); -+ } -+ -+ probe python.function.return -+ { -+ printf("%s <= %s in %s:%d\n", -+ thread_indent(-1), funcname, filename, lineno); -+ } -+ -+ -+The following script uses the tapset above to provide a top-like view of all -+running CPython code, showing the top 20 most frequently-entered bytecode -+frames, each second, across the whole system: -+ -+.. code-block:: c -+ -+ global fn_calls; -+ -+ probe python.function.entry -+ { -+ fn_calls[pid(), filename, funcname, lineno] += 1; -+ } -+ -+ probe timer.ms(1000) { -+ printf("\033[2J\033[1;1H") /* clear screen */ -+ printf("%6s %80s %6s %30s %6s\n", -+ "PID", "FILENAME", "LINE", "FUNCTION", "CALLS") -+ foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) { -+ printf("%6d %80s %6d %30s %6d\n", -+ pid, filename, lineno, funcname, -+ fn_calls[pid, filename, funcname, lineno]); -+ } -+ delete fn_calls; -+ } -+ -diff -up Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap Python-3.3.0rc2/Lib/test/test_systemtap.py ---- Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap 2012-09-10 09:17:21.117511779 -0400 -+++ Python-3.3.0rc2/Lib/test/test_systemtap.py 2012-09-10 09:17:21.117511779 -0400 -@@ -0,0 +1,234 @@ -+# Verify that systemtap static probes work -+# -+import subprocess -+import sys -+import sysconfig -+import os -+import unittest -+ -+from test.support import run_unittest, TESTFN, unlink -+ -+if '--with-systemtap' not in sysconfig.get_config_var('CONFIG_ARGS'): -+ raise unittest.SkipTest("Python was not configured --with-systemtap") -+ -+try: -+ _, stap_version = subprocess.Popen(["stap", "-V"], -+ stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE, -+ ).communicate() -+except OSError: -+ # This is what "no stap" looks like. There may, however, be other -+ # errors that manifest this way too. -+ raise unittest.SkipTest("Couldn't find stap on the path") -+ -+def invoke_systemtap_script(script, cmd): -+ # Start a child process, probing with the given systemtap script -+ # (passed as stdin to the "stap" tool) -+ # The script should be a bytes instance -+ # Return (stdout, stderr) pair -+ -+ p = subprocess.Popen(["stap", "-", '-vv', '-c', cmd], -+ stdin=subprocess.PIPE, -+ stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE) -+ out, err = p.communicate(input=script) -+ return out, err -+ -+# Verify that stap can run a simple "hello world"-style script -+# This can fail for various reasons: -+# - missing kernel headers -+# - permissions (a non-root user needs to be in the "stapdev" group) -+TRIVIAL_STAP_SCRIPT = b'probe begin { println("hello world") exit () }' -+ -+out, err = invoke_systemtap_script(TRIVIAL_STAP_SCRIPT, 'true') -+if out != b'hello world\n': -+ raise unittest.SkipTest("Test systemtap script did not run; stderr was: %s" % err) -+ -+# We don't expect stderr to be empty, since we're invoking stap with "-vv": stap -+# will (we hope) generate debugging output on stderr. -+ -+def invoke_python_under_systemtap(script, pythoncode=None, pythonfile=None): -+ # Start a child python process, probing with the given systemtap script -+ # (passed as stdin to the "stap" tool) -+ # The script should be a bytes instance -+ # Return (stdout, stderr) pair -+ -+ if pythonfile: -+ pythoncmd = '%s %s' % (sys.executable, pythonfile) -+ else: -+ pythoncmd = '%s -c %r' % (sys.executable, pythoncode) -+ -+ # The process tree of a stap invocation of a command goes through -+ # something like this: -+ # stap ->fork/exec(staprun; exec stapio ->f/e(-c cmd); exec staprun -r) -+ # and this trip through setuid leads to LD_LIBRARY_PATH being dropped, -+ # which would lead to an --enable-shared build of python failing to be -+ # find its libpython, with an error like: -+ # error while loading shared libraries: libpython3.3dm.so.1.0: cannot -+ # open shared object file: No such file or directory -+ # Hence we need to jump through some hoops to expose LD_LIBRARY_PATH to -+ # the invoked python process: -+ LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '') -+ if LD_LIBRARY_PATH: -+ pythoncmd = 'env LD_LIBRARY_PATH=%s ' % LD_LIBRARY_PATH + pythoncmd -+ -+ return invoke_systemtap_script(script, pythoncmd) -+ -+# When using the static markers, we need to supply the prefix of a systemtap -+# dotted probe point that containing the marker. -+# See http://sourceware.org/systemtap/langref/Probe_points.html -+# -+# We need to determine if this is a shared-library build -+# -+# Note that sysconfig can get this wrong; see: -+# http://bugs.python.org/issue14774 -+# -+if '--enable-shared' in sysconfig.get_config_var('CONFIG_ARGS'): -+ # For a shared-library build, the markers are in library(INSTSONAME): -+ INSTSONAME = sysconfig.get_config_var('INSTSONAME') -+ probe_prefix = 'process("%s").library("%s")' % (sys.executable, INSTSONAME) -+else: -+ # For a non-shared-library build, we can simply use sys.executable: -+ probe_prefix = 'process("%s")' % sys.executable -+ -+# The following script ought to generate lots of lines showing recursive -+# function entry and return, of the form: -+# 11408 python(8274): => __contains__ in Lib/_abcoll.py:362 -+# 11414 python(8274): => __getitem__ in Lib/os.py:425 -+# 11418 python(8274): => encode in Lib/os.py:490 -+# 11424 python(8274): <= encode in Lib/os.py:493 -+# 11428 python(8274): <= __getitem__ in Lib/os.py:426 -+# 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366 -+# where the column are: -+# - time in microseconds since start of script -+# - name of executable -+# - PID of process -+# and the remainder indicates the call/return hierarchy -+ -+hierarchy_script = (''' -+probe %s.mark("function__entry") { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ -+ printf("%%s => %%s in %%s:%%d\\n", thread_indent(1), funcname, filename, lineno); -+} -+ -+probe %s.mark("function__return") { -+ filename = user_string($arg1); -+ funcname = user_string($arg2); -+ lineno = $arg3; -+ -+ printf("%%s <= %%s in %%s:%%d\\n", thread_indent(-1), funcname, filename, lineno); -+} -+''' % (probe_prefix, probe_prefix)).encode('utf-8') -+ -+ -+class ErrorDumper: -+ # A context manager that dumps extra information if an exception is raised, -+ # to help track down why the problem occurred -+ def __init__(self, out, err): -+ self.out = out -+ self.err = err -+ -+ def __enter__(self): -+ pass -+ -+ def __exit__(self, type_, value, traceback): -+ if type_: -+ # an exception is being raised: -+ print('stdout: %s' % out.decode()) -+ print('stderr: %s' % err.decode()) -+ -+class SystemtapTests(unittest.TestCase): -+ -+ def test_invoking_python(self): -+ # Ensure that we can invoke python under stap, with a trivial stap -+ # script: -+ out, err = invoke_python_under_systemtap( -+ b'probe begin { println("hello from stap") exit () }', -+ pythoncode="print('hello from python')") -+ with ErrorDumper(out, err): -+ self.assertIn(b'hello from stap', out) -+ self.assertIn(b'hello from python', out) -+ -+ def test_function_entry(self): -+ # Ensure that the function_entry static marker works -+ out, err = invoke_python_under_systemtap(hierarchy_script) -+ # stdout ought to contain various lines showing recursive function -+ # entry and return (see above) -+ -+ # Uncomment this for debugging purposes: -+ # print(out.decode('utf-8')) -+ -+ # Executing the cmdline-supplied "pass": -+ # 0 python(8274): => in :1 -+ # 5 python(8274): <= in :1 -+ with ErrorDumper(out, err): -+ self.assertIn(b'=> in :1', out, -+ msg="stdout: %s\nstderr: %s\n" % (out, err)) -+ -+ def test_function_encoding(self): -+ # Ensure that function names containing non-Latin 1 code -+ # points are handled: -+ pythonfile = TESTFN -+ try: -+ unlink(pythonfile) -+ f = open(pythonfile, "wb") -+ f.write(""" -+# Sample script with non-ASCII filename, for use by test_systemtap.py -+# Implicitly UTF-8 -+ -+def 文字化け(): -+ '''Function with non-ASCII identifier; I believe this reads "mojibake"''' -+ print("hello world!") -+ -+文字化け() -+""".encode('utf-8')) -+ f.close() -+ -+ out, err = invoke_python_under_systemtap(hierarchy_script, -+ pythonfile=pythonfile) -+ out_utf8 = out.decode('utf-8') -+ with ErrorDumper(out, err): -+ self.assertIn('=> in %s:5' % pythonfile, out_utf8) -+ self.assertIn(' => 文字化け in %s:5' % pythonfile, out_utf8) -+ self.assertIn(' <= 文字化け in %s:7' % pythonfile, out_utf8) -+ self.assertIn('<= in %s:9' % pythonfile, out_utf8) -+ finally: -+ unlink(pythonfile) -+ -+ @unittest.skipIf(sys.getfilesystemencoding() == 'ascii', -+ 'the test filename is not encodable with ASCII') -+ def test_filename_encoding(self): -+ # Ensure that scripts names containing non-Latin 1 code -+ # points are handled: -+ pythonfile = TESTFN + '_☠.py' -+ try: -+ unlink(pythonfile) -+ f = open(pythonfile, "wb") -+ f.write(""" -+def foo(): -+ '''Function with non-ASCII identifier; I believe this reads "mojibake"''' -+ print("hello world!") -+ -+foo() -+""".encode('utf-8')) -+ f.close() -+ -+ out, err = invoke_python_under_systemtap(hierarchy_script, -+ pythonfile=pythonfile) -+ out_utf8 = out.decode('utf-8') -+ with ErrorDumper(out, err): -+ self.assertIn('=> in %s:2' % pythonfile, out_utf8) -+ self.assertIn(' => foo in %s:2' % pythonfile, out_utf8) -+ self.assertIn(' <= foo in %s:4' % pythonfile, out_utf8) -+ self.assertIn('<= in %s:6' % pythonfile, out_utf8) -+ finally: -+ unlink(pythonfile) -+ -+def test_main(): -+ run_unittest(SystemtapTests) -+ -+if __name__ == "__main__": -+ test_main() -diff -up Python-3.3.0rc2/Makefile.pre.in.systemtap Python-3.3.0rc2/Makefile.pre.in ---- Python-3.3.0rc2/Makefile.pre.in.systemtap 2012-09-09 05:11:05.000000000 -0400 -+++ Python-3.3.0rc2/Makefile.pre.in 2012-09-10 09:19:51.195501518 -0400 -@@ -363,6 +363,7 @@ PYTHON_OBJS= \ ++#pragma D attributes Evolving/Evolving/Common provider python provider ++#pragma D attributes Private/Private/Common provider python module ++#pragma D attributes Private/Private/Common provider python function ++#pragma D attributes Evolving/Evolving/Common provider python name ++#pragma D attributes Evolving/Evolving/Common provider python args +diff -up Python-2.7rc1/Makefile.pre.in.systemtap Python-2.7rc1/Makefile.pre.in +--- Python-2.7rc1/Makefile.pre.in.systemtap 2010-06-06 10:53:15.488978775 -0400 ++++ Python-2.7rc1/Makefile.pre.in 2010-06-06 11:05:30.411100568 -0400 +@@ -298,6 +298,7 @@ PYTHON_OBJS= \ Python/formatter_unicode.o \ - Python/fileutils.o \ + Python/formatter_string.o \ Python/$(DYNLOADFILE) \ -+ @SYSTEMTAPOBJS@ \ ++ @DTRACEOBJS@ \ $(LIBOBJS) \ $(MACHDEP_OBJS) \ $(THREADOBJ) -@@ -713,7 +714,8 @@ Objects/setobject.o: $(srcdir)/Objects/s - $(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) - $(OPCODETARGETGEN) $(OPCODETARGETS_H) - --Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h -+Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h \ -+ $(srcdir)/Python/ceval_systemtap.h @SYSTEMTAPDEPS@ +@@ -599,6 +600,18 @@ Python/formatter_unicode.o: $(srcdir)/Py + Python/formatter_string.o: $(srcdir)/Python/formatter_string.c \ + $(STRINGLIB_HEADERS) - Python/frozen.o: Python/importlib.h Python/importlib_external.h - -@@ -724,6 +726,13 @@ Objects/typeobject.o: $(srcdir)/Objects/ - Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py - $(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > Objects/typeslots.inc - -+# Only needed with --with-systemtap; not a public header: -+$(srcdir)/Python/pysystemtap.h: $(srcdir)/Python/pysystemtap.d -+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/pysystemtap.d ++# Only needed with --with-dtrace ++buildinclude: ++ mkdir -p Include ++ ++Include/pydtrace.h: buildinclude $(srcdir)/Include/pydtrace.d ++ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Include/pydtrace.d ++ ++Python/ceval.o: Include/pydtrace.h + -+Python/pysystemtap.o: $(srcdir)/Python/pysystemtap.d Python/ceval.o -+ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Python/pysystemtap.d Python/ceval.o ++Python/dtrace.o: buildinclude $(srcdir)/Include/pydtrace.d Python/ceval.o ++ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Include/pydtrace.d Python/ceval.o + ############################################################################ # Header files -@@ -1345,6 +1354,7 @@ clean: pycremoval - -rm -f Lib/lib2to3/*Grammar*.pickle - -rm -f Programs/_testembed Programs/_freeze_importlib - -rm -rf build -+ -rm -f $(srcdir)/Python/pysystemtap.h - - profile-removal: - find . -name '*.gc??' -exec rm -f {} ';' -diff -up Python-3.3.0rc2/pyconfig.h.in.systemtap Python-3.3.0rc2/pyconfig.h.in ---- Python-3.3.0rc2/pyconfig.h.in.systemtap 2012-09-09 05:11:14.000000000 -0400 -+++ Python-3.3.0rc2/pyconfig.h.in 2012-09-10 09:17:21.120511781 -0400 -@@ -1306,6 +1306,9 @@ - /* Define if you want to compile in Python-specific mallocs */ - #undef WITH_PYMALLOC - -+/* Define if you want to compile in SystemTap support */ -+#undef WITH_SYSTEMTAP -+ - /* Define if you want to compile in rudimentary thread support */ - #undef WITH_THREAD - -diff -up Python-3.3.0rc2/Python/ceval.c.systemtap Python-3.3.0rc2/Python/ceval.c ---- Python-3.3.0rc2/Python/ceval.c.systemtap 2012-09-09 05:11:12.000000000 -0400 -+++ Python-3.3.0rc2/Python/ceval.c 2012-09-10 09:17:21.122511781 -0400 -@@ -18,6 +18,8 @@ +@@ -1251,7 +1264,7 @@ Python/thread.o: @THREADHEADERS@ + .PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure + .PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools + .PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean +-.PHONY: smelly funny patchcheck touch altmaninstall ++.PHONY: smelly funny patchcheck touch altmaninstall buildinclude + .PHONY: gdbhooks + + # IF YOU PUT ANYTHING HERE IT WILL GO AWAY +diff -up Python-2.7rc1/pyconfig.h.in.systemtap Python-2.7rc1/pyconfig.h.in +--- Python-2.7rc1/pyconfig.h.in.systemtap 2010-05-08 07:04:18.000000000 -0400 ++++ Python-2.7rc1/pyconfig.h.in 2010-06-06 10:53:15.521974070 -0400 +@@ -1074,6 +1074,9 @@ + /* Define if you want documentation strings in extension modules */ + #undef WITH_DOC_STRINGS + ++/* Define if you want to compile in Dtrace support */ ++#undef WITH_DTRACE ++ + /* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic + linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). + Dyld is necessary to support frameworks. */ +diff -up Python-2.7rc1/Python/ceval.c.systemtap Python-2.7rc1/Python/ceval.c +--- Python-2.7rc1/Python/ceval.c.systemtap 2010-05-09 10:46:46.000000000 -0400 ++++ Python-2.7rc1/Python/ceval.c 2010-06-06 11:08:40.683100500 -0400 +@@ -19,6 +19,10 @@ #include -+#include "ceval_systemtap.h" ++#ifdef WITH_DTRACE ++#include "pydtrace.h" ++#endif + #ifndef WITH_TSC #define READ_TIMESTAMP(var) -@@ -1160,6 +1162,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int - } - } - -+ if (PYTHON_FUNCTION_ENTRY_ENABLED()) { -+ systemtap_function_entry(f); -+ } -+ - co = f->f_code; - names = co->co_names; - consts = co->co_consts; -@@ -3077,6 +3083,11 @@ fast_yield: +@@ -671,6 +675,55 @@ PyEval_EvalCode(PyCodeObject *co, PyObje + NULL); + } - /* pop frame */ - exit_eval_frame: -+ -+ if (PYTHON_FUNCTION_RETURN_ENABLED()) { -+ systemtap_function_return(f); -+ } -+ - Py_LeaveRecursiveCall(); - f->f_executing = 0; - tstate->frame = f->f_back; -diff -up Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap Python-3.3.0rc2/Python/ceval_systemtap.h ---- Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap 2012-09-10 09:17:21.122511781 -0400 -+++ Python-3.3.0rc2/Python/ceval_systemtap.h 2012-09-10 09:17:21.122511781 -0400 -@@ -0,0 +1,86 @@ -+/* -+ Support for SystemTap static markers -+*/ -+ -+#ifdef WITH_SYSTEMTAP -+ -+#include "pysystemtap.h" -+ -+/* -+ A struct to hold all of the information gathered when one of the traceable -+ markers is triggered -+*/ -+struct frame_marker_info ++#ifdef WITH_DTRACE ++static void ++dtrace_entry(PyFrameObject *f) +{ -+ PyObject *filename_obj; -+ PyObject *funcname_obj; + const char *filename; -+ const char *funcname; ++ const char *fname; + int lineno; -+}; + -+static void -+get_frame_marker_info(PyFrameObject *f, struct frame_marker_info *fmi) -+{ -+ PyObject *ptype; -+ PyObject *pvalue; -+ PyObject *ptraceback; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ -+ fmi->filename_obj = PyUnicode_EncodeFSDefault(f->f_code->co_filename); -+ if (fmi->filename_obj) { -+ fmi->filename = PyBytes_AsString(fmi->filename_obj); -+ } else { -+ fmi->filename = NULL; -+ } ++ filename = PyString_AsString(f->f_code->co_filename); ++ fname = PyString_AsString(f->f_code->co_name); ++ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); + -+ fmi->funcname_obj = PyUnicode_AsUTF8String(f->f_code->co_name); -+ if (fmi->funcname_obj) { -+ fmi->funcname = PyBytes_AsString(fmi->funcname_obj); -+ } else { -+ fmi->funcname = NULL; -+ } -+ -+ fmi->lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); -+ -+ PyErr_Restore(ptype, pvalue, ptraceback); ++ PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno); + ++ /* ++ * Currently a USDT tail-call will not receive the correct arguments. ++ * Disable the tail call here. ++ */ ++#if defined(__sparc) ++ asm("nop"); ++#endif +} + +static void -+release_frame_marker_info(struct frame_marker_info *fmi) ++dtrace_return(PyFrameObject *f) +{ -+ Py_XDECREF(fmi->filename_obj); -+ Py_XDECREF(fmi->funcname_obj); -+} ++ const char *filename; ++ const char *fname; ++ int lineno; + -+static void -+systemtap_function_entry(PyFrameObject *f) -+{ -+ struct frame_marker_info fmi; -+ get_frame_marker_info(f, &fmi); -+ PYTHON_FUNCTION_ENTRY(fmi.filename, fmi.funcname, fmi.lineno, f); -+ release_frame_marker_info(&fmi); -+} ++ filename = PyString_AsString(f->f_code->co_filename); ++ fname = PyString_AsString(f->f_code->co_name); ++ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); ++ PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno); + -+static void -+systemtap_function_return(PyFrameObject *f) -+{ -+ struct frame_marker_info fmi; -+ get_frame_marker_info(f, &fmi); -+ PYTHON_FUNCTION_RETURN(fmi.filename, fmi.funcname, fmi.lineno, f); -+ release_frame_marker_info(&fmi); ++ /* ++ * Currently a USDT tail-call will not receive the correct arguments. ++ * Disable the tail call here. ++ */ ++#if defined(__sparc) ++ asm("nop"); ++#endif +} ++#else ++#define PYTHON_FUNCTION_ENTRY_ENABLED() 0 ++#define PYTHON_FUNCTION_RETURN_ENABLED() 0 ++#define dtrace_entry(f) ++#define dtrace_return(f) ++#endif + + /* Interpreter main loop */ + +@@ -909,6 +962,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int + } + } + ++ if (PYTHON_FUNCTION_ENTRY_ENABLED()) ++ dtrace_entry(f); + -+#else /* #ifdef WITH_SYSTEMTAP */ -+ -+/* -+ When configured --without-systemtap, everything compiles away to nothing: -+*/ -+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0 -+#define PYTHON_FUNCTION_RETURN_ENABLED() 0 -+#define systemtap_function_entry(f) -+#define systemtap_function_return(f) + co = f->f_code; + names = co->co_names; + consts = co->co_consts; +@@ -3000,6 +3056,9 @@ fast_yield: + + /* pop frame */ + exit_eval_frame: ++ if (PYTHON_FUNCTION_RETURN_ENABLED()) ++ dtrace_return(f); + -+#endif -diff -up Python-3.3.0rc2/Python/pysystemtap.d.systemtap Python-3.3.0rc2/Python/pysystemtap.d ---- Python-3.3.0rc2/Python/pysystemtap.d.systemtap 2012-09-10 09:17:21.122511781 -0400 -+++ Python-3.3.0rc2/Python/pysystemtap.d 2012-09-10 09:17:21.122511781 -0400 -@@ -0,0 +1,4 @@ -+provider python { -+ probe function__entry(const char *, const char *, int, PyFrameObject *); -+ probe function__return(const char *, const char *, int, PyFrameObject *); -+}; + Py_LeaveRecursiveCall(); + tstate->frame = f->f_back; + diff --git a/SOURCES/00111-no-static-lib.patch b/SOURCES/00111-no-static-lib.patch index bc4203de..2f4fdd68 100644 --- a/SOURCES/00111-no-static-lib.patch +++ b/SOURCES/00111-no-static-lib.patch @@ -1,20 +1,19 @@ -diff --git a/Makefile.pre.in b/Makefile.pre.in -index 4b093e3..1088435 100644 ---- a/Makefile.pre.in -+++ b/Makefile.pre.in -@@ -543,7 +543,7 @@ clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c - $(PYTHON_FOR_REGEN) ./Tools/clinic/clinic.py --make +diff -up Python-2.7.3/Makefile.pre.in.no-static-lib Python-2.7.3/Makefile.pre.in +--- Python-2.7.3/Makefile.pre.in.no-static-lib 2013-02-19 14:03:40.801993224 -0500 ++++ Python-2.7.3/Makefile.pre.in 2013-02-19 14:04:44.070988898 -0500 +@@ -397,7 +397,7 @@ coverage: - # Build the interpreter --$(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) -+$(BUILDPYTHON): Programs/python.o $(LDLIBRARY) $(PY3LIBRARY) - $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) - platform: $(BUILDPYTHON) pybuilddir.txt -@@ -588,18 +588,6 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o + # Build the interpreter +-$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) ++$(BUILDPYTHON): Modules/python.o $(LDLIBRARY) + $(LINKCC) $(CFLAGS) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ + Modules/python.o \ + $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) +@@ -413,18 +413,6 @@ sharedmods: $(BUILDPYTHON) + $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build - -# Build static library -# avoid long command lines, same as LIBRARY_OBJS -$(LIBRARY): $(LIBRARY_OBJS) @@ -22,30 +21,21 @@ index 4b093e3..1088435 100644 - $(AR) $(ARFLAGS) $@ Modules/getbuildinfo.o - $(AR) $(ARFLAGS) $@ $(PARSER_OBJS) - $(AR) $(ARFLAGS) $@ $(OBJECT_OBJS) -- $(AR) $(ARFLAGS) $@ $(PYTHON_OBJS) Python/frozen.o -- $(AR) $(ARFLAGS) $@ $(MODULE_OBJS) +- $(AR) $(ARFLAGS) $@ $(PYTHON_OBJS) +- $(AR) $(ARFLAGS) $@ $(MODULE_OBJS) $(SIGNAL_OBJS) - $(AR) $(ARFLAGS) $@ $(MODOBJS) - $(RANLIB) $@ - - libpython$(LDVERSION).so: $(LIBRARY_OBJS) + libpython$(VERSION).so: $(LIBRARY_OBJS) if test $(INSTSONAME) != $(LDLIBRARY); then \ $(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ -@@ -689,7 +677,7 @@ Modules/Setup: $(srcdir)/Modules/Setup.dist - echo "-----------------------------------------------"; \ - fi - --Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) -+Programs/_testembed: Programs/_testembed.o $(LDLIBRARY) $(PY3LIBRARY) - $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) - - ############################################################################ -@@ -1425,18 +1413,6 @@ libainstall: @DEF_MAKE_RULE@ python-config +@@ -1021,18 +1009,6 @@ libainstall: all python-config else true; \ fi; \ done - @if test -d $(LIBRARY); then :; else \ - if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \ -- if test "$(SHLIB_SUFFIX)" = .dll; then \ +- if test "$(SO)" = .dll; then \ - $(INSTALL_DATA) $(LDLIBRARY) $(DESTDIR)$(LIBPL) ; \ - else \ - $(INSTALL_DATA) $(LIBRARY) $(DESTDIR)$(LIBPL)/$(LIBRARY) ; \ @@ -56,5 +46,5 @@ index 4b093e3..1088435 100644 - fi; \ - fi $(INSTALL_DATA) Modules/config.c $(DESTDIR)$(LIBPL)/config.c - $(INSTALL_DATA) Programs/python.o $(DESTDIR)$(LIBPL)/python.o + $(INSTALL_DATA) Modules/python.o $(DESTDIR)$(LIBPL)/python.o $(INSTALL_DATA) $(srcdir)/Modules/config.c.in $(DESTDIR)$(LIBPL)/config.c.in diff --git a/SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch b/SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch index 77dc6ecb..e63395fb 100644 --- a/SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch +++ b/SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch @@ -1,16 +1,17 @@ -diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python-3.2.2/Lib/unittest/case.py ---- Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400 -+++ Python-3.2.2/Lib/unittest/case.py 2011-09-09 06:35:16.365568382 -0400 -@@ -3,6 +3,7 @@ +diff -up Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python-2.7.2/Lib/unittest/case.py +--- Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-08 14:45:47.677169191 -0400 ++++ Python-2.7.2/Lib/unittest/case.py 2011-09-08 16:01:36.287858159 -0400 +@@ -1,6 +1,7 @@ + """Test case implementation""" + + import collections ++import os import sys import functools import difflib -+import os - import logging - import pprint - import re -@@ -101,5 +102,21 @@ def expectedFailure(func): - raise self.test_case.failureException(msg) +@@ -94,6 +95,43 @@ def expectedFailure(func): + return wrapper + +# Non-standard/downstream-only hooks for handling issues with specific test +# cases: @@ -28,19 +29,40 @@ diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python + else: + return _id + - class _AssertRaisesBaseContext(_BaseTestCaseContext): ++def _expectedFailureInRpmBuild(func): ++ """ ++ Non-standard/downstream-only decorator for marking a specific unit test ++ as expected to fail within the %check of an rpmbuild. ++ ++ Specifically, this takes effect when WITHIN_PYTHON_RPM_BUILD is set within ++ the environment, and has no effect otherwise. ++ """ ++ @functools.wraps(func) ++ def wrapper(*args, **kwargs): ++ if 'WITHIN_PYTHON_RPM_BUILD' in os.environ: ++ try: ++ func(*args, **kwargs) ++ except Exception: ++ raise _ExpectedFailure(sys.exc_info()) ++ raise _UnexpectedSuccess ++ else: ++ # Call directly: ++ func(*args, **kwargs) ++ return wrapper ++ + class _AssertRaisesContext(object): + """A context manager used to implement TestCase.assertRaises* methods.""" - def __init__(self, expected, test_case, expected_regex=None): -diff -up Python-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-3.2.2/Lib/unittest/__init__.py ---- Python-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400 -+++ Python-3.2.2/Lib/unittest/__init__.py 2011-09-09 06:35:16.366568382 -0400 +diff -up Python-2.7.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-2.7.2/Lib/unittest/__init__.py +--- Python-2.7.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest 2011-09-08 14:59:39.534112310 -0400 ++++ Python-2.7.2/Lib/unittest/__init__.py 2011-09-08 15:07:09.191081562 -0400 @@ -57,7 +57,8 @@ __unittest = True from .result import TestResult from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf, - skipUnless, expectedFailure) + skipUnless, expectedFailure, -+ _skipInRpmBuild) ++ _skipInRpmBuild, _expectedFailureInRpmBuild) from .suite import BaseTestSuite, TestSuite from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames, findTestCases) diff --git a/SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch b/SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch index 04570930..86537722 100644 --- a/SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch +++ b/SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch @@ -1,12 +1,12 @@ -diff -up Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py ---- Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild 2011-09-03 12:16:40.000000000 -0400 -+++ Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py 2011-09-10 05:04:56.328852558 -0400 -@@ -23,6 +23,7 @@ setup(name='foo', version='0.1', py_modu +diff -up Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py +--- Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild 2012-04-09 19:07:29.000000000 -0400 ++++ Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py 2012-04-13 00:20:08.223819263 -0400 +@@ -24,6 +24,7 @@ setup(name='foo', version='0.1', py_modu """ +@unittest._skipInRpmBuild("don't try to nest one rpm build inside another rpm build") class BuildRpmTestCase(support.TempdirManager, - support.EnvironGuard, support.LoggingSilencer, -diff -up Python-3.2.2/Lib/distutils/tests/test_build_ext.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_build_ext.py + unittest.TestCase): +diff -up Python-2.7.3/Lib/distutils/tests/test_build_ext.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_build_ext.py diff --git a/SOURCES/00146-hashlib-fips.patch b/SOURCES/00146-hashlib-fips.patch index e0cdce0a..c67eb3b5 100644 --- a/SOURCES/00146-hashlib-fips.patch +++ b/SOURCES/00146-hashlib-fips.patch @@ -1,48 +1,82 @@ -diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index 316cece..b7ad879 100644 ---- a/Lib/hashlib.py -+++ b/Lib/hashlib.py -@@ -23,6 +23,16 @@ the zlib module. +diff -up Python-2.7.2/Lib/hashlib.py.hashlib-fips Python-2.7.2/Lib/hashlib.py +--- Python-2.7.2/Lib/hashlib.py.hashlib-fips 2011-06-11 11:46:24.000000000 -0400 ++++ Python-2.7.2/Lib/hashlib.py 2011-09-14 00:21:26.194252001 -0400 +@@ -6,9 +6,12 @@ + + __doc__ = """hashlib module - A common interface to many hash functions. + +-new(name, string='') - returns a new hash object implementing the +- given hash function; initializing the hash +- using the given string data. ++new(name, string='', usedforsecurity=True) ++ - returns a new hash object implementing the given hash function; ++ initializing the hash using the given string data. ++ ++ "usedforsecurity" is a non-standard extension for better supporting ++ FIPS-compliant environments (see below) + + Named constructor functions are also available, these are much faster + than using new(): +@@ -24,6 +27,20 @@ the zlib module. Choose your hash function wisely. Some have known collision weaknesses. sha384 and sha512 will be slow on 32 bit platforms. -+If the underlying implementation supports "FIPS mode", and this is enabled, it -+may restrict the available hashes to only those that are compliant with FIPS -+regulations. For example, it may deny the use of MD5, on the grounds that this -+is not secure for uses such as authentication, system integrity checking, or -+digital signatures. If you need to use such a hash for non-security purposes -+(such as indexing into a data structure for speed), you can override the keyword -+argument "usedforsecurity" from True to False to signify that your code is not -+relying on the hash for security purposes, and this will allow the hash to be -+usable even in FIPS mode. ++Our implementation of hashlib uses OpenSSL. ++ ++OpenSSL has a "FIPS mode", which, if enabled, may restrict the available hashes ++to only those that are compliant with FIPS regulations. For example, it may ++deny the use of MD5, on the grounds that this is not secure for uses such as ++authentication, system integrity checking, or digital signatures. ++ ++If you need to use such a hash for non-security purposes (such as indexing into ++a data structure for speed), you can override the keyword argument ++"usedforsecurity" from True to False to signify that your code is not relying ++on the hash for security purposes, and this will allow the hash to be usable ++even in FIPS mode. This is not a standard feature of Python 2.7's hashlib, and ++is included here to better support FIPS mode. + Hash objects have these methods: - - update(arg): Update the hash object with the bytes in arg. Repeated calls + - update(arg): Update the hash object with the string arg. Repeated calls are equivalent to a single call with the concatenation of all -@@ -62,6 +72,18 @@ algorithms_available = set(__always_supported) - __all__ = __always_supported + ('new', 'algorithms_guaranteed', - 'algorithms_available', 'pbkdf2_hmac') - -+import functools -+def __ignore_usedforsecurity(func): -+ """Used for sha3_* functions. Until OpenSSL implements them, we want -+ to use them from Python _sha3 module, but we want them to accept -+ usedforsecurity argument too.""" -+ # TODO: remove this function when OpenSSL implements sha3 -+ @functools.wraps(func) -+ def inner(*args, **kwargs): -+ if 'usedforsecurity' in kwargs: -+ kwargs.pop('usedforsecurity') -+ return func(*args, **kwargs) -+ return inner - - __builtin_constructor_cache = {} - -@@ -100,31 +122,39 @@ def __get_openssl_constructor(name): +@@ -63,74 +80,39 @@ algorithms = __always_supported + __all__ = __always_supported + ('new', 'algorithms') + + +-def __get_builtin_constructor(name): +- try: +- if name in ('SHA1', 'sha1'): +- import _sha +- return _sha.new +- elif name in ('MD5', 'md5'): +- import _md5 +- return _md5.new +- elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): +- import _sha256 +- bs = name[3:] +- if bs == '256': +- return _sha256.sha256 +- elif bs == '224': +- return _sha256.sha224 +- elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): +- import _sha512 +- bs = name[3:] +- if bs == '512': +- return _sha512.sha512 +- elif bs == '384': +- return _sha512.sha384 +- except ImportError: +- pass # no extension module, this hash is unsupported. +- +- raise ValueError('unsupported hash type ' + name) +- +- + def __get_openssl_constructor(name): + try: f = getattr(_hashlib, 'openssl_' + name) # Allow the C module to raise ValueError. The function will be # defined but the hash not actually available thanks to OpenSSL. - f() ++ # + # We pass "usedforsecurity=False" to disable FIPS-based restrictions: + # at this stage we're merely seeing if the function is callable, + # rather than using it for actual work. @@ -50,76 +84,61 @@ index 316cece..b7ad879 100644 # Use the C function directly (very fast) return f except (AttributeError, ValueError): -+ # TODO: We want to just raise here when OpenSSL implements sha3 -+ # because we want to make sure that Fedora uses everything from OpenSSL - return __get_builtin_constructor(name) - - --def __py_new(name, data=b''): -- """new(name, data=b'') - Return a new hashing object using the named algorithm; -- optionally initialized with data (which must be bytes). -+def __py_new(name, data=b'', usedforsecurity=True): -+ """new(name, data=b'', usedforsecurity=True) - Return a new hashing object using -+ the named algorithm; optionally initialized with data (which must be bytes). -+ The 'usedforsecurity' keyword argument does nothing, and is for compatibilty -+ with the OpenSSL implementation - """ - return __get_builtin_constructor(name)(data) - +- return __get_builtin_constructor(name) ++ raise --def __hash_new(name, data=b''): -- """new(name, data=b'') - Return a new hashing object using the named algorithm; -- optionally initialized with data (which must be bytes). -+def __hash_new(name, data=b'', usedforsecurity=True): -+ """new(name, data=b'', usedforsecurity=True) - Return a new hashing object using -+ the named algorithm; optionally initialized with data (which must be bytes). -+ +- +-def __py_new(name, string=''): +- """new(name, string='') - Return a new hashing object using the named algorithm; +- optionally initialized with a string. +- """ +- return __get_builtin_constructor(name)(string) +- +- +-def __hash_new(name, string=''): ++def __hash_new(name, string='', usedforsecurity=True): + """new(name, string='') - Return a new hashing object using the named algorithm; + optionally initialized with a string. + Override 'usedforsecurity' to False when using for non-security purposes in + a FIPS environment """ try: -- return _hashlib.new(name, data) -+ return _hashlib.new(name, data, usedforsecurity) +- return _hashlib.new(name, string) ++ return _hashlib.new(name, string, usedforsecurity) except ValueError: - # If the _hashlib module (OpenSSL) doesn't support the named - # hash, try using our builtin implementations. - # This allows for SHA224/256 and SHA384/512 support even though - # the OpenSSL library prior to 0.9.8 doesn't provide them. -+ # TODO: We want to just raise here when OpenSSL implements sha3 -+ # because we want to make sure that Fedora uses everything from OpenSSL - return __get_builtin_constructor(name)(data) - - -@@ -207,7 +237,10 @@ for __func_name in __always_supported: +- return __get_builtin_constructor(name)(string) +- ++ raise + + try: + import _hashlib + new = __hash_new + __get_hash = __get_openssl_constructor + except ImportError: +- new = __py_new +- __get_hash = __get_builtin_constructor ++ # We don't build the legacy modules ++ raise + + for __func_name in __always_supported: # try them all, some may not work due to the OpenSSL - # version not supporting that algorithm. - try: -- globals()[__func_name] = __get_hash(__func_name) -+ func = __get_hash(__func_name) -+ if 'sha3_' in __func_name: -+ func = __ignore_usedforsecurity(func) -+ globals()[__func_name] = func - except ValueError: - import logging - logging.exception('code for hash %s was not found.', __func_name) -@@ -215,3 +248,4 @@ for __func_name in __always_supported: +@@ -143,4 +125,4 @@ for __func_name in __always_supported: + # Cleanup locals() del __always_supported, __func_name, __get_hash - del __py_new, __hash_new, __get_openssl_constructor -+del __ignore_usedforsecurity -\ No newline at end of file -diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index c9b113e..60e2392 100644 ---- a/Lib/test/test_hashlib.py -+++ b/Lib/test/test_hashlib.py -@@ -24,7 +24,22 @@ from test.support import _4G, bigmemtest, import_fresh_module - COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') - - c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) --py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) -+# skipped on Fedora, since we always use OpenSSL implementation -+# py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) -+ +-del __py_new, __hash_new, __get_openssl_constructor ++del __hash_new, __get_openssl_constructor +diff -up Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips Python-2.7.2/Lib/test/test_hashlib.py +--- Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips 2011-06-11 11:46:25.000000000 -0400 ++++ Python-2.7.2/Lib/test/test_hashlib.py 2011-09-14 01:08:55.525254195 -0400 +@@ -32,6 +32,19 @@ def hexstr(s): + r = r + h[(i >> 4) & 0xF] + h[i & 0xF] + return r + +def openssl_enforces_fips(): + # Use the "openssl" command (if present) to try to determine if the local + # OpenSSL is configured to enforce FIPS @@ -134,80 +153,122 @@ index c9b113e..60e2392 100644 + return b'unknown cipher' in stderr +OPENSSL_ENFORCES_FIPS = openssl_enforces_fips() - def hexstr(s): - assert isinstance(s, bytes), repr(s) -@@ -34,6 +49,16 @@ def hexstr(s): - r += h[(i >> 4) & 0xF] + h[i & 0xF] - return r - -+# hashlib and _hashlib-based functions support a "usedforsecurity" keyword -+# argument, and FIPS mode requires that it be used overridden with a False -+# value for these selftests to work. Other cryptographic code within Python -+# doesn't support this keyword. -+# Modify a function to one in which "usedforsecurity=False" is added to the -+# keyword arguments: -+def suppress_fips(f): -+ def g(*args, **kwargs): -+ return f(*args, usedforsecurity=False, **kwargs) -+ return g - class HashLibTestCase(unittest.TestCase): supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', -@@ -63,11 +88,11 @@ class HashLibTestCase(unittest.TestCase): - # For each algorithm, test the direct constructor and the use +@@ -61,10 +74,10 @@ class HashLibTestCase(unittest.TestCase) # of hashlib.new given the algorithm name. for algorithm, constructors in self.constructors_to_test.items(): -- constructors.add(getattr(hashlib, algorithm)) -+ constructors.add(suppress_fips(getattr(hashlib, algorithm))) - def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm): + constructors.add(getattr(hashlib, algorithm)) +- def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm): ++ def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, usedforsecurity=True): if data is None: - return hashlib.new(_alg) - return hashlib.new(_alg, data) -+ return suppress_fips(hashlib.new)(_alg) -+ return suppress_fips(hashlib.new)(_alg, data) ++ return hashlib.new(_alg, usedforsecurity=usedforsecurity) ++ return hashlib.new(_alg, data, usedforsecurity=usedforsecurity) constructors.add(_test_algorithm_via_hashlib_new) _hashlib = self._conditional_import_module('_hashlib') -@@ -79,27 +104,12 @@ class HashLibTestCase(unittest.TestCase): - for algorithm, constructors in self.constructors_to_test.items(): - constructor = getattr(_hashlib, 'openssl_'+algorithm, None) +@@ -78,28 +91,13 @@ class HashLibTestCase(unittest.TestCase) if constructor: -- constructors.add(constructor) -+ constructors.add(suppress_fips(constructor)) - - def add_builtin_constructor(name): - constructor = getattr(hashlib, "__get_builtin_constructor")(name) - self.constructors_to_test[name].add(constructor) + constructors.add(constructor) - _md5 = self._conditional_import_module('_md5') - if _md5: -- add_builtin_constructor('md5') -- _sha1 = self._conditional_import_module('_sha1') -- if _sha1: -- add_builtin_constructor('sha1') +- self.constructors_to_test['md5'].add(_md5.new) +- _sha = self._conditional_import_module('_sha') +- if _sha: +- self.constructors_to_test['sha1'].add(_sha.new) - _sha256 = self._conditional_import_module('_sha256') - if _sha256: -- add_builtin_constructor('sha224') -- add_builtin_constructor('sha256') +- self.constructors_to_test['sha224'].add(_sha256.sha224) +- self.constructors_to_test['sha256'].add(_sha256.sha256) - _sha512 = self._conditional_import_module('_sha512') - if _sha512: -- add_builtin_constructor('sha384') -- add_builtin_constructor('sha512') +- self.constructors_to_test['sha384'].add(_sha512.sha384) +- self.constructors_to_test['sha512'].add(_sha512.sha512) - super(HashLibTestCase, self).__init__(*args, **kwargs) - @property -@@ -148,9 +158,6 @@ class HashLibTestCase(unittest.TestCase): - else: - del sys.modules['_md5'] - self.assertRaises(TypeError, get_builtin_constructor, 3) -- constructor = get_builtin_constructor('md5') -- self.assertIs(constructor, _md5.md5) -- self.assertEqual(sorted(builtin_constructor_cache), ['MD5', 'md5']) - + def test_hash_array(self): + a = array.array("b", range(10)) + constructors = self.constructors_to_test.itervalues() + for cons in itertools.chain.from_iterable(constructors): +- c = cons(a) ++ c = cons(a, usedforsecurity=False) + c.hexdigest() + + def test_algorithms_attribute(self): +@@ -115,28 +113,9 @@ class HashLibTestCase(unittest.TestCase) + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) + +- def test_get_builtin_constructor(self): +- get_builtin_constructor = hashlib.__dict__[ +- '__get_builtin_constructor'] +- self.assertRaises(ValueError, get_builtin_constructor, 'test') +- try: +- import _md5 +- except ImportError: +- pass +- # This forces an ImportError for "import _md5" statements +- sys.modules['_md5'] = None +- try: +- self.assertRaises(ValueError, get_builtin_constructor, 'md5') +- finally: +- if '_md5' in locals(): +- sys.modules['_md5'] = _md5 +- else: +- del sys.modules['_md5'] +- self.assertRaises(TypeError, get_builtin_constructor, 3) +- def test_hexdigest(self): - for cons in self.hash_constructors: -@@ -433,6 +440,64 @@ class HashLibTestCase(unittest.TestCase): + for name in self.supported_hash_names: +- h = hashlib.new(name) ++ h = hashlib.new(name, usedforsecurity=False) + self.assertTrue(hexstr(h.digest()) == h.hexdigest()) + + def test_large_update(self): +@@ -145,16 +125,16 @@ class HashLibTestCase(unittest.TestCase) + abcs = aas + bees + cees + + for name in self.supported_hash_names: +- m1 = hashlib.new(name) ++ m1 = hashlib.new(name, usedforsecurity=False) + m1.update(aas) + m1.update(bees) + m1.update(cees) + +- m2 = hashlib.new(name) ++ m2 = hashlib.new(name, usedforsecurity=False) + m2.update(abcs) + self.assertEqual(m1.digest(), m2.digest(), name+' update problem.') + +- m3 = hashlib.new(name, abcs) ++ m3 = hashlib.new(name, abcs, usedforsecurity=False) + self.assertEqual(m1.digest(), m3.digest(), name+' new problem.') + + def check(self, name, data, digest): +@@ -162,7 +142,7 @@ class HashLibTestCase(unittest.TestCase) + # 2 is for hashlib.name(...) and hashlib.new(name, ...) + self.assertGreaterEqual(len(constructors), 2) + for hash_object_constructor in constructors: +- computed = hash_object_constructor(data).hexdigest() ++ computed = hash_object_constructor(data, usedforsecurity=False).hexdigest() + self.assertEqual( + computed, digest, + "Hash algorithm %s constructed using %s returned hexdigest" +@@ -172,7 +152,8 @@ class HashLibTestCase(unittest.TestCase) + + def check_unicode(self, algorithm_name): + # Unicode objects are not allowed as input. +- expected = hashlib.new(algorithm_name, str(u'spam')).hexdigest() ++ expected = hashlib.new(algorithm_name, str(u'spam'), ++ usedforsecurity=False).hexdigest() + self.check(algorithm_name, u'spam', expected) + + def test_unicode(self): +@@ -354,6 +335,70 @@ class HashLibTestCase(unittest.TestCase) self.assertEqual(expected_hash, hasher.hexdigest()) @@ -227,74 +288,70 @@ index c9b113e..60e2392 100644 + m = hashlib.new('md5', b'abc\n', usedforsecurity=False) + self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + ++ def assertRaisesUnknownCipher(self, callable_obj=None, *args, **kwargs): ++ try: ++ callable_obj(*args, **kwargs) ++ except ValueError, e: ++ if not e.args[0].endswith('unknown cipher'): ++ self.fail('Incorrect exception raised') ++ else: ++ self.fail('Exception was not raised') ++ + @unittest.skipUnless(OPENSSL_ENFORCES_FIPS, + 'FIPS enforcement required for this test.') + def test_hashlib_fips_mode(self): + # Ensure that we raise a ValueError on vanilla attempts to use MD5 + # in hashlib in a FIPS-enforced setting: -+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): -+ m = hashlib.md5() -+ -+ if not self._conditional_import_module('_md5'): -+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): -+ m = hashlib.new('md5') ++ self.assertRaisesUnknownCipher(hashlib.md5) ++ self.assertRaisesUnknownCipher(hashlib.new, 'md5') + + @unittest.skipUnless(OPENSSL_ENFORCES_FIPS, + 'FIPS enforcement required for this test.') + def test_hashopenssl_fips_mode(self): + # Verify the _hashlib module's handling of md5: -+ _hashlib = self._conditional_import_module('_hashlib') -+ if _hashlib: -+ assert hasattr(_hashlib, 'openssl_md5') ++ import _hashlib ++ ++ assert hasattr(_hashlib, 'openssl_md5') + -+ # Ensure that _hashlib raises a ValueError on vanilla attempts to -+ # use MD5 in a FIPS-enforced setting: -+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): -+ m = _hashlib.openssl_md5() -+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): -+ m = _hashlib.new('md5') ++ # Ensure that _hashlib raises a ValueError on vanilla attempts to ++ # use MD5 in a FIPS-enforced setting: ++ self.assertRaisesUnknownCipher(_hashlib.openssl_md5) ++ self.assertRaisesUnknownCipher(_hashlib.new, 'md5') + -+ # Ensure that in such a setting we can whitelist a callsite with -+ # usedforsecurity=False and have it succeed: -+ m = _hashlib.openssl_md5(usedforsecurity=False) -+ m.update(b'abc\n') -+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") ++ # Ensure that in such a setting we can whitelist a callsite with ++ # usedforsecurity=False and have it succeed: ++ m = _hashlib.openssl_md5(usedforsecurity=False) ++ m.update('abc\n') ++ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + -+ m = _hashlib.new('md5', usedforsecurity=False) -+ m.update(b'abc\n') -+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") -+ -+ m = _hashlib.openssl_md5(b'abc\n', usedforsecurity=False) -+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") ++ m = _hashlib.new('md5', usedforsecurity=False) ++ m.update('abc\n') ++ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + -+ m = _hashlib.new('md5', b'abc\n', usedforsecurity=False) -+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") - - class KDFTests(unittest.TestCase): - -@@ -516,7 +581,7 @@ class KDFTests(unittest.TestCase): - out = pbkdf2(hash_name='sha1', password=b'password', salt=b'salt', - iterations=1, dklen=None) - self.assertEqual(out, self.pbkdf2_results['sha1'][0][0]) -- -+ @unittest.skip('skipped on Fedora, as we always use OpenSSL pbkdf2_hmac') - def test_pbkdf2_hmac_py(self): - self._test_pbkdf2_hmac(py_hashlib.pbkdf2_hmac) - -diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 44765ac..b8cf490 100644 ---- a/Modules/_hashopenssl.c -+++ b/Modules/_hashopenssl.c -@@ -20,6 +20,8 @@ ++ m = _hashlib.openssl_md5('abc\n', usedforsecurity=False) ++ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") ++ ++ m = _hashlib.new('md5', 'abc\n', usedforsecurity=False) ++ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") ++ ++ ++ + def test_main(): + test_support.run_unittest(HashLibTestCase) +diff -up Python-2.7.2/Modules/_hashopenssl.c.hashlib-fips Python-2.7.2/Modules/_hashopenssl.c +--- Python-2.7.2/Modules/_hashopenssl.c.hashlib-fips 2011-06-11 11:46:26.000000000 -0400 ++++ Python-2.7.2/Modules/_hashopenssl.c 2011-09-14 00:21:26.199252001 -0400 +@@ -36,6 +36,8 @@ + #endif /* EVP is the preferred interface to hashing in OpenSSL */ +#include +#include #include - #include - /* We use the object interface to discover what hashes OpenSSL supports. */ -@@ -45,11 +47,19 @@ typedef struct { + + #define MUNCH_SIZE INT_MAX +@@ -65,11 +67,19 @@ typedef struct { static PyTypeObject EVPtype; @@ -318,7 +375,7 @@ index 44765ac..b8cf490 100644 DEFINE_CONSTS_FOR_NEW(md5) DEFINE_CONSTS_FOR_NEW(sha1) -@@ -92,6 +102,48 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) +@@ -115,6 +125,48 @@ EVP_hash(EVPobject *self, const void *vp } } @@ -349,7 +406,7 @@ index 44765ac..b8cf490 100644 + errstr = ERR_error_string(ERR_peek_last_error(), NULL); + ERR_clear_error(); + -+ return PyUnicode_FromString(errstr); /* Can be NULL */ ++ return PyString_FromString(errstr); /* Can be NULL */ +} + +static void @@ -367,28 +424,27 @@ index 44765ac..b8cf490 100644 /* Internal methods for a hash object */ static void -@@ -259,15 +311,16 @@ EVP_repr(EVPobject *self) +@@ -313,14 +365,15 @@ EVP_repr(PyObject *self) static int EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"name", "string", NULL}; + static char *kwlist[] = {"name", "string", "usedforsecurity", NULL}; PyObject *name_obj = NULL; - PyObject *data_obj = NULL; + int usedforsecurity = 1; - Py_buffer view; + Py_buffer view = { 0 }; char *nameStr; const EVP_MD *digest; -- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:HASH", kwlist, -- &name_obj, &data_obj)) { -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:HASH", kwlist, -+ &name_obj, &data_obj, &usedforsecurity)) { +- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*:HASH", kwlist, +- &name_obj, &view)) { ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*i:HASH", kwlist, ++ &name_obj, &view, &usedforsecurity)) { return -1; } -@@ -288,7 +341,12 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) - PyBuffer_Release(&view); +@@ -336,7 +389,12 @@ EVP_tp_init(EVPobject *self, PyObject *a + PyBuffer_Release(&view); return -1; } - EVP_DigestInit(&self->ctx, digest); @@ -401,7 +457,7 @@ index 44765ac..b8cf490 100644 self->name = name_obj; Py_INCREF(self->name); -@@ -372,7 +430,8 @@ static PyTypeObject EVPtype = { +@@ -420,7 +478,8 @@ static PyTypeObject EVPtype = { static PyObject * EVPnew(PyObject *name_obj, const EVP_MD *digest, const EVP_MD_CTX *initial_ctx, @@ -411,7 +467,7 @@ index 44765ac..b8cf490 100644 { EVPobject *self; -@@ -387,7 +446,12 @@ EVPnew(PyObject *name_obj, +@@ -435,7 +494,12 @@ EVPnew(PyObject *name_obj, if (initial_ctx) { EVP_MD_CTX_copy(&self->ctx, initial_ctx); } else { @@ -425,7 +481,7 @@ index 44765ac..b8cf490 100644 } if (cp && len) { -@@ -411,21 +475,29 @@ PyDoc_STRVAR(EVP_new__doc__, +@@ -459,20 +523,28 @@ PyDoc_STRVAR(EVP_new__doc__, An optional string argument may be provided and will be\n\ automatically hashed.\n\ \n\ @@ -445,32 +501,29 @@ index 44765ac..b8cf490 100644 - static char *kwlist[] = {"name", "string", NULL}; + static char *kwlist[] = {"name", "string", "usedforsecurity", NULL}; PyObject *name_obj = NULL; - PyObject *data_obj = NULL; -+ int usedforsecurity = 1; Py_buffer view = { 0 }; PyObject *ret_obj; char *name; const EVP_MD *digest; ++ int usedforsecurity = 1; -- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|O:new", kwlist, -- &name_obj, &data_obj)) { -+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|Oi:new", kwlist, -+ &name_obj, &data_obj, &usedforsecurity)) { +- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*:new", kwlist, +- &name_obj, &view)) { ++ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*i:new", kwlist, ++ &name_obj, &view, &usedforsecurity)) { return NULL; } -@@ -439,7 +511,8 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) - +@@ -484,58 +556,118 @@ EVP_new(PyObject *self, PyObject *args, digest = EVP_get_digestbyname(name); -- ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len); -+ ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len, -+ usedforsecurity); - - if (data_obj) - PyBuffer_Release(&view); -@@ -722,57 +795,114 @@ generate_hash_name_list(void) + ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, +- view.len); ++ view.len, usedforsecurity); + PyBuffer_Release(&view); + return ret_obj; + } /* - * This macro generates constructor function definitions for specific @@ -486,32 +539,25 @@ index 44765ac..b8cf490 100644 #define GEN_CONSTRUCTOR(NAME) \ static PyObject * \ - EVP_new_ ## NAME (PyObject *self, PyObject *args) \ -+ EVP_new_ ## NAME (PyObject *self, PyObject *args, PyObject *kwdict) \ ++ EVP_new_ ## NAME (PyObject *self, PyObject *args, PyObject *kwdict) \ { \ -- PyObject *data_obj = NULL; \ - Py_buffer view = { 0 }; \ - PyObject *ret_obj; \ - \ -- if (!PyArg_ParseTuple(args, "|O:" #NAME , &data_obj)) { \ +- if (!PyArg_ParseTuple(args, "|s*:" #NAME , &view)) { \ - return NULL; \ - } \ - \ -- if (data_obj) \ -- GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \ -- \ - ret_obj = EVPnew( \ - CONST_ ## NAME ## _name_obj, \ - NULL, \ - CONST_new_ ## NAME ## _ctx_p, \ -- (unsigned char*)view.buf, \ -- view.len); \ -- \ -- if (data_obj) \ -- PyBuffer_Release(&view); \ +- (unsigned char*)view.buf, view.len); \ +- PyBuffer_Release(&view); \ - return ret_obj; \ -+ return implement_specific_EVP_new(self, args, kwdict, \ -+ "|Oi:" #NAME, \ -+ &cached_info_ ## NAME ); \ ++ return implement_specific_EVP_new(self, args, kwdict, \ ++ "|s*i:" #NAME, \ ++ &cached_info_ ## NAME ); \ } +static PyObject * @@ -520,7 +566,6 @@ index 44765ac..b8cf490 100644 + EVPCachedInfo *cached_info) +{ + static char *kwlist[] = {"string", "usedforsecurity", NULL}; -+ PyObject *data_obj = NULL; + Py_buffer view = { 0 }; + int usedforsecurity = 1; + int idx; @@ -529,13 +574,10 @@ index 44765ac..b8cf490 100644 + assert(cached_info); + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, format, kwlist, -+ &data_obj, &usedforsecurity)) { ++ &view, &usedforsecurity)) { + return NULL; + } + -+ if (data_obj) -+ GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); -+ + idx = usedforsecurity ? 1 : 0; + + /* @@ -558,10 +600,9 @@ index 44765ac..b8cf490 100644 + } else { + PyErr_SetString(PyExc_ValueError, "Error initializing hash"); + } -+ } -+ -+ if (data_obj) -+ PyBuffer_Release(&view); ++ } ++ ++ PyBuffer_Release(&view); + + return ret_obj; +} @@ -570,7 +611,7 @@ index 44765ac..b8cf490 100644 #define CONSTRUCTOR_METH_DEF(NAME) \ - {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \ + {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, \ -+ METH_VARARGS|METH_KEYWORDS, \ ++ METH_VARARGS |METH_KEYWORDS, \ PyDoc_STR("Returns a " #NAME \ " hash object; optionally initialized with a string") \ } @@ -579,7 +620,7 @@ index 44765ac..b8cf490 100644 - constructor constants if they haven't been initialized already. */ -#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ - if (CONST_ ## NAME ## _name_obj == NULL) { \ -- CONST_ ## NAME ## _name_obj = PyUnicode_FromString(#NAME); \ +- CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \ - if (EVP_get_digestbyname(#NAME)) { \ - CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \ - EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \ @@ -591,17 +632,18 @@ index 44765ac..b8cf490 100644 + Try to initialize a context for each hash twice, once with + EVP_MD_CTX_FLAG_NON_FIPS_ALLOW and once without. + -+ Any that have errors during initialization will end up with a NULL ctx_ptrs ++ Any that have errors during initialization will end up wit a NULL ctx_ptrs + entry, and err_msgs will be set (unless we're very low on memory) +*/ +#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ + init_constructor_constant(&cached_info_ ## NAME, #NAME); \ } while (0); + +static void +init_constructor_constant(EVPCachedInfo *cached_info, const char *name) +{ + assert(cached_info); -+ cached_info->name_obj = PyUnicode_FromString(name); ++ cached_info->name_obj = PyString_FromString(name); + if (EVP_get_digestbyname(name)) { + int i; + for (i=0; i<2; i++) { @@ -612,29 +654,76 @@ index 44765ac..b8cf490 100644 + cached_info->ctx_ptrs[i] = &cached_info->ctxs[i]; + } else { + /* Failure: */ -+ cached_info->ctx_ptrs[i] = NULL; -+ cached_info->error_msgs[i] = error_msg_for_last_error(); ++ cached_info->ctx_ptrs[i] = NULL; ++ cached_info->error_msgs[i] = error_msg_for_last_error(); + } + } + } +} - ++ GEN_CONSTRUCTOR(md5) GEN_CONSTRUCTOR(sha1) -@@ -819,13 +949,10 @@ PyInit__hashlib(void) + #ifdef _OPENSSL_SUPPORTS_SHA2 +@@ -565,13 +700,10 @@ init_hashlib(void) { - PyObject *m, *openssl_md_meth_names; + PyObject *m; -- OpenSSL_add_all_digests(); -- ERR_load_crypto_strings(); + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_digests(); - /* TODO build EVP_functions openssl_* entries dynamically based - * on what hashes are supported rather than listing many - * but having some be unsupported. Only init appropriate - * constants. */ -+ OpenSSL_add_all_digests(); - +- Py_TYPE(&EVPtype) = &PyType_Type; if (PyType_Ready(&EVPtype) < 0) + return; +diff -up Python-2.7.2/Modules/Setup.dist.hashlib-fips Python-2.7.2/Modules/Setup.dist +--- Python-2.7.2/Modules/Setup.dist.hashlib-fips 2011-09-14 00:21:26.163252001 -0400 ++++ Python-2.7.2/Modules/Setup.dist 2011-09-14 00:21:26.201252001 -0400 +@@ -248,14 +248,14 @@ imageop imageop.c # Operations on images + # Message-Digest Algorithm, described in RFC 1321. The necessary files + # md5.c and md5.h are included here. + +-_md5 md5module.c md5.c ++#_md5 md5module.c md5.c + + + # The _sha module implements the SHA checksum algorithms. + # (NIST's Secure Hash Algorithms.) +-_sha shamodule.c +-_sha256 sha256module.c +-_sha512 sha512module.c ++#_sha shamodule.c ++#_sha256 sha256module.c ++#_sha512 sha512module.c + + + # SGI IRIX specific modules -- off by default. +diff -up Python-2.7.2/setup.py.hashlib-fips Python-2.7.2/setup.py +--- Python-2.7.2/setup.py.hashlib-fips 2011-09-14 00:21:25.722252001 -0400 ++++ Python-2.7.2/setup.py 2011-09-14 00:21:26.203252001 -0400 +@@ -768,21 +768,6 @@ class PyBuildExt(build_ext): + print ("warning: openssl 0x%08x is too old for _hashlib" % + openssl_ver) + missing.append('_hashlib') +- if COMPILED_WITH_PYDEBUG or not have_usable_openssl: +- # The _sha module implements the SHA1 hash algorithm. +- exts.append( Extension('_sha', ['shamodule.c']) ) +- # The _md5 module implements the RSA Data Security, Inc. MD5 +- # Message-Digest Algorithm, described in RFC 1321. The +- # necessary files md5.c and md5.h are included here. +- exts.append( Extension('_md5', +- sources = ['md5module.c', 'md5.c'], +- depends = ['md5.h']) ) +- +- min_sha2_openssl_ver = 0x00908000 +- if COMPILED_WITH_PYDEBUG or openssl_ver < min_sha2_openssl_ver: +- # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash +- exts.append( Extension('_sha256', ['sha256module.c']) ) +- exts.append( Extension('_sha512', ['sha512module.c']) ) + + # Modules that provide persistent dictionary-like semantics. You will + # probably want to arrange for at least one of them to be available on diff --git a/SOURCES/00155-avoid-ctypes-thunks.patch b/SOURCES/00155-avoid-ctypes-thunks.patch index f03890ee..92dd6685 100644 --- a/SOURCES/00155-avoid-ctypes-thunks.patch +++ b/SOURCES/00155-avoid-ctypes-thunks.patch @@ -1,7 +1,7 @@ -diff -up Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 Python-3.2.3/Lib/ctypes/__init__.py ---- Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 15:12:49.017867692 -0400 -+++ Python-3.2.3/Lib/ctypes/__init__.py 2012-04-20 15:15:09.501111408 -0400 -@@ -275,11 +275,6 @@ def _reset_cache(): +diff -up Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 Python-2.7.3/Lib/ctypes/__init__.py +--- Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 14:51:19.390990244 -0400 ++++ Python-2.7.3/Lib/ctypes/__init__.py 2012-04-20 14:51:45.141668316 -0400 +@@ -272,11 +272,6 @@ def _reset_cache(): # _SimpleCData.c_char_p_from_param POINTER(c_char).from_param = c_char_p.from_param _pointer_type_cache[None] = c_void_p @@ -11,5 +11,5 @@ diff -up Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 Python-3.2.3/Lib/ctypes/ - # compiled with the MS SDK compiler. Or an uninitialized variable? - CFUNCTYPE(c_int)(lambda: None) - def create_unicode_buffer(init, size=None): - """create_unicode_buffer(aString) -> character array + try: + from _ctypes import set_conversion_mode diff --git a/SOURCES/00157-uid-gid-overflows.patch b/SOURCES/00157-uid-gid-overflows.patch index 03f3e021..13546bbf 100644 --- a/SOURCES/00157-uid-gid-overflows.patch +++ b/SOURCES/00157-uid-gid-overflows.patch @@ -1,68 +1,49 @@ -diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py -index e9fdb07..ea60e6e 100644 ---- a/Lib/test/test_os.py -+++ b/Lib/test/test_os.py -@@ -1723,30 +1723,36 @@ class PosixUidGidTests(unittest.TestCase): - def test_setuid(self): - if os.getuid() != 0: - self.assertRaises(OSError, os.setuid, 0) -+ self.assertRaises(TypeError, os.setuid, 'not an int') - self.assertRaises(OverflowError, os.setuid, 1<<32) +diff -up Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows Python-2.7.3/Lib/test/test_os.py +--- Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_os.py 2012-06-26 14:51:36.000817929 -0400 +@@ -677,30 +677,36 @@ if sys.platform != 'win32': + def test_setuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setuid, 0) ++ self.assertRaises(TypeError, os.setuid, 'not an int') + self.assertRaises(OverflowError, os.setuid, 1<<32) - @unittest.skipUnless(hasattr(os, 'setgid'), 'test needs os.setgid()') - def test_setgid(self): - if os.getuid() != 0 and not HAVE_WHEEL_GROUP: - self.assertRaises(OSError, os.setgid, 0) -+ self.assertRaises(TypeError, os.setgid, 'not an int') - self.assertRaises(OverflowError, os.setgid, 1<<32) + if hasattr(os, 'setgid'): + def test_setgid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setgid, 0) ++ self.assertRaises(TypeError, os.setgid, 'not an int') + self.assertRaises(OverflowError, os.setgid, 1<<32) - @unittest.skipUnless(hasattr(os, 'seteuid'), 'test needs os.seteuid()') - def test_seteuid(self): - if os.getuid() != 0: - self.assertRaises(OSError, os.seteuid, 0) -+ self.assertRaises(TypeError, os.seteuid, 'not an int') - self.assertRaises(OverflowError, os.seteuid, 1<<32) + if hasattr(os, 'seteuid'): + def test_seteuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.seteuid, 0) ++ self.assertRaises(TypeError, os.seteuid, 'not an int') + self.assertRaises(OverflowError, os.seteuid, 1<<32) - @unittest.skipUnless(hasattr(os, 'setegid'), 'test needs os.setegid()') - def test_setegid(self): - if os.getuid() != 0 and not HAVE_WHEEL_GROUP: - self.assertRaises(OSError, os.setegid, 0) -+ self.assertRaises(TypeError, os.setegid, 'not an int') - self.assertRaises(OverflowError, os.setegid, 1<<32) + if hasattr(os, 'setegid'): + def test_setegid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setegid, 0) ++ self.assertRaises(TypeError, os.setegid, 'not an int') + self.assertRaises(OverflowError, os.setegid, 1<<32) - @unittest.skipUnless(hasattr(os, 'setreuid'), 'test needs os.setreuid()') - def test_setreuid(self): - if os.getuid() != 0: - self.assertRaises(OSError, os.setreuid, 0, 0) -+ self.assertRaises(TypeError, os.setreuid, 'not an int', 0) -+ self.assertRaises(TypeError, os.setreuid, 0, 'not an int') - self.assertRaises(OverflowError, os.setreuid, 1<<32, 0) - self.assertRaises(OverflowError, os.setreuid, 0, 1<<32) + if hasattr(os, 'setreuid'): + def test_setreuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setreuid, 0, 0) ++ self.assertRaises(TypeError, os.setreuid, 'not an int', 0) ++ self.assertRaises(TypeError, os.setreuid, 0, 'not an int') + self.assertRaises(OverflowError, os.setreuid, 1<<32, 0) + self.assertRaises(OverflowError, os.setreuid, 0, 1<<32) -@@ -1762,6 +1768,8 @@ class PosixUidGidTests(unittest.TestCase): - def test_setregid(self): - if os.getuid() != 0 and not HAVE_WHEEL_GROUP: - self.assertRaises(OSError, os.setregid, 0, 0) -+ self.assertRaises(TypeError, os.setregid, 'not an int', 0) -+ self.assertRaises(TypeError, os.setregid, 0, 'not an int') - self.assertRaises(OverflowError, os.setregid, 1<<32, 0) - self.assertRaises(OverflowError, os.setregid, 0, 1<<32) +@@ -715,6 +721,8 @@ if sys.platform != 'win32': + def test_setregid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setregid, 0, 0) ++ self.assertRaises(TypeError, os.setregid, 'not an int', 0) ++ self.assertRaises(TypeError, os.setregid, 0, 'not an int') + self.assertRaises(OverflowError, os.setregid, 1<<32, 0) + self.assertRaises(OverflowError, os.setregid, 0, 1<<32) -diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py -index ac9cff7..db98159 100644 ---- a/Lib/test/test_pwd.py -+++ b/Lib/test/test_pwd.py -@@ -104,11 +104,11 @@ class PwdTest(unittest.TestCase): - # In some cases, byuids isn't a complete list of all users in the - # system, so if we try to pick a value not in byuids (via a perturbing - # loop, say), pwd.getpwuid() might still be able to find data for that -- # uid. Using sys.maxint may provoke the same problems, but hopefully -+ # uid. Using 2**32 - 2 may provoke the same problems, but hopefully - # it will be a more repeatable failure. - # Android accepts a very large span of uids including sys.maxsize and - # -1; it raises KeyError with 1 or 2 for example. -- fakeuid = sys.maxsize -+ fakeuid = 2**32 - 2 - self.assertNotIn(fakeuid, byuids) - if not support.is_android: - self.assertRaises(KeyError, pwd.getpwuid, fakeuid) diff --git a/SOURCES/00170-gc-assertions.patch b/SOURCES/00170-gc-assertions.patch index f4917334..3fb37ff3 100644 --- a/SOURCES/00170-gc-assertions.patch +++ b/SOURCES/00170-gc-assertions.patch @@ -1,92 +1,33 @@ -diff --git a/Include/object.h b/Include/object.h -index 0c88603..e3413e8 100644 ---- a/Include/object.h -+++ b/Include/object.h -@@ -1059,6 +1059,49 @@ PyAPI_FUNC(void) - _PyObject_DebugTypeStats(FILE *out); - #endif /* ifndef Py_LIMITED_API */ - -+/* -+ Define a pair of assertion macros. -+ -+ These work like the regular C assert(), in that they will abort the -+ process with a message on stderr if the given condition fails to hold, -+ but compile away to nothing if NDEBUG is defined. -+ -+ However, before aborting, Python will also try to call _PyObject_Dump() on -+ the given object. This may be of use when investigating bugs in which a -+ particular object is corrupt (e.g. buggy a tp_visit method in an extension -+ module breaking the garbage collector), to help locate the broken objects. -+ -+ The WITH_MSG variant allows you to supply an additional message that Python -+ will attempt to print to stderr, after the object dump. -+*/ -+#ifdef NDEBUG -+/* No debugging: compile away the assertions: */ -+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0) -+#else -+/* With debugging: generate checks: */ -+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \ -+ ((expr) \ -+ ? (void)(0) \ -+ : _PyObject_AssertFailed((obj), \ -+ (msg), \ -+ (__STRING(expr)), \ -+ (__FILE__), \ -+ (__LINE__), \ -+ (__PRETTY_FUNCTION__))) -+#endif -+ -+#define PyObject_ASSERT(obj, expr) \ -+ PyObject_ASSERT_WITH_MSG(obj, expr, NULL) -+ -+/* -+ Declare and define the entrypoint even when NDEBUG is defined, to avoid -+ causing compiler/linker errors when building extensions without NDEBUG -+ against a Python built with NDEBUG defined -+*/ -+PyAPI_FUNC(void) _PyObject_AssertFailed(PyObject *, const char *, -+ const char *, const char *, int, -+ const char *); -+ - #ifdef __cplusplus - } - #endif -diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py -index e727499..6efcafb 100644 ---- a/Lib/test/test_gc.py -+++ b/Lib/test/test_gc.py -@@ -1,10 +1,11 @@ +diff -up Python-2.7.3/Lib/test/test_gc.py.gc-assertions Python-2.7.3/Lib/test/test_gc.py +--- Python-2.7.3/Lib/test/test_gc.py.gc-assertions 2013-02-20 16:28:20.890536607 -0500 ++++ Python-2.7.3/Lib/test/test_gc.py 2013-02-20 16:39:52.720489297 -0500 +@@ -1,6 +1,7 @@ import unittest - from test.support import (verbose, refcount_test, run_unittest, - strip_python_stderr, cpython_only, start_threads, -- temp_dir, requires_type_collecting) -+ temp_dir, import_module, requires_type_collecting) - from test.support.script_helper import assert_python_ok, make_script - +-from test.test_support import verbose, run_unittest ++from test.test_support import verbose, run_unittest, import_module import sys +import sysconfig import time import gc import weakref -@@ -50,6 +51,8 @@ class GC_Detector(object): - # gc collects it. +@@ -32,6 +33,8 @@ class GC_Detector(object): self.wr = weakref.ref(C1055820(666), it_happened) -+BUILD_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS']) + ++BUILT_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS']) + - @with_tp_del - class Uncollectable(object): - """Create a reference cycle with multiple __del__ methods. -@@ -862,6 +865,50 @@ class GCCallbackTests(unittest.TestCase): - self.assertEqual(len(gc.garbage), 0) + ### Tests + ############################################################################### +@@ -476,6 +479,49 @@ class GCTests(unittest.TestCase): + # would be damaged, with an empty __dict__. + self.assertEqual(x, None) -+ @unittest.skipIf(BUILD_WITH_NDEBUG, ++ @unittest.skipIf(BUILT_WITH_NDEBUG, + 'built with -NDEBUG') + def test_refcount_errors(self): -+ self.preclean() + # Verify the "handling" of objects with broken refcounts ++ + import_module("ctypes") #skip if not supported + + import subprocess @@ -112,59 +53,131 @@ index e727499..6efcafb 100644 + p.stdout.close() + p.stderr.close() + # Verify that stderr has a useful error message: -+ self.assertRegex(stderr, -+ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "\(\(gc\)->gc.gc_refs >> \(1\)\) != 0" failed.') -+ self.assertRegex(stderr, ++ self.assertRegexpMatches(stderr, ++ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "gc->gc.gc_refs != 0" failed.') ++ self.assertRegexpMatches(stderr, + b'refcount was too small') -+ self.assertRegex(stderr, ++ self.assertRegexpMatches(stderr, + b'object : \[\]') -+ self.assertRegex(stderr, ++ self.assertRegexpMatches(stderr, + b'type : list') -+ self.assertRegex(stderr, ++ self.assertRegexpMatches(stderr, + b'refcount: 1') -+ self.assertRegex(stderr, ++ self.assertRegexpMatches(stderr, + b'address : 0x[0-9a-f]+') -+ + class GCTogglingTests(unittest.TestCase): def setUp(self): gc.enable() -diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c -index 0c6f444..87edd5a 100644 ---- a/Modules/gcmodule.c -+++ b/Modules/gcmodule.c -@@ -341,7 +341,8 @@ update_refs(PyGC_Head *containers) +diff -up Python-2.7.3/Modules/gcmodule.c.gc-assertions Python-2.7.3/Modules/gcmodule.c +--- Python-2.7.3/Modules/gcmodule.c.gc-assertions 2012-04-09 19:07:34.000000000 -0400 ++++ Python-2.7.3/Modules/gcmodule.c 2013-02-20 16:28:21.029536600 -0500 +@@ -21,6 +21,73 @@ + #include "Python.h" + #include "frameobject.h" /* for PyFrame_ClearFreeList */ + ++/* ++ Define a pair of assertion macros. ++ ++ These work like the regular C assert(), in that they will abort the ++ process with a message on stderr if the given condition fails to hold, ++ but compile away to nothing if NDEBUG is defined. ++ ++ However, before aborting, Python will also try to call _PyObject_Dump() on ++ the given object. This may be of use when investigating bugs in which a ++ particular object is corrupt (e.g. buggy a tp_visit method in an extension ++ module breaking the garbage collector), to help locate the broken objects. ++ ++ The WITH_MSG variant allows you to supply an additional message that Python ++ will attempt to print to stderr, after the object dump. ++*/ ++#ifdef NDEBUG ++/* No debugging: compile away the assertions: */ ++#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0) ++#else ++/* With debugging: generate checks: */ ++#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \ ++ ((expr) \ ++ ? (void)(0) \ ++ : _PyObject_AssertFailed((obj), \ ++ (msg), \ ++ (__STRING(expr)), \ ++ (__FILE__), \ ++ (__LINE__), \ ++ (__PRETTY_FUNCTION__))) ++#endif ++ ++#define PyObject_ASSERT(obj, expr) \ ++ PyObject_ASSERT_WITH_MSG(obj, expr, NULL) ++ ++static void _PyObject_AssertFailed(PyObject *, const char *, ++ const char *, const char *, int, ++ const char *); ++ ++static void ++_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr, ++ const char *file, int line, const char *function) ++{ ++ fprintf(stderr, ++ "%s:%d: %s: Assertion \"%s\" failed.\n", ++ file, line, function, expr); ++ if (msg) { ++ fprintf(stderr, "%s\n", msg); ++ } ++ ++ fflush(stderr); ++ ++ if (obj) { ++ /* This might succeed or fail, but we're about to abort, so at least ++ try to provide any extra info we can: */ ++ _PyObject_Dump(obj); ++ } ++ else { ++ fprintf(stderr, "NULL object\n"); ++ } ++ ++ fflush(stdout); ++ fflush(stderr); ++ ++ /* Terminate the process: */ ++ abort(); ++} ++ + /* Get an object's GC head */ + #define AS_GC(o) ((PyGC_Head *)(o)-1) + +@@ -288,7 +355,8 @@ update_refs(PyGC_Head *containers) { PyGC_Head *gc = containers->gc.gc_next; for (; gc != containers; gc = gc->gc.gc_next) { -- assert(_PyGCHead_REFS(gc) == GC_REACHABLE); +- assert(gc->gc.gc_refs == GC_REACHABLE); + PyObject_ASSERT(FROM_GC(gc), -+ _PyGCHead_REFS(gc) == GC_REACHABLE); - _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); ++ gc->gc.gc_refs == GC_REACHABLE); + gc->gc.gc_refs = Py_REFCNT(FROM_GC(gc)); /* Python's cyclic gc should never see an incoming refcount * of 0: if something decref'ed to 0, it should have been -@@ -361,7 +362,8 @@ update_refs(PyGC_Head *containers) +@@ -308,7 +376,8 @@ update_refs(PyGC_Head *containers) * so serious that maybe this should be a release-build * check instead of an assert? */ -- assert(_PyGCHead_REFS(gc) != 0); +- assert(gc->gc.gc_refs != 0); + PyObject_ASSERT(FROM_GC(gc), -+ _PyGCHead_REFS(gc) != 0); ++ gc->gc.gc_refs != 0); } } -@@ -376,7 +378,9 @@ visit_decref(PyObject *op, void *data) +@@ -323,7 +392,9 @@ visit_decref(PyObject *op, void *data) * generation being collected, which can be recognized * because only they have positive gc_refs. */ -- assert(_PyGCHead_REFS(gc) != 0); /* else refcount was too small */ +- assert(gc->gc.gc_refs != 0); /* else refcount was too small */ + PyObject_ASSERT_WITH_MSG(FROM_GC(gc), -+ _PyGCHead_REFS(gc) != 0, -+ "refcount was too small"); /* else refcount was too small */ - if (_PyGCHead_REFS(gc) > 0) - _PyGCHead_DECREF(gc); ++ gc->gc.gc_refs != 0, ++ "refcount was too small"); + if (gc->gc.gc_refs > 0) + gc->gc.gc_refs--; } -@@ -436,9 +440,10 @@ visit_reachable(PyObject *op, PyGC_Head *reachable) +@@ -383,9 +454,10 @@ visit_reachable(PyObject *op, PyGC_Head * If gc_refs == GC_UNTRACKED, it must be ignored. */ else { @@ -178,25 +191,26 @@ index 0c6f444..87edd5a 100644 } } return 0; -@@ -480,7 +485,7 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) +@@ -427,7 +499,7 @@ move_unreachable(PyGC_Head *young, PyGC_ */ PyObject *op = FROM_GC(gc); traverseproc traverse = Py_TYPE(op)->tp_traverse; -- assert(_PyGCHead_REFS(gc) > 0); -+ PyObject_ASSERT(op, _PyGCHead_REFS(gc) > 0); - _PyGCHead_SET_REFS(gc, GC_REACHABLE); +- assert(gc->gc.gc_refs > 0); ++ PyObject_ASSERT(op, gc->gc.gc_refs > 0); + gc->gc.gc_refs = GC_REACHABLE; (void) traverse(op, (visitproc)visit_reachable, -@@ -543,7 +548,7 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) +@@ -494,7 +566,8 @@ move_finalizers(PyGC_Head *unreachable, for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyObject *op = FROM_GC(gc); - assert(IS_TENTATIVELY_UNREACHABLE(op)); + PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op)); ++ next = gc->gc.gc_next; - if (has_legacy_finalizer(op)) { -@@ -619,7 +624,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) + if (has_finalizer(op)) { +@@ -570,7 +643,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyWeakReference **wrlist; op = FROM_GC(gc); @@ -205,7 +219,7 @@ index 0c6f444..87edd5a 100644 next = gc->gc.gc_next; if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op))) -@@ -640,9 +645,9 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) +@@ -591,9 +664,9 @@ handle_weakrefs(PyGC_Head *unreachable, * the callback pointer intact. Obscure: it also * changes *wrlist. */ @@ -217,7 +231,7 @@ index 0c6f444..87edd5a 100644 if (wr->wr_callback == NULL) continue; /* no callback */ -@@ -676,7 +681,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) +@@ -627,7 +700,7 @@ handle_weakrefs(PyGC_Head *unreachable, */ if (IS_TENTATIVELY_UNREACHABLE(wr)) continue; @@ -226,7 +240,7 @@ index 0c6f444..87edd5a 100644 /* Create a new reference so that wr can't go away * before we can process it again. -@@ -685,7 +690,8 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) +@@ -636,7 +709,8 @@ handle_weakrefs(PyGC_Head *unreachable, /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); @@ -236,7 +250,7 @@ index 0c6f444..87edd5a 100644 next isn't, so they can't be the same */ gc_list_move(wrasgc, &wrcb_to_call); -@@ -701,11 +707,11 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) +@@ -652,11 +726,11 @@ handle_weakrefs(PyGC_Head *unreachable, gc = wrcb_to_call.gc.gc_next; op = FROM_GC(gc); @@ -251,60 +265,12 @@ index 0c6f444..87edd5a 100644 /* copy-paste of weakrefobject.c's handle_callback() */ temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); -@@ -822,12 +828,14 @@ check_garbage(PyGC_Head *collectable) - for (gc = collectable->gc.gc_next; gc != collectable; - gc = gc->gc.gc_next) { - _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); -- assert(_PyGCHead_REFS(gc) != 0); -+ PyObject_ASSERT(FROM_GC(gc), -+ _PyGCHead_REFS(gc) != 0); - } - subtract_refs(collectable); - for (gc = collectable->gc.gc_next; gc != collectable; - gc = gc->gc.gc_next) { -- assert(_PyGCHead_REFS(gc) >= 0); -+ PyObject_ASSERT(FROM_GC(gc), -+ _PyGCHead_REFS(gc) >= 0); - if (_PyGCHead_REFS(gc) != 0) - return -1; - } -diff --git a/Objects/object.c b/Objects/object.c -index 559794f..a47d47f 100644 ---- a/Objects/object.c -+++ b/Objects/object.c -@@ -2022,6 +2022,35 @@ _PyTrash_thread_destroy_chain(void) - } - } +@@ -759,7 +833,7 @@ delete_garbage(PyGC_Head *collectable, P + PyGC_Head *gc = collectable->gc.gc_next; + PyObject *op = FROM_GC(gc); -+PyAPI_FUNC(void) -+_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr, -+ const char *file, int line, const char *function) -+{ -+ fprintf(stderr, -+ "%s:%d: %s: Assertion \"%s\" failed.\n", -+ file, line, function, expr); -+ if (msg) { -+ fprintf(stderr, "%s\n", msg); -+ } -+ -+ fflush(stderr); -+ -+ if (obj) { -+ /* This might succeed or fail, but we're about to abort, so at least -+ try to provide any extra info we can: */ -+ _PyObject_Dump(obj); -+ } -+ else { -+ fprintf(stderr, "NULL object\n"); -+ } -+ -+ fflush(stdout); -+ fflush(stderr); -+ -+ /* Terminate the process: */ -+ abort(); -+} -+ - #ifndef Py_TRACE_REFS - /* For Py_LIMITED_API, we need an out-of-line version of _Py_Dealloc. - Define this here, so we can undefine the macro. */ +- assert(IS_TENTATIVELY_UNREACHABLE(op)); ++ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op)); + if (debug & DEBUG_SAVEALL) { + PyList_Append(garbage, op); + } diff --git a/SOURCES/00180-python-add-support-for-ppc64p7.patch b/SOURCES/00180-python-add-support-for-ppc64p7.patch index 054f9f39..022944a5 100644 --- a/SOURCES/00180-python-add-support-for-ppc64p7.patch +++ b/SOURCES/00180-python-add-support-for-ppc64p7.patch @@ -1,13 +1,12 @@ -diff --git a/config.sub b/config.sub -index 40ea5df..932128b 100755 ---- a/config.sub -+++ b/config.sub -@@ -1045,7 +1045,7 @@ case $basic_machine in +diff -r de35eae9048a config.sub +--- a/config.sub Wed Apr 24 23:33:20 2013 +0200 ++++ b/config.sub Thu Apr 25 08:51:00 2013 +0200 +@@ -1008,7 +1008,7 @@ ;; ppc64) basic_machine=powerpc64-unknown ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little) + ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown diff --git a/SOURCES/00209-pep466-backport-hmac.compare_digest.patch b/SOURCES/00209-pep466-backport-hmac.compare_digest.patch new file mode 100644 index 00000000..cca8afea --- /dev/null +++ b/SOURCES/00209-pep466-backport-hmac.compare_digest.patch @@ -0,0 +1,353 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1399849904 25200 +# Node ID b40f1a00b13460cc089450028280c4e52dd24a64 +# Parent 951775c68b1b7782750c213b0fce1f61d46b2f51 +backport hmac.compare_digest to partially implement PEP 466 (closes #21306) + +Backport from Alex Gaynor. + +diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst +--- a/Doc/library/hmac.rst ++++ b/Doc/library/hmac.rst +@@ -38,6 +38,13 @@ An HMAC object has the following methods + This string will be the same length as the *digest_size* of the digest given to + the constructor. It may contain non-ASCII characters, including NUL bytes. + ++ .. warning:: ++ ++ When comparing the output of :meth:`digest` to an externally-supplied ++ digest during a verification routine, it is recommended to use the ++ :func:`compare_digest` function instead of the ``==`` operator ++ to reduce the vulnerability to timing attacks. ++ + + .. method:: HMAC.hexdigest() + +@@ -45,6 +52,13 @@ An HMAC object has the following methods + containing only hexadecimal digits. This may be used to exchange the value + safely in email or other non-binary environments. + ++ .. warning:: ++ ++ When comparing the output of :meth:`hexdigest` to an externally-supplied ++ digest during a verification routine, it is recommended to use the ++ :func:`compare_digest` function instead of the ``==`` operator ++ to reduce the vulnerability to timing attacks. ++ + + .. method:: HMAC.copy() + +@@ -52,6 +66,25 @@ An HMAC object has the following methods + compute the digests of strings that share a common initial substring. + + ++This module also provides the following helper function: ++ ++.. function:: compare_digest(a, b) ++ ++ Return ``a == b``. This function uses an approach designed to prevent ++ timing analysis by avoiding content-based short circuiting behaviour, ++ making it appropriate for cryptography. *a* and *b* must both be of the ++ same type: either :class:`unicode` or a :term:`bytes-like object`. ++ ++ .. note:: ++ ++ If *a* and *b* are of different lengths, or if an error occurs, ++ a timing attack could theoretically reveal information about the ++ types and lengths of *a* and *b*--but not their values. ++ ++ ++ .. versionadded:: 2.7.7 ++ ++ + .. seealso:: + + Module :mod:`hashlib` +diff --git a/Lib/hmac.py b/Lib/hmac.py +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -5,6 +5,9 @@ Implements the HMAC algorithm as describ + + import warnings as _warnings + ++from operator import _compare_digest as compare_digest ++ ++ + trans_5C = "".join ([chr (x ^ 0x5C) for x in xrange(256)]) + trans_36 = "".join ([chr (x ^ 0x36) for x in xrange(256)]) + +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -302,12 +302,122 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(h1.hexdigest() == h2.hexdigest(), + "Hexdigest of copy doesn't match original hexdigest.") + ++ ++class CompareDigestTestCase(unittest.TestCase): ++ ++ def test_compare_digest(self): ++ # Testing input type exception handling ++ a, b = 100, 200 ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = 100, b"foobar" ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = b"foobar", 200 ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = u"foobar", b"foobar" ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = b"foobar", u"foobar" ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ ++ # Testing bytes of different lengths ++ a, b = b"foobar", b"foo" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ a, b = b"\xde\xad\xbe\xef", b"\xde\xad" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing bytes of same lengths, different values ++ a, b = b"foobar", b"foobaz" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing bytes of same lengths, same values ++ a, b = b"foobar", b"foobar" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ ++ # Testing bytearrays of same lengths, same values ++ a, b = bytearray(b"foobar"), bytearray(b"foobar") ++ self.assertTrue(hmac.compare_digest(a, b)) ++ ++ # Testing bytearrays of diffeent lengths ++ a, b = bytearray(b"foobar"), bytearray(b"foo") ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing bytearrays of same lengths, different values ++ a, b = bytearray(b"foobar"), bytearray(b"foobaz") ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing byte and bytearray of same lengths, same values ++ a, b = bytearray(b"foobar"), b"foobar" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ self.assertTrue(hmac.compare_digest(b, a)) ++ ++ # Testing byte bytearray of diffeent lengths ++ a, b = bytearray(b"foobar"), b"foo" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ self.assertFalse(hmac.compare_digest(b, a)) ++ ++ # Testing byte and bytearray of same lengths, different values ++ a, b = bytearray(b"foobar"), b"foobaz" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ self.assertFalse(hmac.compare_digest(b, a)) ++ ++ # Testing str of same lengths ++ a, b = "foobar", "foobar" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ ++ # Testing str of diffeent lengths ++ a, b = "foo", "foobar" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing bytes of same lengths, different values ++ a, b = "foobar", "foobaz" ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ # Testing error cases ++ a, b = u"foobar", b"foobar" ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = b"foobar", u"foobar" ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = b"foobar", 1 ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = 100, 200 ++ self.assertRaises(TypeError, hmac.compare_digest, a, b) ++ a, b = "fooä", "fooä" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ ++ # subclasses are supported by ignore __eq__ ++ class mystr(str): ++ def __eq__(self, other): ++ return False ++ ++ a, b = mystr("foobar"), mystr("foobar") ++ self.assertTrue(hmac.compare_digest(a, b)) ++ a, b = mystr("foobar"), "foobar" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ a, b = mystr("foobar"), mystr("foobaz") ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ class mybytes(bytes): ++ def __eq__(self, other): ++ return False ++ ++ a, b = mybytes(b"foobar"), mybytes(b"foobar") ++ self.assertTrue(hmac.compare_digest(a, b)) ++ a, b = mybytes(b"foobar"), b"foobar" ++ self.assertTrue(hmac.compare_digest(a, b)) ++ a, b = mybytes(b"foobar"), mybytes(b"foobaz") ++ self.assertFalse(hmac.compare_digest(a, b)) ++ ++ + def test_main(): + test_support.run_unittest( + TestVectorsTestCase, + ConstructorTestCase, + SanityTestCase, +- CopyTestCase ++ CopyTestCase, ++ CompareDigestTestCase, + ) + + if __name__ == "__main__": +diff --git a/Modules/operator.c b/Modules/operator.c +--- a/Modules/operator.c ++++ b/Modules/operator.c +@@ -235,6 +235,132 @@ op_delslice(PyObject *s, PyObject *a) + #define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \ + {#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)}, + ++ ++ ++/* compare_digest **********************************************************/ ++ ++/* ++ * timing safe compare ++ * ++ * Returns 1 of the strings are equal. ++ * In case of len(a) != len(b) the function tries to keep the timing ++ * dependent on the length of b. CPU cache locally may still alter timing ++ * a bit. ++ */ ++static int ++_tscmp(const unsigned char *a, const unsigned char *b, ++ Py_ssize_t len_a, Py_ssize_t len_b) ++{ ++ /* The volatile type declarations make sure that the compiler has no ++ * chance to optimize and fold the code in any way that may change ++ * the timing. ++ */ ++ volatile Py_ssize_t length; ++ volatile const unsigned char *left; ++ volatile const unsigned char *right; ++ Py_ssize_t i; ++ unsigned char result; ++ ++ /* loop count depends on length of b */ ++ length = len_b; ++ left = NULL; ++ right = b; ++ ++ /* don't use else here to keep the amount of CPU instructions constant, ++ * volatile forces re-evaluation ++ * */ ++ if (len_a == length) { ++ left = *((volatile const unsigned char**)&a); ++ result = 0; ++ } ++ if (len_a != length) { ++ left = b; ++ result = 1; ++ } ++ ++ for (i=0; i < length; i++) { ++ result |= *left++ ^ *right++; ++ } ++ ++ return (result == 0); ++} ++ ++PyDoc_STRVAR(compare_digest__doc__, ++"compare_digest(a, b) -> bool\n" ++"\n" ++"Return 'a == b'. This function uses an approach designed to prevent\n" ++"timing analysis, making it appropriate for cryptography.\n" ++"a and b must both be of the same type: either str (ASCII only),\n" ++"or any type that supports the buffer protocol (e.g. bytes).\n" ++"\n" ++"Note: If a and b are of different lengths, or if an error occurs,\n" ++"a timing attack could theoretically reveal information about the\n" ++"types and lengths of a and b--but not their values.\n"); ++ ++static PyObject* ++compare_digest(PyObject *self, PyObject *args) ++{ ++ PyObject *a, *b; ++ int rc; ++ ++ if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) { ++ return NULL; ++ } ++ ++ /* Unicode string */ ++ if (PyUnicode_Check(a) && PyUnicode_Check(b)) { ++ rc = _tscmp(PyUnicode_AS_DATA(a), ++ PyUnicode_AS_DATA(b), ++ PyUnicode_GET_DATA_SIZE(a), ++ PyUnicode_GET_DATA_SIZE(b)); ++ } ++ /* fallback to buffer interface for bytes, bytesarray and other */ ++ else { ++ Py_buffer view_a; ++ Py_buffer view_b; ++ ++ if ((PyObject_CheckBuffer(a) == 0) & (PyObject_CheckBuffer(b) == 0)) { ++ PyErr_Format(PyExc_TypeError, ++ "unsupported operand types(s) or combination of types: " ++ "'%.100s' and '%.100s'", ++ Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); ++ return NULL; ++ } ++ ++ if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) { ++ return NULL; ++ } ++ if (view_a.ndim > 1) { ++ PyErr_SetString(PyExc_BufferError, ++ "Buffer must be single dimension"); ++ PyBuffer_Release(&view_a); ++ return NULL; ++ } ++ ++ if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) { ++ PyBuffer_Release(&view_a); ++ return NULL; ++ } ++ if (view_b.ndim > 1) { ++ PyErr_SetString(PyExc_BufferError, ++ "Buffer must be single dimension"); ++ PyBuffer_Release(&view_a); ++ PyBuffer_Release(&view_b); ++ return NULL; ++ } ++ ++ rc = _tscmp((const unsigned char*)view_a.buf, ++ (const unsigned char*)view_b.buf, ++ view_a.len, ++ view_b.len); ++ ++ PyBuffer_Release(&view_a); ++ PyBuffer_Release(&view_b); ++ } ++ ++ return PyBool_FromLong(rc); ++} ++ + static struct PyMethodDef operator_methods[] = { + + spam1o(isCallable, +@@ -318,6 +444,8 @@ spam2(ne,__ne__, "ne(a, b) -- Same as a! + spam2(gt,__gt__, "gt(a, b) -- Same as a>b.") + spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.") + ++ {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS, ++ compare_digest__doc__}, + {NULL, NULL} /* sentinel */ + + }; + diff --git a/SOURCES/00210-pep466-backport-hashlib.pbkdf2_hmac.patch b/SOURCES/00210-pep466-backport-hashlib.pbkdf2_hmac.patch new file mode 100644 index 00000000..1ef8934e --- /dev/null +++ b/SOURCES/00210-pep466-backport-hashlib.pbkdf2_hmac.patch @@ -0,0 +1,489 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1401567982 25200 +# Node ID e4da3ba9dcac4374ca0ccc46a48c32be6f951038 +# Parent 8fa8c290c165dccd613632b69a816623b51e801e +backport hashlib.pbkdf2_hmac per PEP 466 (closes #21304) + +Backport by Alex Gaynor. + +diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst +--- a/Doc/library/hashlib.rst ++++ b/Doc/library/hashlib.rst +@@ -135,6 +135,46 @@ A hash object has the following methods: + compute the digests of strings that share a common initial substring. + + ++Key Derivation Function ++----------------------- ++ ++Key derivation and key stretching algorithms are designed for secure password ++hashing. Naive algorithms such as ``sha1(password)`` are not resistant against ++brute-force attacks. A good password hashing function must be tunable, slow, and ++include a `salt `_. ++ ++ ++.. function:: pbkdf2_hmac(name, password, salt, rounds, dklen=None) ++ ++ The function provides PKCS#5 password-based key derivation function 2. It ++ uses HMAC as pseudorandom function. ++ ++ The string *name* is the desired name of the hash digest algorithm for ++ HMAC, e.g. 'sha1' or 'sha256'. *password* and *salt* are interpreted as ++ buffers of bytes. Applications and libraries should limit *password* to ++ a sensible value (e.g. 1024). *salt* should be about 16 or more bytes from ++ a proper source, e.g. :func:`os.urandom`. ++ ++ The number of *rounds* should be chosen based on the hash algorithm and ++ computing power. As of 2013, at least 100,000 rounds of SHA-256 is suggested. ++ ++ *dklen* is the length of the derived key. If *dklen* is ``None`` then the ++ digest size of the hash algorithm *name* is used, e.g. 64 for SHA-512. ++ ++ >>> import hashlib, binascii ++ >>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000) ++ >>> binascii.hexlify(dk) ++ b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5' ++ ++ .. versionadded:: 2.7.8 ++ ++ .. note:: ++ ++ A fast implementation of *pbkdf2_hmac* is available with OpenSSL. The ++ Python implementation uses an inline version of :mod:`hmac`. It is about ++ three times slower and doesn't release the GIL. ++ ++ + .. seealso:: + + Module :mod:`hmac` +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -77,7 +77,7 @@ __always_supported = ('md5', 'sha1', 'sh + + algorithms = __always_supported + +-__all__ = __always_supported + ('new', 'algorithms') ++__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac') + + + def __get_openssl_constructor(name): +@@ -123,6 +123,72 @@ for __func_name in __always_supported: + import logging + logging.exception('code for hash %s was not found.', __func_name) + ++try: ++ # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA ++ from _hashlib import pbkdf2_hmac ++except ImportError: ++ import binascii ++ import struct ++ ++ _trans_5C = b"".join(chr(x ^ 0x5C) for x in range(256)) ++ _trans_36 = b"".join(chr(x ^ 0x36) for x in range(256)) ++ ++ def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None): ++ """Password based key derivation function 2 (PKCS #5 v2.0) ++ ++ This Python implementations based on the hmac module about as fast ++ as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster ++ for long passwords. ++ """ ++ if not isinstance(hash_name, str): ++ raise TypeError(hash_name) ++ ++ if not isinstance(password, (bytes, bytearray)): ++ password = bytes(buffer(password)) ++ if not isinstance(salt, (bytes, bytearray)): ++ salt = bytes(buffer(salt)) ++ ++ # Fast inline HMAC implementation ++ inner = new(hash_name) ++ outer = new(hash_name) ++ blocksize = getattr(inner, 'block_size', 64) ++ if len(password) > blocksize: ++ password = new(hash_name, password).digest() ++ password = password + b'\x00' * (blocksize - len(password)) ++ inner.update(password.translate(_trans_36)) ++ outer.update(password.translate(_trans_5C)) ++ ++ def prf(msg, inner=inner, outer=outer): ++ # PBKDF2_HMAC uses the password as key. We can re-use the same ++ # digest objects and and just update copies to skip initialization. ++ icpy = inner.copy() ++ ocpy = outer.copy() ++ icpy.update(msg) ++ ocpy.update(icpy.digest()) ++ return ocpy.digest() ++ ++ if iterations < 1: ++ raise ValueError(iterations) ++ if dklen is None: ++ dklen = outer.digest_size ++ if dklen < 1: ++ raise ValueError(dklen) ++ ++ hex_format_string = "%%0%ix" % (new(hash_name).digest_size * 2) ++ ++ dkey = b'' ++ loop = 1 ++ while len(dkey) < dklen: ++ prev = prf(salt + struct.pack(b'>I', loop)) ++ rkey = int(binascii.hexlify(prev), 16) ++ for i in xrange(iterations - 1): ++ prev = prf(prev) ++ rkey ^= int(binascii.hexlify(prev), 16) ++ loop += 1 ++ dkey += binascii.unhexlify(hex_format_string % rkey) ++ ++ return dkey[:dklen] ++ + # Cleanup locals() + del __always_supported, __func_name, __get_hash + del __hash_new, __get_openssl_constructor +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -16,6 +16,8 @@ except ImportError: + threading = None + import unittest + import warnings ++from binascii import unhexlify ++ + from test import test_support + from test.test_support import _4G, precisionbigmemtest + +@@ -436,8 +438,72 @@ class HashLibTestCase(unittest.TestCase) + + + ++class KDFTests(unittest.TestCase): ++ pbkdf2_test_vectors = [ ++ (b'password', b'salt', 1, None), ++ (b'password', b'salt', 2, None), ++ (b'password', b'salt', 4096, None), ++ # too slow, it takes over a minute on a fast CPU. ++ #(b'password', b'salt', 16777216, None), ++ (b'passwordPASSWORDpassword', b'saltSALTsaltSALTsaltSALTsaltSALTsalt', ++ 4096, -1), ++ (b'pass\0word', b'sa\0lt', 4096, 16), ++ ] ++ ++ pbkdf2_results = { ++ "sha1": [ ++ # offical test vectors from RFC 6070 ++ (unhexlify('0c60c80f961f0e71f3a9b524af6012062fe037a6'), None), ++ (unhexlify('ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'), None), ++ (unhexlify('4b007901b765489abead49d926f721d065a429c1'), None), ++ #(unhexlify('eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'), None), ++ (unhexlify('3d2eec4fe41c849b80c8d83662c0e44a8b291a964c' ++ 'f2f07038'), 25), ++ (unhexlify('56fa6aa75548099dcc37d7f03425e0c3'), None),], ++ "sha256": [ ++ (unhexlify('120fb6cffcf8b32c43e7225256c4f837' ++ 'a86548c92ccc35480805987cb70be17b'), None), ++ (unhexlify('ae4d0c95af6b46d32d0adff928f06dd0' ++ '2a303f8ef3c251dfd6e2d85a95474c43'), None), ++ (unhexlify('c5e478d59288c841aa530db6845c4c8d' ++ '962893a001ce4e11a4963873aa98134a'), None), ++ #(unhexlify('cf81c66fe8cfc04d1f31ecb65dab4089' ++ # 'f7f179e89b3b0bcb17ad10e3ac6eba46'), None), ++ (unhexlify('348c89dbcbd32b2f32d814b8116e84cf2b17' ++ '347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9'), 40), ++ (unhexlify('89b69d0516f829893c696226650a8687'), None),], ++ "sha512": [ ++ (unhexlify('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5' ++ 'd513554e1c8cf252c02d470a285a0501bad999bfe943c08f' ++ '050235d7d68b1da55e63f73b60a57fce'), None), ++ (unhexlify('e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f004071' ++ '3f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82' ++ 'be67335c77a6068e04112754f27ccf4e'), None), ++ (unhexlify('d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f8' ++ '7f6902e072f457b5143f30602641b3d55cd335988cb36b84' ++ '376060ecd532e039b742a239434af2d5'), None), ++ (unhexlify('8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b8' ++ '68c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30' ++ '225c583a186cd82bd4daea9724a3d3b8'), 64), ++ (unhexlify('9d9e9c4cd21fe4be24d5b8244c759665'), None),], ++ } ++ ++ def test_pbkdf2_hmac(self): ++ for digest_name, results in self.pbkdf2_results.items(): ++ for i, vector in enumerate(self.pbkdf2_test_vectors): ++ password, salt, rounds, dklen = vector ++ expected, overwrite_dklen = results[i] ++ if overwrite_dklen: ++ dklen = overwrite_dklen ++ out = hashlib.pbkdf2_hmac( ++ digest_name, password, salt, rounds, dklen) ++ self.assertEqual(out, expected, ++ (digest_name, password, salt, rounds, dklen)) ++ ++ ++ + def test_main(): +- test_support.run_unittest(HashLibTestCase) ++ test_support.run_unittest(HashLibTestCase, KDFTests) + + if __name__ == "__main__": + test_main() +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #define MUNCH_SIZE INT_MAX + +@@ -563,6 +564,226 @@ EVP_new(PyObject *self, PyObject *args, + return ret_obj; + } + ++ ++ ++#if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \ ++ && !defined(OPENSSL_NO_SHA)) ++ ++#define PY_PBKDF2_HMAC 1 ++ ++/* Improved implementation of PKCS5_PBKDF2_HMAC() ++ * ++ * PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of ++ * `iter` times. Today (2013) the iteration count is typically 100,000 or ++ * more. The improved algorithm is not subject to a Denial-of-Service ++ * vulnerability with overly large passwords. ++ * ++ * Also OpenSSL < 1.0 don't provide PKCS5_PBKDF2_HMAC(), only ++ * PKCS5_PBKDF2_SHA1. ++ */ ++static int ++PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen, ++ const unsigned char *salt, int saltlen, ++ int iter, const EVP_MD *digest, ++ int keylen, unsigned char *out) ++{ ++ unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; ++ int cplen, j, k, tkeylen, mdlen; ++ unsigned long i = 1; ++ HMAC_CTX hctx_tpl, hctx; ++ ++ mdlen = EVP_MD_size(digest); ++ if (mdlen < 0) ++ return 0; ++ ++ HMAC_CTX_init(&hctx_tpl); ++ HMAC_CTX_init(&hctx); ++ p = out; ++ tkeylen = keylen; ++ if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL)) { ++ HMAC_CTX_cleanup(&hctx_tpl); ++ return 0; ++ } ++ while(tkeylen) { ++ if(tkeylen > mdlen) ++ cplen = mdlen; ++ else ++ cplen = tkeylen; ++ /* We are unlikely to ever use more than 256 blocks (5120 bits!) ++ * but just in case... ++ */ ++ itmp[0] = (unsigned char)((i >> 24) & 0xff); ++ itmp[1] = (unsigned char)((i >> 16) & 0xff); ++ itmp[2] = (unsigned char)((i >> 8) & 0xff); ++ itmp[3] = (unsigned char)(i & 0xff); ++ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { ++ HMAC_CTX_cleanup(&hctx_tpl); ++ return 0; ++ } ++ if (!HMAC_Update(&hctx, salt, saltlen) ++ || !HMAC_Update(&hctx, itmp, 4) ++ || !HMAC_Final(&hctx, digtmp, NULL)) { ++ HMAC_CTX_cleanup(&hctx_tpl); ++ HMAC_CTX_cleanup(&hctx); ++ return 0; ++ } ++ HMAC_CTX_cleanup(&hctx); ++ memcpy(p, digtmp, cplen); ++ for (j = 1; j < iter; j++) { ++ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { ++ HMAC_CTX_cleanup(&hctx_tpl); ++ return 0; ++ } ++ if (!HMAC_Update(&hctx, digtmp, mdlen) ++ || !HMAC_Final(&hctx, digtmp, NULL)) { ++ HMAC_CTX_cleanup(&hctx_tpl); ++ HMAC_CTX_cleanup(&hctx); ++ return 0; ++ } ++ HMAC_CTX_cleanup(&hctx); ++ for (k = 0; k < cplen; k++) { ++ p[k] ^= digtmp[k]; ++ } ++ } ++ tkeylen-= cplen; ++ i++; ++ p+= cplen; ++ } ++ HMAC_CTX_cleanup(&hctx_tpl); ++ return 1; ++} ++ ++/* LCOV_EXCL_START */ ++static PyObject * ++_setException(PyObject *exc) ++{ ++ unsigned long errcode; ++ const char *lib, *func, *reason; ++ ++ errcode = ERR_peek_last_error(); ++ if (!errcode) { ++ PyErr_SetString(exc, "unknown reasons"); ++ return NULL; ++ } ++ ERR_clear_error(); ++ ++ lib = ERR_lib_error_string(errcode); ++ func = ERR_func_error_string(errcode); ++ reason = ERR_reason_error_string(errcode); ++ ++ if (lib && func) { ++ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); ++ } ++ else if (lib) { ++ PyErr_Format(exc, "[%s] %s", lib, reason); ++ } ++ else { ++ PyErr_SetString(exc, reason); ++ } ++ return NULL; ++} ++/* LCOV_EXCL_STOP */ ++ ++PyDoc_STRVAR(pbkdf2_hmac__doc__, ++"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key\n\ ++\n\ ++Password based key derivation function 2 (PKCS #5 v2.0) with HMAC as\n\ ++pseudorandom function."); ++ ++static PyObject * ++pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict) ++{ ++ static char *kwlist[] = {"hash_name", "password", "salt", "iterations", ++ "dklen", NULL}; ++ PyObject *key_obj = NULL, *dklen_obj = Py_None; ++ char *name, *key; ++ Py_buffer password, salt; ++ long iterations, dklen; ++ int retval; ++ const EVP_MD *digest; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ss*s*l|O:pbkdf2_hmac", ++ kwlist, &name, &password, &salt, ++ &iterations, &dklen_obj)) { ++ return NULL; ++ } ++ ++ digest = EVP_get_digestbyname(name); ++ if (digest == NULL) { ++ PyErr_SetString(PyExc_ValueError, "unsupported hash type"); ++ goto end; ++ } ++ ++ if (password.len > INT_MAX) { ++ PyErr_SetString(PyExc_OverflowError, ++ "password is too long."); ++ goto end; ++ } ++ ++ if (salt.len > INT_MAX) { ++ PyErr_SetString(PyExc_OverflowError, ++ "salt is too long."); ++ goto end; ++ } ++ ++ if (iterations < 1) { ++ PyErr_SetString(PyExc_ValueError, ++ "iteration value must be greater than 0."); ++ goto end; ++ } ++ if (iterations > INT_MAX) { ++ PyErr_SetString(PyExc_OverflowError, ++ "iteration value is too great."); ++ goto end; ++ } ++ ++ if (dklen_obj == Py_None) { ++ dklen = EVP_MD_size(digest); ++ } else { ++ dklen = PyLong_AsLong(dklen_obj); ++ if ((dklen == -1) && PyErr_Occurred()) { ++ goto end; ++ } ++ } ++ if (dklen < 1) { ++ PyErr_SetString(PyExc_ValueError, ++ "key length must be greater than 0."); ++ goto end; ++ } ++ if (dklen > INT_MAX) { ++ /* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */ ++ PyErr_SetString(PyExc_OverflowError, ++ "key length is too great."); ++ goto end; ++ } ++ ++ key_obj = PyBytes_FromStringAndSize(NULL, dklen); ++ if (key_obj == NULL) { ++ goto end; ++ } ++ key = PyBytes_AS_STRING(key_obj); ++ ++ Py_BEGIN_ALLOW_THREADS ++ retval = PKCS5_PBKDF2_HMAC_fast((char*)password.buf, (int)password.len, ++ (unsigned char *)salt.buf, (int)salt.len, ++ iterations, digest, dklen, ++ (unsigned char *)key); ++ Py_END_ALLOW_THREADS ++ ++ if (!retval) { ++ Py_CLEAR(key_obj); ++ _setException(PyExc_ValueError); ++ goto end; ++ } ++ ++ end: ++ PyBuffer_Release(&password); ++ PyBuffer_Release(&salt); ++ return key_obj; ++} ++ ++#endif ++ + /* + * This macro and function generates a family of constructor function + * definitions for specific hash algorithms. These constructors are much +@@ -690,6 +911,10 @@ static struct PyMethodDef EVP_functions[ + CONSTRUCTOR_METH_DEF(sha384), + CONSTRUCTOR_METH_DEF(sha512), + #endif ++#ifdef PY_PBKDF2_HMAC ++ {"pbkdf2_hmac", (PyCFunction)pbkdf2_hmac, METH_VARARGS|METH_KEYWORDS, ++ pbkdf2_hmac__doc__}, ++#endif + {NULL, NULL} /* Sentinel */ + }; + +diff -up Python-2.7.5/Lib/test/test_hmac.py.cod Python-2.7.5/Lib/test/test_hmac.py +--- Python-2.7.5/Lib/test/test_hmac.py.cod 2015-02-23 10:37:13.448594606 +0100 ++++ Python-2.7.5/Lib/test/test_hmac.py 2015-02-23 10:37:27.581717509 +0100 +@@ -1,3 +1,5 @@ ++# coding: utf-8 ++ + import hmac + import hashlib + import unittest diff --git a/SOURCES/00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch b/SOURCES/00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch new file mode 100644 index 00000000..c6ea78e9 --- /dev/null +++ b/SOURCES/00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch @@ -0,0 +1,67 @@ + +# HG changeset patch +# User Serhiy Storchaka +# Date 1382204269 -10800 +# Node ID 214c0aac7540947d88a38ff0061734547ef86710 +# Parent c207ac413457a1b834e4b7dcf1a6836cd6e036e3 +Issue #19279: UTF-7 decoder no more produces illegal unicode strings. + +diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py +--- a/Lib/test/test_codecs.py ++++ b/Lib/test/test_codecs.py +@@ -611,6 +611,35 @@ class UTF7Test(ReadTest): + ] + ) + ++ def test_errors(self): ++ tests = [ ++ ('a\xffb', u'a\ufffdb'), ++ ('a+IK', u'a\ufffd'), ++ ('a+IK-b', u'a\ufffdb'), ++ ('a+IK,b', u'a\ufffdb'), ++ ('a+IKx', u'a\u20ac\ufffd'), ++ ('a+IKx-b', u'a\u20ac\ufffdb'), ++ ('a+IKwgr', u'a\u20ac\ufffd'), ++ ('a+IKwgr-b', u'a\u20ac\ufffdb'), ++ ('a+IKwgr,', u'a\u20ac\ufffd'), ++ ('a+IKwgr,-b', u'a\u20ac\ufffd-b'), ++ ('a+IKwgrB', u'a\u20ac\u20ac\ufffd'), ++ ('a+IKwgrB-b', u'a\u20ac\u20ac\ufffdb'), ++ ('a+/,+IKw-b', u'a\ufffd\u20acb'), ++ ('a+//,+IKw-b', u'a\ufffd\u20acb'), ++ ('a+///,+IKw-b', u'a\uffff\ufffd\u20acb'), ++ ('a+////,+IKw-b', u'a\uffff\ufffd\u20acb'), ++ ] ++ for raw, expected in tests: ++ self.assertRaises(UnicodeDecodeError, codecs.utf_7_decode, ++ raw, 'strict', True) ++ self.assertEqual(raw.decode('utf-7', 'replace'), expected) ++ ++ def test_nonbmp(self): ++ self.assertEqual(u'\U000104A0'.encode(self.encoding), '+2AHcoA-') ++ self.assertEqual(u'\ud801\udca0'.encode(self.encoding), '+2AHcoA-') ++ self.assertEqual('+2AHcoA-'.decode(self.encoding), u'\U000104A0') ++ + class UTF16ExTest(unittest.TestCase): + + def test_errors(self): +diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c +--- a/Objects/unicodeobject.c ++++ b/Objects/unicodeobject.c +@@ -1671,6 +1671,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c + (base64buffer >> (base64bits-16)); + base64bits -= 16; + base64buffer &= (1 << base64bits) - 1; /* clear high bits */ ++ assert(outCh <= 0xffff); + if (surrogate) { + /* expecting a second surrogate */ + if (outCh >= 0xDC00 && outCh <= 0xDFFF) { +@@ -1737,6 +1738,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c + inShift = 1; + shiftOutStart = p; + base64bits = 0; ++ base64buffer = 0; + } + } + else if (DECODE_DIRECT(ch)) { /* character decodes as itself */ + diff --git a/SOURCES/00212-pep466-pyunicode_fromformat-raise-overflow.patch b/SOURCES/00212-pep466-pyunicode_fromformat-raise-overflow.patch new file mode 100644 index 00000000..a05dd006 --- /dev/null +++ b/SOURCES/00212-pep466-pyunicode_fromformat-raise-overflow.patch @@ -0,0 +1,40 @@ + +# HG changeset patch +# User Serhiy Storchaka +# Date 1372008129 -10800 +# Node ID 2f1e8b7fa534b147280fdc9b92e44a7c7305338a +# Parent 8f0adcb66633ee97e4f7bdeee2104268113b86c3 +Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise +OverflowError when an argument of %c format is out of range. + +diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c +--- a/Objects/unicodeobject.c ++++ b/Objects/unicodeobject.c +@@ -740,8 +740,25 @@ PyUnicode_FromFormatV(const char *format + + switch (*f) { + case 'c': +- (void)va_arg(count, int); ++ { ++ int ordinal = va_arg(count, int); ++#ifdef Py_UNICODE_WIDE ++ if (ordinal < 0 || ordinal > 0x10ffff) { ++ PyErr_SetString(PyExc_OverflowError, ++ "%c arg not in range(0x110000) " ++ "(wide Python build)"); ++ goto fail; ++ } ++#else ++ if (ordinal < 0 || ordinal > 0xffff) { ++ PyErr_SetString(PyExc_OverflowError, ++ "%c arg not in range(0x10000) " ++ "(narrow Python build)"); ++ goto fail; ++ } ++#endif + /* fall through... */ ++ } + case '%': + n++; + break; + diff --git a/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch b/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch new file mode 100644 index 00000000..b3262605 --- /dev/null +++ b/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch @@ -0,0 +1,176 @@ + +# HG changeset patch +# User Victor Stinner +# Date 1406673545 -7200 +# Node ID 263701e0b77e3160bc6a835087f838bd6b24092a +# Parent 6c47c6d2033e20e9b35f1d22e0e797961d6e680f +Issue #22023: Fix %S, %R and %V formats of PyUnicode_FromFormat(). + +diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c +--- a/Objects/unicodeobject.c ++++ b/Objects/unicodeobject.c +@@ -690,7 +690,12 @@ makefmt(char *fmt, int longflag, int siz + *fmt = '\0'; + } + +-#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;} ++#define appendstring(string) \ ++ do { \ ++ for (copy = string;*copy; copy++) { \ ++ *s++ = (unsigned char)*copy; \ ++ } \ ++ } while (0) + + PyObject * + PyUnicode_FromFormatV(const char *format, va_list vargs) +@@ -845,7 +850,7 @@ PyUnicode_FromFormatV(const char *format + str = PyObject_Str(obj); + if (!str) + goto fail; +- n += PyUnicode_GET_SIZE(str); ++ n += PyString_GET_SIZE(str); + /* Remember the str and switch to the next slot */ + *callresult++ = str; + break; +@@ -1006,15 +1011,10 @@ PyUnicode_FromFormatV(const char *format + case 'S': + case 'R': + { +- Py_UNICODE *ucopy; +- Py_ssize_t usize; +- Py_ssize_t upos; ++ const char *str = PyString_AS_STRING(*callresult); + /* unused, since we already have the result */ + (void) va_arg(vargs, PyObject *); +- ucopy = PyUnicode_AS_UNICODE(*callresult); +- usize = PyUnicode_GET_SIZE(*callresult); +- for (upos = 0; upos forget it */ + Py_DECREF(*callresult); + /* switch to next unicode()/repr() result */ + +diff -up Python-2.7.5/Lib/test/test_unicode.py.uni Python-2.7.5/Lib/test/test_unicode.py +--- Python-2.7.5/Lib/test/test_unicode.py.uni 2015-02-24 13:37:01.704739438 +0100 ++++ Python-2.7.5/Lib/test/test_unicode.py 2015-02-24 13:38:38.439482167 +0100 +@@ -1633,6 +1633,119 @@ class UnicodeTest( + self.assertEqual("%s" % u, u'__unicode__ overridden') + self.assertEqual("{}".format(u), '__unicode__ overridden') + ++ # Test PyUnicode_FromFormat() ++ def test_from_format(self): ++ test_support.import_module('ctypes') ++ from ctypes import ( ++ pythonapi, py_object, sizeof, ++ c_int, c_long, c_longlong, c_ssize_t, ++ c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) ++ if sys.maxunicode == 0xffff: ++ name = "PyUnicodeUCS2_FromFormat" ++ else: ++ name = "PyUnicodeUCS4_FromFormat" ++ _PyUnicode_FromFormat = getattr(pythonapi, name) ++ _PyUnicode_FromFormat.restype = py_object ++ ++ def PyUnicode_FromFormat(format, *args): ++ cargs = tuple( ++ py_object(arg) if isinstance(arg, unicode) else arg ++ for arg in args) ++ return _PyUnicode_FromFormat(format, *cargs) ++ ++ def check_format(expected, format, *args): ++ text = PyUnicode_FromFormat(format, *args) ++ self.assertEqual(expected, text) ++ ++ # ascii format, non-ascii argument ++ check_format(u'ascii\x7f=unicode\xe9', ++ b'ascii\x7f=%U', u'unicode\xe9') ++ ++ # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV() ++ # raises an error ++ #self.assertRaisesRegex(ValueError, ++ # '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format ' ++ # 'string, got a non-ASCII byte: 0xe9$', ++ # PyUnicode_FromFormat, b'unicode\xe9=%s', u'ascii') ++ ++ # test "%c" ++ check_format(u'\uabcd', ++ b'%c', c_int(0xabcd)) ++ if sys.maxunicode > 0xffff: ++ check_format(u'\U0010ffff', ++ b'%c', c_int(0x10ffff)) ++ with self.assertRaises(OverflowError): ++ PyUnicode_FromFormat(b'%c', c_int(0x110000)) ++ # Issue #18183 ++ if sys.maxunicode > 0xffff: ++ check_format(u'\U00010000\U00100000', ++ b'%c%c', c_int(0x10000), c_int(0x100000)) ++ ++ # test "%" ++ check_format(u'%', ++ b'%') ++ check_format(u'%', ++ b'%%') ++ check_format(u'%s', ++ b'%%s') ++ check_format(u'[%]', ++ b'[%%]') ++ check_format(u'%abc', ++ b'%%%s', b'abc') ++ ++ # test %S ++ check_format(u"repr=abc", ++ b'repr=%S', u'abc') ++ ++ # test %R ++ check_format(u"repr=u'abc'", ++ b'repr=%R', u'abc') ++ ++ # test integer formats (%i, %d, %u) ++ check_format(u'010', ++ b'%03i', c_int(10)) ++ check_format(u'0010', ++ b'%0.4i', c_int(10)) ++ check_format(u'-123', ++ b'%i', c_int(-123)) ++ ++ check_format(u'-123', ++ b'%d', c_int(-123)) ++ check_format(u'-123', ++ b'%ld', c_long(-123)) ++ check_format(u'-123', ++ b'%zd', c_ssize_t(-123)) ++ ++ check_format(u'123', ++ b'%u', c_uint(123)) ++ check_format(u'123', ++ b'%lu', c_ulong(123)) ++ check_format(u'123', ++ b'%zu', c_size_t(123)) ++ ++ # test long output ++ PyUnicode_FromFormat(b'%p', c_void_p(-1)) ++ ++ # test %V ++ check_format(u'repr=abc', ++ b'repr=%V', u'abc', b'xyz') ++ check_format(u'repr=\xe4\xba\xba\xe6\xb0\x91', ++ b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91') ++ check_format(u'repr=abc\xff', ++ b'repr=%V', None, b'abc\xff') ++ ++ # not supported: copy the raw format string. these tests are just here ++ # to check for crashs and should not be considered as specifications ++ check_format(u'%s', ++ b'%1%s', b'abc') ++ check_format(u'%1abc', ++ b'%1abc') ++ check_format(u'%+i', ++ b'%+i', c_int(10)) ++ check_format(u'%s', ++ b'%.%s', b'abc') ++ ++ + def test_encode_decimal(self): + from _testcapi import unicode_encodedecimal + self.assertEqual(unicode_encodedecimal(u'123'), diff --git a/SOURCES/00214-pep466-backport-py3-ssl-changes.patch b/SOURCES/00214-pep466-backport-py3-ssl-changes.patch new file mode 100644 index 00000000..960eb0da --- /dev/null +++ b/SOURCES/00214-pep466-backport-py3-ssl-changes.patch @@ -0,0 +1,13082 @@ +# HG changeset patch +# User Benjamin Peterson +# Date 1408562090 18000 +# Node ID 221a1f9155e2a8b4d12015261b83a2ce3a0c62a2 +# Parent c1edc4e43eb103254c5d96f1708542623fe08f17 +backport many ssl features from Python 3 (closes #21308) + +A contribution of Alex Gaynor and David Reid with the generous support of +Rackspace. May God have mercy on their souls. + +diff -up Python-2.7.5/Lib/ssl.py.rev Python-2.7.5/Lib/ssl.py +--- Python-2.7.5/Lib/ssl.py.rev 2015-03-03 11:11:56.743921122 +0100 ++++ Python-2.7.5/Lib/ssl.py 2015-03-03 11:18:11.829704572 +0100 +@@ -89,6 +89,7 @@ else: + + from socket import socket, _fileobject, _delegate_methods, error as socket_error + from socket import getnameinfo as _getnameinfo ++from socket import SOL_SOCKET, SO_TYPE, SOCK_STREAM + import base64 # for DER-to-PEM translation + import errno + +@@ -108,6 +109,10 @@ class SSLSocket(socket): + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, ciphers=None): ++ # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get ++ # mixed in. ++ if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: ++ raise NotImplementedError("only stream sockets are supported") + socket.__init__(self, _sock=sock._sock) + # The initializer for socket overrides the methods send(), recv(), etc. + # in the instancce, which we don't need -- but we want to provide the +diff -up Python-2.7.5/Lib/test/test_ssl.py.rev Python-2.7.5/Lib/test/test_ssl.py +diff -up Python-2.7.5/Modules/_ssl.c.rev Python-2.7.5/Modules/_ssl.c +--- Python-2.7.5/Modules/_ssl.c.rev 2015-03-03 10:37:10.331849242 +0100 ++++ Python-2.7.5/Modules/_ssl.c 2015-03-03 11:11:09.324442807 +0100 +@@ -281,6 +281,7 @@ newPySSLObject(PySocketSockObject *Sock, + self->ssl = NULL; + self->ctx = NULL; + self->Socket = NULL; ++ self->shutdown_seen_zero = 0; + + /* Make sure the SSL error state is initialized */ + (void) ERR_get_state(); +@@ -686,7 +687,7 @@ _get_peer_alt_names (X509 *certificate) + + int i, j; + PyObject *peer_alt_names = Py_None; +- PyObject *v, *t; ++ PyObject *v = NULL, *t; + X509_EXTENSION *ext = NULL; + GENERAL_NAMES *names = NULL; + GENERAL_NAME *name; +@@ -745,7 +746,7 @@ _get_peer_alt_names (X509 *certificate) + ASN1_STRING *as = NULL; + + name = sk_GENERAL_NAME_value(names, j); +- gntype = name-> type; ++ gntype = name->type; + switch (gntype) { + case GEN_DIRNAME: + +@@ -781,15 +782,15 @@ _get_peer_alt_names (X509 *certificate) + goto fail; + switch (gntype) { + case GEN_EMAIL: +- v = PyUnicode_FromString("email"); ++ v = PyString_FromString("email"); + as = name->d.rfc822Name; + break; + case GEN_DNS: +- v = PyUnicode_FromString("DNS"); ++ v = PyString_FromString("DNS"); + as = name->d.dNSName; + break; + case GEN_URI: +- v = PyUnicode_FromString("URI"); ++ v = PyString_FromString("URI"); + as = name->d.uniformResourceIdentifier; + break; + } +@@ -819,7 +820,7 @@ _get_peer_alt_names (X509 *certificate) + break; + default: + if (PyErr_Warn(PyExc_RuntimeWarning, +- "Unknown general name type") == -1) { ++ "Unknown general name type") == -1) { + goto fail; + } + break; +@@ -849,7 +850,7 @@ _get_peer_alt_names (X509 *certificate) + goto fail; + } + PyTuple_SET_ITEM(t, 1, v); +- break; ++ break; + } + + /* and add that rendering to the list */ +@@ -1248,6 +1249,12 @@ static PyObject *PySSL_SSLwrite(PySSLObj + if (!PyArg_ParseTuple(args, "s*:write", &buf)) + return NULL; + ++ if (buf.len > INT_MAX) { ++ PyErr_Format(PyExc_OverflowError, ++ "string longer than %d bytes", INT_MAX); ++ goto error; ++ } ++ + /* just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); +@@ -1269,7 +1276,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj + } + do { + PySSL_BEGIN_ALLOW_THREADS +- len = SSL_write(self->ssl, buf.buf, buf.len); ++ len = SSL_write(self->ssl, buf.buf, (int)buf.len); + err = SSL_get_error(self->ssl, len); + PySSL_END_ALLOW_THREADS + if (PyErr_CheckSignals()) { +@@ -1451,7 +1458,7 @@ static PyObject *PySSL_SSLshutdown(PySSL + * Otherwise OpenSSL might read in too much data, + * eating clear text data that happens to be + * transmitted after the SSL shutdown. +- * Should be safe to call repeatedly everytime this ++ * Should be safe to call repeatedly every time this + * function is used and the shutdown_seen_zero != 0 + * condition is met. + */ +@@ -1615,9 +1622,9 @@ PyDoc_STRVAR(PySSL_RAND_egd_doc, + \n\ + Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ + Returns number of bytes read. Raises SSLError if connection to EGD\n\ +-fails or if it does provide enough data to seed PRNG."); ++fails or if it does not provide enough data to seed PRNG."); + +-#endif ++#endif /* HAVE_OPENSSL_RAND */ + + /* List of functions exported by this module. */ + +diff -up Python-2.7.5/Modules/_ssl.c.ssl2 Python-2.7.5/Modules/_ssl.c +--- Python-2.7.5/Modules/_ssl.c.ssl2 2015-03-03 15:48:56.112889298 +0100 ++++ Python-2.7.5/Modules/_ssl.c 2015-03-03 15:47:21.598870012 +0100 +@@ -14,20 +14,26 @@ + http://bugs.python.org/issue8108#msg102867 ? + */ + ++#define PY_SSIZE_T_CLEAN + #include "Python.h" + + #ifdef WITH_THREAD + #include "pythread.h" ++#define PySSL_BEGIN_ALLOW_THREADS_S(save) \ ++ do { if (_ssl_locks_count>0) { (save) = PyEval_SaveThread(); } } while (0) ++#define PySSL_END_ALLOW_THREADS_S(save) \ ++ do { if (_ssl_locks_count>0) { PyEval_RestoreThread(save); } } while (0) + #define PySSL_BEGIN_ALLOW_THREADS { \ + PyThreadState *_save = NULL; \ +- if (_ssl_locks_count>0) {_save = PyEval_SaveThread();} +-#define PySSL_BLOCK_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save)}; +-#define PySSL_UNBLOCK_THREADS if (_ssl_locks_count>0){_save = PyEval_SaveThread()}; +-#define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \ +- } ++ PySSL_BEGIN_ALLOW_THREADS_S(_save); ++#define PySSL_BLOCK_THREADS PySSL_END_ALLOW_THREADS_S(_save); ++#define PySSL_UNBLOCK_THREADS PySSL_BEGIN_ALLOW_THREADS_S(_save); ++#define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); } + + #else /* no WITH_THREAD */ + ++#define PySSL_BEGIN_ALLOW_THREADS_S(save) ++#define PySSL_END_ALLOW_THREADS_S(save) + #define PySSL_BEGIN_ALLOW_THREADS + #define PySSL_BLOCK_THREADS + #define PySSL_UNBLOCK_THREADS +@@ -35,6 +41,68 @@ + + #endif + ++/* Include symbols from _socket module */ ++#include "socketmodule.h" ++ ++#if defined(HAVE_POLL_H) ++#include ++#elif defined(HAVE_SYS_POLL_H) ++#include ++#endif ++ ++/* Include OpenSSL header files */ ++#include "openssl/rsa.h" ++#include "openssl/crypto.h" ++#include "openssl/x509.h" ++#include "openssl/x509v3.h" ++#include "openssl/pem.h" ++#include "openssl/ssl.h" ++#include "openssl/err.h" ++#include "openssl/rand.h" ++ ++/* SSL error object */ ++static PyObject *PySSLErrorObject; ++static PyObject *PySSLZeroReturnErrorObject; ++static PyObject *PySSLWantReadErrorObject; ++static PyObject *PySSLWantWriteErrorObject; ++static PyObject *PySSLSyscallErrorObject; ++static PyObject *PySSLEOFErrorObject; ++ ++/* Error mappings */ ++static PyObject *err_codes_to_names; ++static PyObject *err_names_to_codes; ++static PyObject *lib_codes_to_names; ++ ++struct py_ssl_error_code { ++ const char *mnemonic; ++ int library, reason; ++}; ++struct py_ssl_library_code { ++ const char *library; ++ int code; ++}; ++ ++/* Include generated data (error codes) */ ++#include "_ssl_data.h" ++ ++/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1 ++ http://www.openssl.org/news/changelog.html ++ */ ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L ++# define HAVE_TLSv1_2 1 ++#else ++# define HAVE_TLSv1_2 0 ++#endif ++ ++/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f ++ * This includes the SSL_set_SSL_CTX() function. ++ */ ++#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ++# define HAVE_SNI 1 ++#else ++# define HAVE_SNI 0 ++#endif ++ + enum py_ssl_error { + /* these mirror ssl.h */ + PY_SSL_ERROR_NONE, +@@ -47,6 +115,7 @@ enum py_ssl_error { + PY_SSL_ERROR_WANT_CONNECT, + /* start of non ssl.h errorcodes */ + PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */ ++ PY_SSL_ERROR_NO_SOCKET, /* socket has been GC'd */ + PY_SSL_ERROR_INVALID_ERROR_CODE + }; + +@@ -62,35 +131,17 @@ enum py_ssl_cert_requirements { + }; + + enum py_ssl_version { +-#ifndef OPENSSL_NO_SSL2 + PY_SSL_VERSION_SSL2, +-#endif + PY_SSL_VERSION_SSL3=1, + PY_SSL_VERSION_SSL23, ++#if HAVE_TLSv1_2 ++ PY_SSL_VERSION_TLS1, ++ PY_SSL_VERSION_TLS1_1, ++ PY_SSL_VERSION_TLS1_2 ++#else + PY_SSL_VERSION_TLS1 +-}; +- +-/* Include symbols from _socket module */ +-#include "socketmodule.h" +- +-#if defined(HAVE_POLL_H) +-#include +-#elif defined(HAVE_SYS_POLL_H) +-#include + #endif +- +-/* Include OpenSSL header files */ +-#include "openssl/rsa.h" +-#include "openssl/crypto.h" +-#include "openssl/x509.h" +-#include "openssl/x509v3.h" +-#include "openssl/pem.h" +-#include "openssl/ssl.h" +-#include "openssl/err.h" +-#include "openssl/rand.h" +- +-/* SSL error object */ +-static PyObject *PySSLErrorObject; ++}; + + #ifdef WITH_THREAD + +@@ -112,27 +163,79 @@ static unsigned int _ssl_locks_count = 0 + # undef HAVE_OPENSSL_RAND + #endif + ++/* SSL_CTX_clear_options() and SSL_clear_options() were first added in ++ * OpenSSL 0.9.8m but do not appear in some 0.9.9-dev versions such the ++ * 0.9.9 from "May 2008" that NetBSD 5.0 uses. */ ++#if OPENSSL_VERSION_NUMBER >= 0x009080dfL && OPENSSL_VERSION_NUMBER != 0x00909000L ++# define HAVE_SSL_CTX_CLEAR_OPTIONS ++#else ++# undef HAVE_SSL_CTX_CLEAR_OPTIONS ++#endif ++ ++/* In case of 'tls-unique' it will be 12 bytes for TLS, 36 bytes for ++ * older SSL, but let's be safe */ ++#define PySSL_CB_MAXLEN 128 ++ ++/* SSL_get_finished got added to OpenSSL in 0.9.5 */ ++#if OPENSSL_VERSION_NUMBER >= 0x0090500fL ++# define HAVE_OPENSSL_FINISHED 1 ++#else ++# define HAVE_OPENSSL_FINISHED 0 ++#endif ++ ++/* ECDH support got added to OpenSSL in 0.9.8 */ ++#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_ECDH) ++# define OPENSSL_NO_ECDH ++#endif ++ ++/* compression support got added to OpenSSL in 0.9.8 */ ++#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_COMP) ++# define OPENSSL_NO_COMP ++#endif ++ ++/* X509_VERIFY_PARAM got added to OpenSSL in 0.9.8 */ ++#if OPENSSL_VERSION_NUMBER >= 0x0090800fL ++# define HAVE_OPENSSL_VERIFY_PARAM ++#endif ++ ++ ++typedef struct { ++ PyObject_HEAD ++ SSL_CTX *ctx; ++#ifdef OPENSSL_NPN_NEGOTIATED ++ char *npn_protocols; ++ int npn_protocols_len; ++#endif ++#ifndef OPENSSL_NO_TLSEXT ++ PyObject *set_hostname; ++#endif ++ int check_hostname; ++} PySSLContext; ++ + typedef struct { + PyObject_HEAD +- PySocketSockObject *Socket; /* Socket on which we're layered */ +- SSL_CTX* ctx; +- SSL* ssl; +- X509* peer_cert; +- char server[X509_NAME_MAXLEN]; +- char issuer[X509_NAME_MAXLEN]; +- int shutdown_seen_zero; +- +-} PySSLObject; +- +-static PyTypeObject PySSL_Type; +-static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); +-static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); ++ PySocketSockObject *Socket; ++ PyObject *ssl_sock; ++ SSL *ssl; ++ PySSLContext *ctx; /* weakref to SSL context */ ++ X509 *peer_cert; ++ char shutdown_seen_zero; ++ char handshake_done; ++ enum py_ssl_server_or_client socket_type; ++} PySSLSocket; ++ ++static PyTypeObject PySSLContext_Type; ++static PyTypeObject PySSLSocket_Type; ++ ++static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args); ++static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args); + static int check_socket_and_wait_for_timeout(PySocketSockObject *s, + int writing); +-static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); +-static PyObject *PySSL_cipher(PySSLObject *self); ++static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args); ++static PyObject *PySSL_cipher(PySSLSocket *self); + +-#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) ++#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type) ++#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type) + + typedef enum { + SOCKET_IS_NONBLOCKING, +@@ -149,36 +252,140 @@ typedef enum { + #define ERRSTR1(x,y,z) (x ":" y ": " z) + #define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x) + +-/* XXX It might be helpful to augment the error message generated +- below with the name of the SSL function that generated the error. +- I expect it's obvious most of the time. +-*/ ++ ++/* ++ * SSL errors. ++ */ ++ ++PyDoc_STRVAR(SSLError_doc, ++"An error occurred in the SSL implementation."); ++ ++PyDoc_STRVAR(SSLZeroReturnError_doc, ++"SSL/TLS session closed cleanly."); ++ ++PyDoc_STRVAR(SSLWantReadError_doc, ++"Non-blocking SSL socket needs to read more data\n" ++"before the requested operation can be completed."); ++ ++PyDoc_STRVAR(SSLWantWriteError_doc, ++"Non-blocking SSL socket needs to write more data\n" ++"before the requested operation can be completed."); ++ ++PyDoc_STRVAR(SSLSyscallError_doc, ++"System error when attempting SSL operation."); ++ ++PyDoc_STRVAR(SSLEOFError_doc, ++"SSL/TLS connection terminated abruptly."); ++ + + static PyObject * +-PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno) ++SSLError_str(PyEnvironmentErrorObject *self) + { +- PyObject *v; +- char buf[2048]; +- char *errstr; ++ if (self->strerror != NULL) { ++ Py_INCREF(self->strerror); ++ return self->strerror; ++ } ++ else ++ return PyObject_Str(self->args); ++} ++ ++static void ++fill_and_set_sslerror(PyObject *type, int ssl_errno, const char *errstr, ++ int lineno, unsigned long errcode) ++{ ++ PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL; ++ PyObject *init_value, *msg, *key; ++ ++ if (errcode != 0) { ++ int lib, reason; ++ ++ lib = ERR_GET_LIB(errcode); ++ reason = ERR_GET_REASON(errcode); ++ key = Py_BuildValue("ii", lib, reason); ++ if (key == NULL) ++ goto fail; ++ reason_obj = PyDict_GetItem(err_codes_to_names, key); ++ Py_DECREF(key); ++ if (reason_obj == NULL) { ++ /* XXX if reason < 100, it might reflect a library number (!!) */ ++ PyErr_Clear(); ++ } ++ key = PyLong_FromLong(lib); ++ if (key == NULL) ++ goto fail; ++ lib_obj = PyDict_GetItem(lib_codes_to_names, key); ++ Py_DECREF(key); ++ if (lib_obj == NULL) { ++ PyErr_Clear(); ++ } ++ if (errstr == NULL) ++ errstr = ERR_reason_error_string(errcode); ++ } ++ if (errstr == NULL) ++ errstr = "unknown error"; ++ ++ if (reason_obj && lib_obj) ++ msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)", ++ lib_obj, reason_obj, errstr, lineno); ++ else if (lib_obj) ++ msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)", ++ lib_obj, errstr, lineno); ++ else ++ msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno); ++ if (msg == NULL) ++ goto fail; ++ ++ init_value = Py_BuildValue("iN", ssl_errno, msg); ++ if (init_value == NULL) ++ goto fail; ++ ++ err_value = PyObject_CallObject(type, init_value); ++ Py_DECREF(init_value); ++ if (err_value == NULL) ++ goto fail; ++ ++ if (reason_obj == NULL) ++ reason_obj = Py_None; ++ if (PyObject_SetAttrString(err_value, "reason", reason_obj)) ++ goto fail; ++ if (lib_obj == NULL) ++ lib_obj = Py_None; ++ if (PyObject_SetAttrString(err_value, "library", lib_obj)) ++ goto fail; ++ PyErr_SetObject(type, err_value); ++fail: ++ Py_XDECREF(err_value); ++} ++ ++static PyObject * ++PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno) ++{ ++ PyObject *type = PySSLErrorObject; ++ char *errstr = NULL; + int err; + enum py_ssl_error p = PY_SSL_ERROR_NONE; ++ unsigned long e = 0; + + assert(ret <= 0); ++ e = ERR_peek_last_error(); + + if (obj->ssl != NULL) { + err = SSL_get_error(obj->ssl, ret); + + switch (err) { + case SSL_ERROR_ZERO_RETURN: +- errstr = "TLS/SSL connection has been closed"; ++ errstr = "TLS/SSL connection has been closed (EOF)"; ++ type = PySSLZeroReturnErrorObject; + p = PY_SSL_ERROR_ZERO_RETURN; + break; + case SSL_ERROR_WANT_READ: + errstr = "The operation did not complete (read)"; ++ type = PySSLWantReadErrorObject; + p = PY_SSL_ERROR_WANT_READ; + break; + case SSL_ERROR_WANT_WRITE: + p = PY_SSL_ERROR_WANT_WRITE; ++ type = PySSLWantWriteErrorObject; + errstr = "The operation did not complete (write)"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: +@@ -191,210 +398,109 @@ PySSL_SetError(PySSLObject *obj, int ret + break; + case SSL_ERROR_SYSCALL: + { +- unsigned long e = ERR_get_error(); + if (e == 0) { +- if (ret == 0 || !obj->Socket) { ++ PySocketSockObject *s = obj->Socket; ++ if (ret == 0) { + p = PY_SSL_ERROR_EOF; ++ type = PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } else if (ret == -1) { + /* underlying BIO reported an I/O error */ ++ Py_INCREF(s); + ERR_clear_error(); +- return obj->Socket->errorhandler(); ++ s->errorhandler(); ++ Py_DECREF(s); ++ return NULL; + } else { /* possible? */ + p = PY_SSL_ERROR_SYSCALL; ++ type = PySSLSyscallErrorObject; + errstr = "Some I/O error occurred"; + } + } else { + p = PY_SSL_ERROR_SYSCALL; +- /* XXX Protected by global interpreter lock */ +- errstr = ERR_error_string(e, NULL); + } + break; + } + case SSL_ERROR_SSL: + { +- unsigned long e = ERR_get_error(); + p = PY_SSL_ERROR_SSL; +- if (e != 0) +- /* XXX Protected by global interpreter lock */ +- errstr = ERR_error_string(e, NULL); +- else { /* possible? */ ++ if (e == 0) ++ /* possible? */ + errstr = "A failure in the SSL library occurred"; +- } + break; + } + default: + p = PY_SSL_ERROR_INVALID_ERROR_CODE; + errstr = "Invalid error code"; + } +- } else { +- errstr = ERR_error_string(ERR_peek_last_error(), NULL); + } +- PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); ++ fill_and_set_sslerror(type, p, errstr, lineno, e); + ERR_clear_error(); +- v = Py_BuildValue("(is)", p, buf); +- if (v != NULL) { +- PyErr_SetObject(PySSLErrorObject, v); +- Py_DECREF(v); +- } + return NULL; + } + + static PyObject * + _setSSLError (char *errstr, int errcode, char *filename, int lineno) { + +- char buf[2048]; +- PyObject *v; +- +- if (errstr == NULL) { ++ if (errstr == NULL) + errcode = ERR_peek_last_error(); +- errstr = ERR_error_string(errcode, NULL); +- } +- PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); ++ else ++ errcode = 0; ++ fill_and_set_sslerror(PySSLErrorObject, errcode, errstr, lineno, errcode); + ERR_clear_error(); +- v = Py_BuildValue("(is)", errcode, buf); +- if (v != NULL) { +- PyErr_SetObject(PySSLErrorObject, v); +- Py_DECREF(v); +- } + return NULL; + } + +-static PySSLObject * +-newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, ++/* ++ * SSL objects ++ */ ++ ++static PySSLSocket * ++newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, + enum py_ssl_server_or_client socket_type, +- enum py_ssl_cert_requirements certreq, +- enum py_ssl_version proto_version, +- char *cacerts_file, char *ciphers) ++ char *server_hostname, PyObject *ssl_sock) + { +- PySSLObject *self; +- char *errstr = NULL; +- int ret; +- int verification_mode; ++ PySSLSocket *self; ++ SSL_CTX *ctx = sslctx->ctx; ++ long mode; + +- self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ ++ self = PyObject_New(PySSLSocket, &PySSLSocket_Type); + if (self == NULL) + return NULL; +- memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); +- memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); ++ + self->peer_cert = NULL; + self->ssl = NULL; +- self->ctx = NULL; + self->Socket = NULL; ++ self->ssl_sock = NULL; ++ self->ctx = sslctx; + self->shutdown_seen_zero = 0; ++ self->handshake_done = 0; ++ Py_INCREF(sslctx); + + /* Make sure the SSL error state is initialized */ + (void) ERR_get_state(); + ERR_clear_error(); + +- if ((key_file && !cert_file) || (!key_file && cert_file)) { +- errstr = ERRSTR("Both the key & certificate files " +- "must be specified"); +- goto fail; +- } +- +- if ((socket_type == PY_SSL_SERVER) && +- ((key_file == NULL) || (cert_file == NULL))) { +- errstr = ERRSTR("Both the key & certificate files " +- "must be specified for server-side operation"); +- goto fail; +- } +- +- PySSL_BEGIN_ALLOW_THREADS +- if (proto_version == PY_SSL_VERSION_TLS1) +- self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ +- else if (proto_version == PY_SSL_VERSION_SSL3) +- self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ +-#ifndef OPENSSL_NO_SSL2 +- else if (proto_version == PY_SSL_VERSION_SSL2) +- self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ +-#endif +- else if (proto_version == PY_SSL_VERSION_SSL23) +- self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ +- PySSL_END_ALLOW_THREADS +- +- if (self->ctx == NULL) { +- errstr = ERRSTR("Invalid SSL protocol variant specified."); +- goto fail; +- } +- +- if (ciphers != NULL) { +- ret = SSL_CTX_set_cipher_list(self->ctx, ciphers); +- if (ret == 0) { +- errstr = ERRSTR("No cipher can be selected."); +- goto fail; +- } +- } +- +- if (certreq != PY_SSL_CERT_NONE) { +- if (cacerts_file == NULL) { +- errstr = ERRSTR("No root certificates specified for " +- "verification of other-side certificates."); +- goto fail; +- } else { +- PySSL_BEGIN_ALLOW_THREADS +- ret = SSL_CTX_load_verify_locations(self->ctx, +- cacerts_file, +- NULL); +- PySSL_END_ALLOW_THREADS +- if (ret != 1) { +- _setSSLError(NULL, 0, __FILE__, __LINE__); +- goto fail; +- } +- } +- } +- if (key_file) { +- PySSL_BEGIN_ALLOW_THREADS +- ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, +- SSL_FILETYPE_PEM); +- PySSL_END_ALLOW_THREADS +- if (ret != 1) { +- _setSSLError(NULL, ret, __FILE__, __LINE__); +- goto fail; +- } +- +- PySSL_BEGIN_ALLOW_THREADS +- ret = SSL_CTX_use_certificate_chain_file(self->ctx, +- cert_file); +- PySSL_END_ALLOW_THREADS +- if (ret != 1) { +- /* +- fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n", +- ret, ERR_peek_error(), ERR_peek_last_error(), cert_file); +- */ +- if (ERR_peek_last_error() != 0) { +- _setSSLError(NULL, ret, __FILE__, __LINE__); +- goto fail; +- } +- } +- } +- +- /* ssl compatibility */ +- SSL_CTX_set_options(self->ctx, +- SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); +- +- verification_mode = SSL_VERIFY_NONE; +- if (certreq == PY_SSL_CERT_OPTIONAL) +- verification_mode = SSL_VERIFY_PEER; +- else if (certreq == PY_SSL_CERT_REQUIRED) +- verification_mode = (SSL_VERIFY_PEER | +- SSL_VERIFY_FAIL_IF_NO_PEER_CERT); +- SSL_CTX_set_verify(self->ctx, verification_mode, +- NULL); /* set verify lvl */ +- + PySSL_BEGIN_ALLOW_THREADS +- self->ssl = SSL_new(self->ctx); /* New ssl struct */ ++ self->ssl = SSL_new(ctx); + PySSL_END_ALLOW_THREADS +- SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ ++ SSL_set_app_data(self->ssl,self); ++ SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int)); ++ mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; + #ifdef SSL_MODE_AUTO_RETRY +- SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); ++ mode |= SSL_MODE_AUTO_RETRY; ++#endif ++ SSL_set_mode(self->ssl, mode); ++ ++#if HAVE_SNI ++ if (server_hostname != NULL) ++ SSL_set_tlsext_host_name(self->ssl, server_hostname); + #endif + + /* If the socket is in non-blocking mode or timeout mode, set the BIO + * to non-blocking mode (blocking is the default) + */ +- if (Sock->sock_timeout >= 0.0) { +- /* Set both the read and write BIO's to non-blocking mode */ ++ if (sock->sock_timeout >= 0.0) { + BIO_set_nbio(SSL_get_rbio(self->ssl), 1); + BIO_set_nbio(SSL_get_wbio(self->ssl), 1); + } +@@ -406,65 +512,31 @@ newPySSLObject(PySocketSockObject *Sock, + SSL_set_accept_state(self->ssl); + PySSL_END_ALLOW_THREADS + +- self->Socket = Sock; ++ self->socket_type = socket_type; ++ self->Socket = sock; + Py_INCREF(self->Socket); ++ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); ++ if (self->ssl_sock == NULL) { ++ Py_DECREF(self); ++ return NULL; ++ } + return self; +- fail: +- if (errstr) +- PyErr_SetString(PySSLErrorObject, errstr); +- Py_DECREF(self); +- return NULL; + } + +-static PyObject * +-PySSL_sslwrap(PyObject *self, PyObject *args) +-{ +- PySocketSockObject *Sock; +- int server_side = 0; +- int verification_mode = PY_SSL_CERT_NONE; +- int protocol = PY_SSL_VERSION_SSL23; +- char *key_file = NULL; +- char *cert_file = NULL; +- char *cacerts_file = NULL; +- char *ciphers = NULL; +- +- if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap", +- PySocketModule.Sock_Type, +- &Sock, +- &server_side, +- &key_file, &cert_file, +- &verification_mode, &protocol, +- &cacerts_file, &ciphers)) +- return NULL; +- +- /* +- fprintf(stderr, +- "server_side is %d, keyfile %p, certfile %p, verify_mode %d, " +- "protocol %d, certs %p\n", +- server_side, key_file, cert_file, verification_mode, +- protocol, cacerts_file); +- */ +- +- return (PyObject *) newPySSLObject(Sock, key_file, cert_file, +- server_side, verification_mode, +- protocol, cacerts_file, +- ciphers); +-} +- +-PyDoc_STRVAR(ssl_doc, +-"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n" +-" cacertsfile, ciphers]) -> sslobject"); + + /* SSL object methods */ + +-static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) ++static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) + { + int ret; + int err; + int sockstate, nonblocking; ++ PySocketSockObject *sock = self->Socket; ++ ++ Py_INCREF(sock); + + /* just in case the blocking state of the socket has been changed */ +- nonblocking = (self->Socket->sock_timeout >= 0.0); ++ nonblocking = (sock->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + +@@ -475,60 +547,48 @@ static PyObject *PySSL_SSLdo_handshake(P + ret = SSL_do_handshake(self->ssl); + err = SSL_get_error(self->ssl, ret); + PySSL_END_ALLOW_THREADS +- if(PyErr_CheckSignals()) { +- return NULL; +- } ++ if (PyErr_CheckSignals()) ++ goto error; + if (err == SSL_ERROR_WANT_READ) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ++ sockstate = check_socket_and_wait_for_timeout(sock, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ++ sockstate = check_socket_and_wait_for_timeout(sock, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("The handshake operation timed out")); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("Underlying socket has been closed.")); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("Underlying socket too large for select().")); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); ++ Py_DECREF(sock); + if (ret < 1) + return PySSL_SetError(self, ret, __FILE__, __LINE__); + + if (self->peer_cert) + X509_free (self->peer_cert); + PySSL_BEGIN_ALLOW_THREADS +- if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) { +- X509_NAME_oneline(X509_get_subject_name(self->peer_cert), +- self->server, X509_NAME_MAXLEN); +- X509_NAME_oneline(X509_get_issuer_name(self->peer_cert), +- self->issuer, X509_NAME_MAXLEN); +- } ++ self->peer_cert = SSL_get_peer_certificate(self->ssl); + PySSL_END_ALLOW_THREADS ++ self->handshake_done = 1; + + Py_INCREF(Py_None); + return Py_None; +-} +- +-static PyObject * +-PySSL_server(PySSLObject *self) +-{ +- return PyString_FromString(self->server); +-} + +-static PyObject * +-PySSL_issuer(PySSLObject *self) +-{ +- return PyString_FromString(self->issuer); ++error: ++ Py_DECREF(sock); ++ return NULL; + } + + static PyObject * +@@ -634,8 +694,8 @@ _create_tuple_for_X509_NAME (X509_NAME * + /* + fprintf(stderr, "RDN level %d, attribute %s: %s\n", + entry->set, +- PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)), +- PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1))); ++ PyBytes_AS_STRING(PyTuple_GET_ITEM(attr, 0)), ++ PyBytes_AS_STRING(PyTuple_GET_ITEM(attr, 1))); + */ + if (attr == NULL) + goto fail1; +@@ -722,21 +782,24 @@ _get_peer_alt_names (X509 *certificate) + /* now decode the altName */ + ext = X509_get_ext(certificate, i); + if(!(method = X509V3_EXT_get(ext))) { +- PyErr_SetString(PySSLErrorObject, +- ERRSTR("No method for internalizing subjectAltName!")); ++ PyErr_SetString ++ (PySSLErrorObject, ++ ERRSTR("No method for internalizing subjectAltName!")); + goto fail; + } + + p = ext->value->data; + if (method->it) +- names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, +- &p, +- ext->value->length, +- ASN1_ITEM_ptr(method->it))); ++ names = (GENERAL_NAMES*) ++ (ASN1_item_d2i(NULL, ++ &p, ++ ext->value->length, ++ ASN1_ITEM_ptr(method->it))); + else +- names = (GENERAL_NAMES*) (method->d2i(NULL, +- &p, +- ext->value->length)); ++ names = (GENERAL_NAMES*) ++ (method->d2i(NULL, ++ &p, ++ ext->value->length)); + + for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { + +@@ -885,7 +948,127 @@ _get_peer_alt_names (X509 *certificate) + } + + static PyObject * +-_decode_certificate (X509 *certificate, int verbose) { ++_get_aia_uri(X509 *certificate, int nid) { ++ PyObject *lst = NULL, *ostr = NULL; ++ int i, result; ++ AUTHORITY_INFO_ACCESS *info; ++ ++ info = X509_get_ext_d2i(certificate, NID_info_access, NULL, NULL); ++ if ((info == NULL) || (sk_ACCESS_DESCRIPTION_num(info) == 0)) { ++ return Py_None; ++ } ++ ++ if ((lst = PyList_New(0)) == NULL) { ++ goto fail; ++ } ++ ++ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { ++ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); ++ ASN1_IA5STRING *uri; ++ ++ if ((OBJ_obj2nid(ad->method) != nid) || ++ (ad->location->type != GEN_URI)) { ++ continue; ++ } ++ uri = ad->location->d.uniformResourceIdentifier; ++ ostr = PyUnicode_FromStringAndSize((char *)uri->data, ++ uri->length); ++ if (ostr == NULL) { ++ goto fail; ++ } ++ result = PyList_Append(lst, ostr); ++ Py_DECREF(ostr); ++ if (result < 0) { ++ goto fail; ++ } ++ } ++ AUTHORITY_INFO_ACCESS_free(info); ++ ++ /* convert to tuple or None */ ++ if (PyList_Size(lst) == 0) { ++ Py_DECREF(lst); ++ return Py_None; ++ } else { ++ PyObject *tup; ++ tup = PyList_AsTuple(lst); ++ Py_DECREF(lst); ++ return tup; ++ } ++ ++ fail: ++ AUTHORITY_INFO_ACCESS_free(info); ++ Py_XDECREF(lst); ++ return NULL; ++} ++ ++static PyObject * ++_get_crl_dp(X509 *certificate) { ++ STACK_OF(DIST_POINT) *dps; ++ int i, j, result; ++ PyObject *lst; ++ ++#if OPENSSL_VERSION_NUMBER < 0x10001000L ++ dps = X509_get_ext_d2i(certificate, NID_crl_distribution_points, ++ NULL, NULL); ++#else ++ /* Calls x509v3_cache_extensions and sets up crldp */ ++ X509_check_ca(certificate); ++ dps = certificate->crldp; ++#endif ++ ++ if (dps == NULL) { ++ return Py_None; ++ } ++ ++ if ((lst = PyList_New(0)) == NULL) { ++ return NULL; ++ } ++ ++ for (i=0; i < sk_DIST_POINT_num(dps); i++) { ++ DIST_POINT *dp; ++ STACK_OF(GENERAL_NAME) *gns; ++ ++ dp = sk_DIST_POINT_value(dps, i); ++ gns = dp->distpoint->name.fullname; ++ ++ for (j=0; j < sk_GENERAL_NAME_num(gns); j++) { ++ GENERAL_NAME *gn; ++ ASN1_IA5STRING *uri; ++ PyObject *ouri; ++ ++ gn = sk_GENERAL_NAME_value(gns, j); ++ if (gn->type != GEN_URI) { ++ continue; ++ } ++ uri = gn->d.uniformResourceIdentifier; ++ ouri = PyUnicode_FromStringAndSize((char *)uri->data, ++ uri->length); ++ if (ouri == NULL) { ++ Py_DECREF(lst); ++ return NULL; ++ } ++ result = PyList_Append(lst, ouri); ++ Py_DECREF(ouri); ++ if (result < 0) { ++ Py_DECREF(lst); ++ return NULL; ++ } ++ } ++ } ++ /* convert to tuple or None */ ++ if (PyList_Size(lst) == 0) { ++ Py_DECREF(lst); ++ return Py_None; ++ } else { ++ PyObject *tup; ++ tup = PyList_AsTuple(lst); ++ Py_DECREF(lst); ++ return tup; ++ } ++} ++ ++static PyObject * ++_decode_certificate(X509 *certificate) { + + PyObject *retval = NULL; + BIO *biobuf = NULL; +@@ -894,9 +1077,10 @@ _decode_certificate (X509 *certificate, + PyObject *issuer; + PyObject *version; + PyObject *sn_obj; ++ PyObject *obj; + ASN1_INTEGER *serialNumber; + char buf[2048]; +- int len; ++ int len, result; + ASN1_TIME *notBefore, *notAfter; + PyObject *pnotBefore, *pnotAfter; + +@@ -914,65 +1098,62 @@ _decode_certificate (X509 *certificate, + } + Py_DECREF(peer); + +- if (verbose) { +- issuer = _create_tuple_for_X509_NAME( +- X509_get_issuer_name(certificate)); +- if (issuer == NULL) +- goto fail0; +- if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) { +- Py_DECREF(issuer); +- goto fail0; +- } ++ issuer = _create_tuple_for_X509_NAME( ++ X509_get_issuer_name(certificate)); ++ if (issuer == NULL) ++ goto fail0; ++ if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) { + Py_DECREF(issuer); ++ goto fail0; ++ } ++ Py_DECREF(issuer); + +- version = PyInt_FromLong(X509_get_version(certificate) + 1); +- if (PyDict_SetItemString(retval, "version", version) < 0) { +- Py_DECREF(version); +- goto fail0; +- } ++ version = PyLong_FromLong(X509_get_version(certificate) + 1); ++ if (version == NULL) ++ goto fail0; ++ if (PyDict_SetItemString(retval, "version", version) < 0) { + Py_DECREF(version); ++ goto fail0; + } ++ Py_DECREF(version); + + /* get a memory buffer */ + biobuf = BIO_new(BIO_s_mem()); + +- if (verbose) { +- +- (void) BIO_reset(biobuf); +- serialNumber = X509_get_serialNumber(certificate); +- /* should not exceed 20 octets, 160 bits, so buf is big enough */ +- i2a_ASN1_INTEGER(biobuf, serialNumber); +- len = BIO_gets(biobuf, buf, sizeof(buf)-1); +- if (len < 0) { +- _setSSLError(NULL, 0, __FILE__, __LINE__); +- goto fail1; +- } +- sn_obj = PyString_FromStringAndSize(buf, len); +- if (sn_obj == NULL) +- goto fail1; +- if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) { +- Py_DECREF(sn_obj); +- goto fail1; +- } ++ (void) BIO_reset(biobuf); ++ serialNumber = X509_get_serialNumber(certificate); ++ /* should not exceed 20 octets, 160 bits, so buf is big enough */ ++ i2a_ASN1_INTEGER(biobuf, serialNumber); ++ len = BIO_gets(biobuf, buf, sizeof(buf)-1); ++ if (len < 0) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ goto fail1; ++ } ++ sn_obj = PyUnicode_FromStringAndSize(buf, len); ++ if (sn_obj == NULL) ++ goto fail1; ++ if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) { + Py_DECREF(sn_obj); ++ goto fail1; ++ } ++ Py_DECREF(sn_obj); + +- (void) BIO_reset(biobuf); +- notBefore = X509_get_notBefore(certificate); +- ASN1_TIME_print(biobuf, notBefore); +- len = BIO_gets(biobuf, buf, sizeof(buf)-1); +- if (len < 0) { +- _setSSLError(NULL, 0, __FILE__, __LINE__); +- goto fail1; +- } +- pnotBefore = PyString_FromStringAndSize(buf, len); +- if (pnotBefore == NULL) +- goto fail1; +- if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) { +- Py_DECREF(pnotBefore); +- goto fail1; +- } ++ (void) BIO_reset(biobuf); ++ notBefore = X509_get_notBefore(certificate); ++ ASN1_TIME_print(biobuf, notBefore); ++ len = BIO_gets(biobuf, buf, sizeof(buf)-1); ++ if (len < 0) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ goto fail1; ++ } ++ pnotBefore = PyUnicode_FromStringAndSize(buf, len); ++ if (pnotBefore == NULL) ++ goto fail1; ++ if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) { + Py_DECREF(pnotBefore); ++ goto fail1; + } ++ Py_DECREF(pnotBefore); + + (void) BIO_reset(biobuf); + notAfter = X509_get_notAfter(certificate); +@@ -1005,6 +1186,41 @@ _decode_certificate (X509 *certificate, + Py_DECREF(peer_alt_names); + } + ++ /* Authority Information Access: OCSP URIs */ ++ obj = _get_aia_uri(certificate, NID_ad_OCSP); ++ if (obj == NULL) { ++ goto fail1; ++ } else if (obj != Py_None) { ++ result = PyDict_SetItemString(retval, "OCSP", obj); ++ Py_DECREF(obj); ++ if (result < 0) { ++ goto fail1; ++ } ++ } ++ ++ obj = _get_aia_uri(certificate, NID_ad_ca_issuers); ++ if (obj == NULL) { ++ goto fail1; ++ } else if (obj != Py_None) { ++ result = PyDict_SetItemString(retval, "caIssuers", obj); ++ Py_DECREF(obj); ++ if (result < 0) { ++ goto fail1; ++ } ++ } ++ ++ /* CDP (CRL distribution points) */ ++ obj = _get_crl_dp(certificate); ++ if (obj == NULL) { ++ goto fail1; ++ } else if (obj != Py_None) { ++ result = PyDict_SetItemString(retval, "crlDistributionPoints", obj); ++ Py_DECREF(obj); ++ if (result < 0) { ++ goto fail1; ++ } ++ } ++ + BIO_free(biobuf); + return retval; + +@@ -1016,6 +1232,24 @@ _decode_certificate (X509 *certificate, + return NULL; + } + ++static PyObject * ++_certificate_to_der(X509 *certificate) ++{ ++ unsigned char *bytes_buf = NULL; ++ int len; ++ PyObject *retval; ++ ++ bytes_buf = NULL; ++ len = i2d_X509(certificate, &bytes_buf); ++ if (len < 0) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return NULL; ++ } ++ /* this is actually an immutable bytes sequence */ ++ retval = PyBytes_FromStringAndSize((const char *) bytes_buf, len); ++ OPENSSL_free(bytes_buf); ++ return retval; ++} + + static PyObject * + PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { +@@ -1024,28 +1258,30 @@ PySSL_test_decode_certificate (PyObject + char *filename = NULL; + X509 *x=NULL; + BIO *cert; +- int verbose = 1; + +- if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose)) ++ if (!PyArg_ParseTuple(args, "s:test_decode_certificate", &filename)) + return NULL; + + if ((cert=BIO_new(BIO_s_file())) == NULL) { +- PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file"); ++ PyErr_SetString(PySSLErrorObject, ++ "Can't malloc memory to read file"); + goto fail0; + } + + if (BIO_read_filename(cert,filename) <= 0) { +- PyErr_SetString(PySSLErrorObject, "Can't open file"); ++ PyErr_SetString(PySSLErrorObject, ++ "Can't open file"); + goto fail0; + } + + x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL); + if (x == NULL) { +- PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file"); ++ PyErr_SetString(PySSLErrorObject, ++ "Error decoding PEM-encoded file"); + goto fail0; + } + +- retval = _decode_certificate(x, verbose); ++ retval = _decode_certificate(x); + X509_free(x); + + fail0: +@@ -1056,10 +1292,8 @@ PySSL_test_decode_certificate (PyObject + + + static PyObject * +-PySSL_peercert(PySSLObject *self, PyObject *args) ++PySSL_peercert(PySSLSocket *self, PyObject *args) + { +- PyObject *retval = NULL; +- int len; + int verification; + PyObject *binary_mode = Py_None; + int b; +@@ -1067,6 +1301,11 @@ PySSL_peercert(PySSLObject *self, PyObje + if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode)) + return NULL; + ++ if (!self->handshake_done) { ++ PyErr_SetString(PyExc_ValueError, ++ "handshake not done yet"); ++ return NULL; ++ } + if (!self->peer_cert) + Py_RETURN_NONE; + +@@ -1075,26 +1314,13 @@ PySSL_peercert(PySSLObject *self, PyObje + return NULL; + if (b) { + /* return cert in DER-encoded format */ +- +- unsigned char *bytes_buf = NULL; +- +- bytes_buf = NULL; +- len = i2d_X509(self->peer_cert, &bytes_buf); +- if (len < 0) { +- PySSL_SetError(self, len, __FILE__, __LINE__); +- return NULL; +- } +- retval = PyString_FromStringAndSize((const char *) bytes_buf, len); +- OPENSSL_free(bytes_buf); +- return retval; +- ++ return _certificate_to_der(self->peer_cert); + } else { +- +- verification = SSL_CTX_get_verify_mode(self->ctx); ++ verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl)); + if ((verification & SSL_VERIFY_PEER) == 0) + return PyDict_New(); + else +- return _decode_certificate (self->peer_cert, 0); ++ return _decode_certificate(self->peer_cert); + } + } + +@@ -1110,7 +1336,7 @@ If the optional argument is True, return + peer certificate, or None if no certificate was provided. This will\n\ + return the certificate even if it wasn't validated."); + +-static PyObject *PySSL_cipher (PySSLObject *self) { ++static PyObject *PySSL_cipher (PySSLSocket *self) { + + PyObject *retval, *v; + const SSL_CIPHER *current; +@@ -1137,7 +1363,7 @@ static PyObject *PySSL_cipher (PySSLObje + goto fail0; + PyTuple_SET_ITEM(retval, 0, v); + } +- cipher_protocol = SSL_CIPHER_get_version(current); ++ cipher_protocol = (char *) SSL_CIPHER_get_version(current); + if (cipher_protocol == NULL) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(retval, 1, Py_None); +@@ -1158,15 +1384,85 @@ static PyObject *PySSL_cipher (PySSLObje + return NULL; + } + +-static void PySSL_dealloc(PySSLObject *self) ++#ifdef OPENSSL_NPN_NEGOTIATED ++static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { ++ const unsigned char *out; ++ unsigned int outlen; ++ ++ SSL_get0_next_proto_negotiated(self->ssl, ++ &out, &outlen); ++ ++ if (out == NULL) ++ Py_RETURN_NONE; ++ return PyUnicode_FromStringAndSize((char *) out, outlen); ++} ++#endif ++ ++static PyObject *PySSL_compression(PySSLSocket *self) { ++#ifdef OPENSSL_NO_COMP ++ Py_RETURN_NONE; ++#else ++ const COMP_METHOD *comp_method; ++ const char *short_name; ++ ++ if (self->ssl == NULL) ++ Py_RETURN_NONE; ++ comp_method = SSL_get_current_compression(self->ssl); ++ if (comp_method == NULL || comp_method->type == NID_undef) ++ Py_RETURN_NONE; ++ short_name = OBJ_nid2sn(comp_method->type); ++ if (short_name == NULL) ++ Py_RETURN_NONE; ++ return PyBytes_FromString(short_name); ++#endif ++} ++ ++static PySSLContext *PySSL_get_context(PySSLSocket *self, void *closure) { ++ Py_INCREF(self->ctx); ++ return self->ctx; ++} ++ ++static int PySSL_set_context(PySSLSocket *self, PyObject *value, ++ void *closure) { ++ ++ if (PyObject_TypeCheck(value, &PySSLContext_Type)) { ++#if !HAVE_SNI ++ PyErr_SetString(PyExc_NotImplementedError, "setting a socket's " ++ "context is not supported by your OpenSSL library"); ++ return -1; ++#else ++ Py_INCREF(value); ++ Py_DECREF(self->ctx); ++ self->ctx = (PySSLContext *) value; ++ SSL_set_SSL_CTX(self->ssl, self->ctx->ctx); ++#endif ++ } else { ++ PyErr_SetString(PyExc_TypeError, "The value must be a SSLContext"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++PyDoc_STRVAR(PySSL_set_context_doc, ++"_setter_context(ctx)\n\ ++\ ++This changes the context associated with the SSLSocket. This is typically\n\ ++used from within a callback function set by the set_servername_callback\n\ ++on the SSLContext to change the certificate information associated with the\n\ ++SSLSocket before the cryptographic exchange handshake messages\n"); ++ ++ ++ ++static void PySSL_dealloc(PySSLSocket *self) + { + if (self->peer_cert) /* Possible not to have one? */ + X509_free (self->peer_cert); + if (self->ssl) + SSL_free(self->ssl); +- if (self->ctx) +- SSL_CTX_free(self->ctx); + Py_XDECREF(self->Socket); ++ Py_XDECREF(self->ssl_sock); ++ Py_XDECREF(self->ctx); + PyObject_Del(self); + } + +@@ -1238,16 +1534,21 @@ normal_return: + return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; + } + +-static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) ++static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args) + { + Py_buffer buf; + int len; + int sockstate; + int err; + int nonblocking; ++ PySocketSockObject *sock = self->Socket; ++ ++ Py_INCREF(sock); + +- if (!PyArg_ParseTuple(args, "s*:write", &buf)) ++ if (!PyArg_ParseTuple(args, "s*:write", &buf)) { ++ Py_DECREF(sock); + return NULL; ++ } + + if (buf.len > INT_MAX) { + PyErr_Format(PyExc_OverflowError, +@@ -1256,11 +1557,11 @@ static PyObject *PySSL_SSLwrite(PySSLObj + } + + /* just in case the blocking state of the socket has been changed */ +- nonblocking = (self->Socket->sock_timeout >= 0.0); ++ nonblocking = (sock->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ++ sockstate = check_socket_and_wait_for_timeout(sock, 1); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The write operation timed out"); +@@ -1283,9 +1584,9 @@ static PyObject *PySSL_SSLwrite(PySSLObj + goto error; + } + if (err == SSL_ERROR_WANT_READ) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ++ sockstate = check_socket_and_wait_for_timeout(sock, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ++ sockstate = check_socket_and_wait_for_timeout(sock, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } +@@ -1302,6 +1603,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + ++ Py_DECREF(sock); + PyBuffer_Release(&buf); + if (len > 0) + return PyInt_FromLong(len); +@@ -1309,6 +1611,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj + return PySSL_SetError(self, len, __FILE__, __LINE__); + + error: ++ Py_DECREF(sock); + PyBuffer_Release(&buf); + return NULL; + } +@@ -1319,7 +1622,7 @@ PyDoc_STRVAR(PySSL_SSLwrite_doc, + Writes the string s into the SSL object. Returns the number\n\ + of bytes written."); + +-static PyObject *PySSL_SSLpending(PySSLObject *self) ++static PyObject *PySSL_SSLpending(PySSLSocket *self) + { + int count = 0; + +@@ -1338,23 +1641,46 @@ PyDoc_STRVAR(PySSL_SSLpending_doc, + Returns the number of already decrypted bytes available for read,\n\ + pending on the connection.\n"); + +-static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) ++static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args) + { +- PyObject *buf; +- int count = 0; +- int len = 1024; ++ PyObject *dest = NULL; ++ Py_buffer buf; ++ char *mem; ++ int len, count; ++ int buf_passed = 0; + int sockstate; + int err; + int nonblocking; ++ PySocketSockObject *sock = self->Socket; + +- if (!PyArg_ParseTuple(args, "|i:read", &len)) +- return NULL; ++ Py_INCREF(sock); + +- if (!(buf = PyString_FromStringAndSize((char *) 0, len))) +- return NULL; ++ buf.obj = NULL; ++ buf.buf = NULL; ++ if (!PyArg_ParseTuple(args, "i|w*:read", &len, &buf)) ++ goto error; ++ ++ if ((buf.buf == NULL) && (buf.obj == NULL)) { ++ dest = PyBytes_FromStringAndSize(NULL, len); ++ if (dest == NULL) ++ goto error; ++ mem = PyBytes_AS_STRING(dest); ++ } ++ else { ++ buf_passed = 1; ++ mem = buf.buf; ++ if (len <= 0 || len > buf.len) { ++ len = (int) buf.len; ++ if (buf.len != len) { ++ PyErr_SetString(PyExc_OverflowError, ++ "maximum length can't fit in a C 'int'"); ++ goto error; ++ } ++ } ++ } + + /* just in case the blocking state of the socket has been changed */ +- nonblocking = (self->Socket->sock_timeout >= 0.0); ++ nonblocking = (sock->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + +@@ -1364,70 +1690,71 @@ static PyObject *PySSL_SSLread(PySSLObje + PySSL_END_ALLOW_THREADS + + if (!count) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ++ sockstate = check_socket_and_wait_for_timeout(sock, 0); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The read operation timed out"); +- Py_DECREF(buf); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket too large for select()."); +- Py_DECREF(buf); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { +- if (SSL_get_shutdown(self->ssl) != +- SSL_RECEIVED_SHUTDOWN) +- { +- Py_DECREF(buf); +- PyErr_SetString(PySSLErrorObject, +- "Socket closed without SSL shutdown handshake"); +- return NULL; +- } else { +- /* should contain a zero-length string */ +- _PyString_Resize(&buf, 0); +- return buf; +- } ++ count = 0; ++ goto done; + } + } + do { + PySSL_BEGIN_ALLOW_THREADS +- count = SSL_read(self->ssl, PyString_AsString(buf), len); ++ count = SSL_read(self->ssl, mem, len); + err = SSL_get_error(self->ssl, count); + PySSL_END_ALLOW_THREADS +- if(PyErr_CheckSignals()) { +- Py_DECREF(buf); +- return NULL; +- } ++ if (PyErr_CheckSignals()) ++ goto error; + if (err == SSL_ERROR_WANT_READ) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ++ sockstate = check_socket_and_wait_for_timeout(sock, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ++ sockstate = check_socket_and_wait_for_timeout(sock, 1); + } else if ((err == SSL_ERROR_ZERO_RETURN) && + (SSL_get_shutdown(self->ssl) == + SSL_RECEIVED_SHUTDOWN)) + { +- _PyString_Resize(&buf, 0); +- return buf; ++ count = 0; ++ goto done; + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The read operation timed out"); +- Py_DECREF(buf); +- return NULL; ++ goto error; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (count <= 0) { +- Py_DECREF(buf); +- return PySSL_SetError(self, count, __FILE__, __LINE__); ++ PySSL_SetError(self, count, __FILE__, __LINE__); ++ goto error; ++ } ++ ++done: ++ Py_DECREF(sock); ++ if (!buf_passed) { ++ _PyBytes_Resize(&dest, count); ++ return dest; + } +- if (count != len) +- _PyString_Resize(&buf, count); +- return buf; ++ else { ++ PyBuffer_Release(&buf); ++ return PyLong_FromLong(count); ++ } ++ ++error: ++ Py_DECREF(sock); ++ if (!buf_passed) ++ Py_XDECREF(dest); ++ else ++ PyBuffer_Release(&buf); ++ return NULL; + } + + PyDoc_STRVAR(PySSL_SSLread_doc, +@@ -1435,20 +1762,22 @@ PyDoc_STRVAR(PySSL_SSLread_doc, + \n\ + Read up to len bytes from the SSL socket."); + +-static PyObject *PySSL_SSLshutdown(PySSLObject *self) ++static PyObject *PySSL_SSLshutdown(PySSLSocket *self) + { + int err, ssl_err, sockstate, nonblocking; + int zeros = 0; ++ PySocketSockObject *sock = self->Socket; + + /* Guard against closed socket */ +- if (self->Socket->sock_fd < 0) { +- PyErr_SetString(PySSLErrorObject, +- "Underlying socket has been closed."); ++ if (sock->sock_fd < 0) { ++ _setSSLError("Underlying socket connection gone", ++ PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); + return NULL; + } ++ Py_INCREF(sock); + + /* Just in case the blocking state of the socket has been changed */ +- nonblocking = (self->Socket->sock_timeout >= 0.0); ++ nonblocking = (sock->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + +@@ -1483,9 +1812,9 @@ static PyObject *PySSL_SSLshutdown(PySSL + /* Possibly retry shutdown until timeout or failure */ + ssl_err = SSL_get_error(self->ssl, err); + if (ssl_err == SSL_ERROR_WANT_READ) +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ++ sockstate = check_socket_and_wait_for_timeout(sock, 0); + else if (ssl_err == SSL_ERROR_WANT_WRITE) +- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ++ sockstate = check_socket_and_wait_for_timeout(sock, 1); + else + break; + if (sockstate == SOCKET_HAS_TIMED_OUT) { +@@ -1495,24 +1824,29 @@ static PyObject *PySSL_SSLshutdown(PySSL + else + PyErr_SetString(PySSLErrorObject, + "The write operation timed out"); +- return NULL; ++ goto error; + } + else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket too large for select()."); +- return NULL; ++ goto error; + } + else if (sockstate != SOCKET_OPERATION_OK) + /* Retain the SSL error code */ + break; + } + +- if (err < 0) ++ if (err < 0) { ++ Py_DECREF(sock); + return PySSL_SetError(self, err, __FILE__, __LINE__); +- else { +- Py_INCREF(self->Socket); +- return (PyObject *) (self->Socket); + } ++ else ++ /* It's already INCREF'ed */ ++ return (PyObject *) sock; ++ ++error: ++ Py_DECREF(sock); ++ return NULL; + } + + PyDoc_STRVAR(PySSL_SSLshutdown_doc, +@@ -1521,6 +1855,47 @@ PyDoc_STRVAR(PySSL_SSLshutdown_doc, + Does the SSL shutdown handshake with the remote end, and returns\n\ + the underlying socket object."); + ++#if HAVE_OPENSSL_FINISHED ++static PyObject * ++PySSL_tls_unique_cb(PySSLSocket *self) ++{ ++ PyObject *retval = NULL; ++ char buf[PySSL_CB_MAXLEN]; ++ size_t len; ++ ++ if (SSL_session_reused(self->ssl) ^ !self->socket_type) { ++ /* if session is resumed XOR we are the client */ ++ len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN); ++ } ++ else { ++ /* if a new session XOR we are the server */ ++ len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN); ++ } ++ ++ /* It cannot be negative in current OpenSSL version as of July 2011 */ ++ if (len == 0) ++ Py_RETURN_NONE; ++ ++ retval = PyBytes_FromStringAndSize(buf, len); ++ ++ return retval; ++} ++ ++PyDoc_STRVAR(PySSL_tls_unique_cb_doc, ++"tls_unique_cb() -> bytes\n\ ++\n\ ++Returns the 'tls-unique' channel binding data, as defined by RFC 5929.\n\ ++\n\ ++If the TLS handshake is not yet complete, None is returned"); ++ ++#endif /* HAVE_OPENSSL_FINISHED */ ++ ++static PyGetSetDef ssl_getsetlist[] = { ++ {"context", (getter) PySSL_get_context, ++ (setter) PySSL_set_context, PySSL_set_context_doc}, ++ {NULL}, /* sentinel */ ++}; ++ + static PyMethodDef PySSLMethods[] = { + {"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, + {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, +@@ -1529,118 +1904,1786 @@ static PyMethodDef PySSLMethods[] = { + PySSL_SSLread_doc}, + {"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS, + PySSL_SSLpending_doc}, +- {"server", (PyCFunction)PySSL_server, METH_NOARGS}, +- {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, + {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, + PySSL_peercert_doc}, + {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, ++#ifdef OPENSSL_NPN_NEGOTIATED ++ {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, ++#endif ++ {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, + {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, + PySSL_SSLshutdown_doc}, ++#if HAVE_OPENSSL_FINISHED ++ {"tls_unique_cb", (PyCFunction)PySSL_tls_unique_cb, METH_NOARGS, ++ PySSL_tls_unique_cb_doc}, ++#endif + {NULL, NULL} + }; + +-static PyObject *PySSL_getattr(PySSLObject *self, char *name) +-{ +- return Py_FindMethod(PySSLMethods, (PyObject *)self, name); +-} +- +-static PyTypeObject PySSL_Type = { ++static PyTypeObject PySSLSocket_Type = { + PyVarObject_HEAD_INIT(NULL, 0) +- "ssl.SSLContext", /*tp_name*/ +- sizeof(PySSLObject), /*tp_basicsize*/ ++ "_ssl._SSLSocket", /*tp_name*/ ++ sizeof(PySSLSocket), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PySSL_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ +- (getattrfunc)PySSL_getattr, /*tp_getattr*/ ++ 0, /*tp_getattr*/ + 0, /*tp_setattr*/ +- 0, /*tp_compare*/ ++ 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ 0, /*tp_doc*/ ++ 0, /*tp_traverse*/ ++ 0, /*tp_clear*/ ++ 0, /*tp_richcompare*/ ++ 0, /*tp_weaklistoffset*/ ++ 0, /*tp_iter*/ ++ 0, /*tp_iternext*/ ++ PySSLMethods, /*tp_methods*/ ++ 0, /*tp_members*/ ++ ssl_getsetlist, /*tp_getset*/ + }; + +-#ifdef HAVE_OPENSSL_RAND + +-/* helper routines for seeding the SSL PRNG */ ++/* ++ * _SSLContext objects ++ */ ++ + static PyObject * +-PySSL_RAND_add(PyObject *self, PyObject *args) ++context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +- char *buf; +- int len; +- double entropy; ++ char *kwlist[] = {"protocol", NULL}; ++ PySSLContext *self; ++ int proto_version = PY_SSL_VERSION_SSL23; ++ long options; ++ SSL_CTX *ctx = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords( ++ args, kwds, "i:_SSLContext", kwlist, ++ &proto_version)) ++ return NULL; + +- if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) ++ PySSL_BEGIN_ALLOW_THREADS ++ if (proto_version == PY_SSL_VERSION_TLS1) ++ ctx = SSL_CTX_new(TLSv1_method()); ++#if HAVE_TLSv1_2 ++ else if (proto_version == PY_SSL_VERSION_TLS1_1) ++ ctx = SSL_CTX_new(TLSv1_1_method()); ++ else if (proto_version == PY_SSL_VERSION_TLS1_2) ++ ctx = SSL_CTX_new(TLSv1_2_method()); ++#endif ++ else if (proto_version == PY_SSL_VERSION_SSL3) ++ ctx = SSL_CTX_new(SSLv3_method()); ++#ifndef OPENSSL_NO_SSL2 ++ else if (proto_version == PY_SSL_VERSION_SSL2) ++ ctx = SSL_CTX_new(SSLv2_method()); ++#endif ++ else if (proto_version == PY_SSL_VERSION_SSL23) ++ ctx = SSL_CTX_new(SSLv23_method()); ++ else ++ proto_version = -1; ++ PySSL_END_ALLOW_THREADS ++ ++ if (proto_version == -1) { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid protocol version"); + return NULL; +- RAND_add(buf, len, entropy); +- Py_INCREF(Py_None); +- return Py_None; ++ } ++ if (ctx == NULL) { ++ PyErr_SetString(PySSLErrorObject, ++ "failed to allocate SSL context"); ++ return NULL; ++ } ++ ++ assert(type != NULL && type->tp_alloc != NULL); ++ self = (PySSLContext *) type->tp_alloc(type, 0); ++ if (self == NULL) { ++ SSL_CTX_free(ctx); ++ return NULL; ++ } ++ self->ctx = ctx; ++#ifdef OPENSSL_NPN_NEGOTIATED ++ self->npn_protocols = NULL; ++#endif ++#ifndef OPENSSL_NO_TLSEXT ++ self->set_hostname = NULL; ++#endif ++ /* Don't check host name by default */ ++ self->check_hostname = 0; ++ /* Defaults */ ++ SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); ++ options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; ++ SSL_CTX_set_options(self->ctx, options); ++ ++#ifndef OPENSSL_NO_ECDH ++ /* Allow automatic ECDH curve selection (on OpenSSL 1.0.2+), or use ++ prime256v1 by default. This is Apache mod_ssl's initialization ++ policy, so we should be safe. */ ++#if defined(SSL_CTX_set_ecdh_auto) ++ SSL_CTX_set_ecdh_auto(self->ctx, 1); ++#else ++ { ++ EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); ++ SSL_CTX_set_tmp_ecdh(self->ctx, key); ++ EC_KEY_free(key); ++ } ++#endif ++#endif ++ ++#define SID_CTX "Python" ++ SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX, ++ sizeof(SID_CTX)); ++#undef SID_CTX ++ ++ return (PyObject *)self; + } + +-PyDoc_STRVAR(PySSL_RAND_add_doc, +-"RAND_add(string, entropy)\n\ +-\n\ +-Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\ +-bound on the entropy contained in string. See RFC 1750."); ++static int ++context_traverse(PySSLContext *self, visitproc visit, void *arg) ++{ ++#ifndef OPENSSL_NO_TLSEXT ++ Py_VISIT(self->set_hostname); ++#endif ++ return 0; ++} + +-static PyObject * +-PySSL_RAND_status(PyObject *self) ++static int ++context_clear(PySSLContext *self) + { +- return PyInt_FromLong(RAND_status()); ++#ifndef OPENSSL_NO_TLSEXT ++ Py_CLEAR(self->set_hostname); ++#endif ++ return 0; + } + +-PyDoc_STRVAR(PySSL_RAND_status_doc, +-"RAND_status() -> 0 or 1\n\ +-\n\ +-Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ +-It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ +-using the ssl() function."); ++static void ++context_dealloc(PySSLContext *self) ++{ ++ context_clear(self); ++ SSL_CTX_free(self->ctx); ++#ifdef OPENSSL_NPN_NEGOTIATED ++ PyMem_Free(self->npn_protocols); ++#endif ++ Py_TYPE(self)->tp_free(self); ++} + + static PyObject * +-PySSL_RAND_egd(PyObject *self, PyObject *arg) ++set_ciphers(PySSLContext *self, PyObject *args) + { +- int bytes; ++ int ret; ++ const char *cipherlist; + +- if (!PyString_Check(arg)) +- return PyErr_Format(PyExc_TypeError, +- "RAND_egd() expected string, found %s", +- Py_TYPE(arg)->tp_name); +- bytes = RAND_egd(PyString_AS_STRING(arg)); +- if (bytes == -1) { ++ if (!PyArg_ParseTuple(args, "s:set_ciphers", &cipherlist)) ++ return NULL; ++ ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist); ++ if (ret == 0) { ++ /* Clearing the error queue is necessary on some OpenSSL versions, ++ otherwise the error will be reported again when another SSL call ++ is done. */ ++ ERR_clear_error(); + PyErr_SetString(PySSLErrorObject, +- "EGD connection failed or EGD did not return " +- "enough data to seed the PRNG"); ++ "No cipher can be selected."); + return NULL; + } +- return PyInt_FromLong(bytes); ++ Py_RETURN_NONE; + } + +-PyDoc_STRVAR(PySSL_RAND_egd_doc, +-"RAND_egd(path) -> bytes\n\ +-\n\ +-Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ +-Returns number of bytes read. Raises SSLError if connection to EGD\n\ +-fails or if it does not provide enough data to seed PRNG."); ++#ifdef OPENSSL_NPN_NEGOTIATED ++/* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ ++static int ++_advertiseNPN_cb(SSL *s, ++ const unsigned char **data, unsigned int *len, ++ void *args) ++{ ++ PySSLContext *ssl_ctx = (PySSLContext *) args; + +-#endif /* HAVE_OPENSSL_RAND */ ++ if (ssl_ctx->npn_protocols == NULL) { ++ *data = (unsigned char *) ""; ++ *len = 0; ++ } else { ++ *data = (unsigned char *) ssl_ctx->npn_protocols; ++ *len = ssl_ctx->npn_protocols_len; ++ } + +-/* List of functions exported by this module. */ ++ return SSL_TLSEXT_ERR_OK; ++} ++/* this callback gets passed to SSL_CTX_set_next_proto_select_cb */ ++static int ++_selectNPN_cb(SSL *s, ++ unsigned char **out, unsigned char *outlen, ++ const unsigned char *server, unsigned int server_len, ++ void *args) ++{ ++ PySSLContext *ssl_ctx = (PySSLContext *) args; ++ ++ unsigned char *client = (unsigned char *) ssl_ctx->npn_protocols; ++ int client_len; ++ ++ if (client == NULL) { ++ client = (unsigned char *) ""; ++ client_len = 0; ++ } else { ++ client_len = ssl_ctx->npn_protocols_len; ++ } ++ ++ SSL_select_next_proto(out, outlen, ++ server, server_len, ++ client, client_len); ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++#endif ++ ++static PyObject * ++_set_npn_protocols(PySSLContext *self, PyObject *args) ++{ ++#ifdef OPENSSL_NPN_NEGOTIATED ++ Py_buffer protos; ++ ++ if (!PyArg_ParseTuple(args, "s*:set_npn_protocols", &protos)) ++ return NULL; ++ ++ if (self->npn_protocols != NULL) { ++ PyMem_Free(self->npn_protocols); ++ } ++ ++ self->npn_protocols = PyMem_Malloc(protos.len); ++ if (self->npn_protocols == NULL) { ++ PyBuffer_Release(&protos); ++ return PyErr_NoMemory(); ++ } ++ memcpy(self->npn_protocols, protos.buf, protos.len); ++ self->npn_protocols_len = (int) protos.len; ++ ++ /* set both server and client callbacks, because the context can ++ * be used to create both types of sockets */ ++ SSL_CTX_set_next_protos_advertised_cb(self->ctx, ++ _advertiseNPN_cb, ++ self); ++ SSL_CTX_set_next_proto_select_cb(self->ctx, ++ _selectNPN_cb, ++ self); ++ ++ PyBuffer_Release(&protos); ++ Py_RETURN_NONE; ++#else ++ PyErr_SetString(PyExc_NotImplementedError, ++ "The NPN extension requires OpenSSL 1.0.1 or later."); ++ return NULL; ++#endif ++} ++ ++static PyObject * ++get_verify_mode(PySSLContext *self, void *c) ++{ ++ switch (SSL_CTX_get_verify_mode(self->ctx)) { ++ case SSL_VERIFY_NONE: ++ return PyLong_FromLong(PY_SSL_CERT_NONE); ++ case SSL_VERIFY_PEER: ++ return PyLong_FromLong(PY_SSL_CERT_OPTIONAL); ++ case SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT: ++ return PyLong_FromLong(PY_SSL_CERT_REQUIRED); ++ } ++ PyErr_SetString(PySSLErrorObject, ++ "invalid return value from SSL_CTX_get_verify_mode"); ++ return NULL; ++} ++ ++static int ++set_verify_mode(PySSLContext *self, PyObject *arg, void *c) ++{ ++ int n, mode; ++ if (!PyArg_Parse(arg, "i", &n)) ++ return -1; ++ if (n == PY_SSL_CERT_NONE) ++ mode = SSL_VERIFY_NONE; ++ else if (n == PY_SSL_CERT_OPTIONAL) ++ mode = SSL_VERIFY_PEER; ++ else if (n == PY_SSL_CERT_REQUIRED) ++ mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; ++ else { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid value for verify_mode"); ++ return -1; ++ } ++ if (mode == SSL_VERIFY_NONE && self->check_hostname) { ++ PyErr_SetString(PyExc_ValueError, ++ "Cannot set verify_mode to CERT_NONE when " ++ "check_hostname is enabled."); ++ return -1; ++ } ++ SSL_CTX_set_verify(self->ctx, mode, NULL); ++ return 0; ++} ++ ++#ifdef HAVE_OPENSSL_VERIFY_PARAM ++static PyObject * ++get_verify_flags(PySSLContext *self, void *c) ++{ ++ X509_STORE *store; ++ unsigned long flags; ++ ++ store = SSL_CTX_get_cert_store(self->ctx); ++ flags = X509_VERIFY_PARAM_get_flags(store->param); ++ return PyLong_FromUnsignedLong(flags); ++} ++ ++static int ++set_verify_flags(PySSLContext *self, PyObject *arg, void *c) ++{ ++ X509_STORE *store; ++ unsigned long new_flags, flags, set, clear; ++ ++ if (!PyArg_Parse(arg, "k", &new_flags)) ++ return -1; ++ store = SSL_CTX_get_cert_store(self->ctx); ++ flags = X509_VERIFY_PARAM_get_flags(store->param); ++ clear = flags & ~new_flags; ++ set = ~flags & new_flags; ++ if (clear) { ++ if (!X509_VERIFY_PARAM_clear_flags(store->param, clear)) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return -1; ++ } ++ } ++ if (set) { ++ if (!X509_VERIFY_PARAM_set_flags(store->param, set)) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return -1; ++ } ++ } ++ return 0; ++} ++#endif ++ ++static PyObject * ++get_options(PySSLContext *self, void *c) ++{ ++ return PyLong_FromLong(SSL_CTX_get_options(self->ctx)); ++} ++ ++static int ++set_options(PySSLContext *self, PyObject *arg, void *c) ++{ ++ long new_opts, opts, set, clear; ++ if (!PyArg_Parse(arg, "l", &new_opts)) ++ return -1; ++ opts = SSL_CTX_get_options(self->ctx); ++ clear = opts & ~new_opts; ++ set = ~opts & new_opts; ++ if (clear) { ++#ifdef HAVE_SSL_CTX_CLEAR_OPTIONS ++ SSL_CTX_clear_options(self->ctx, clear); ++#else ++ PyErr_SetString(PyExc_ValueError, ++ "can't clear options before OpenSSL 0.9.8m"); ++ return -1; ++#endif ++ } ++ if (set) ++ SSL_CTX_set_options(self->ctx, set); ++ return 0; ++} ++ ++static PyObject * ++get_check_hostname(PySSLContext *self, void *c) ++{ ++ return PyBool_FromLong(self->check_hostname); ++} ++ ++static int ++set_check_hostname(PySSLContext *self, PyObject *arg, void *c) ++{ ++ PyObject *py_check_hostname; ++ int check_hostname; ++ if (!PyArg_Parse(arg, "O", &py_check_hostname)) ++ return -1; ++ ++ check_hostname = PyObject_IsTrue(py_check_hostname); ++ if (check_hostname < 0) ++ return -1; ++ if (check_hostname && ++ SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) { ++ PyErr_SetString(PyExc_ValueError, ++ "check_hostname needs a SSL context with either " ++ "CERT_OPTIONAL or CERT_REQUIRED"); ++ return -1; ++ } ++ self->check_hostname = check_hostname; ++ return 0; ++} ++ ++ ++typedef struct { ++ PyThreadState *thread_state; ++ PyObject *callable; ++ char *password; ++ int size; ++ int error; ++} _PySSLPasswordInfo; ++ ++static int ++_pwinfo_set(_PySSLPasswordInfo *pw_info, PyObject* password, ++ const char *bad_type_error) ++{ ++ /* Set the password and size fields of a _PySSLPasswordInfo struct ++ from a unicode, bytes, or byte array object. ++ The password field will be dynamically allocated and must be freed ++ by the caller */ ++ PyObject *password_bytes = NULL; ++ const char *data = NULL; ++ Py_ssize_t size; ++ ++ if (PyUnicode_Check(password)) { ++ password_bytes = PyUnicode_AsEncodedString(password, NULL, NULL); ++ if (!password_bytes) { ++ goto error; ++ } ++ data = PyBytes_AS_STRING(password_bytes); ++ size = PyBytes_GET_SIZE(password_bytes); ++ } else if (PyBytes_Check(password)) { ++ data = PyBytes_AS_STRING(password); ++ size = PyBytes_GET_SIZE(password); ++ } else if (PyByteArray_Check(password)) { ++ data = PyByteArray_AS_STRING(password); ++ size = PyByteArray_GET_SIZE(password); ++ } else { ++ PyErr_SetString(PyExc_TypeError, bad_type_error); ++ goto error; ++ } ++ ++ if (size > (Py_ssize_t)INT_MAX) { ++ PyErr_Format(PyExc_ValueError, ++ "password cannot be longer than %d bytes", INT_MAX); ++ goto error; ++ } ++ ++ PyMem_Free(pw_info->password); ++ pw_info->password = PyMem_Malloc(size); ++ if (!pw_info->password) { ++ PyErr_SetString(PyExc_MemoryError, ++ "unable to allocate password buffer"); ++ goto error; ++ } ++ memcpy(pw_info->password, data, size); ++ pw_info->size = (int)size; ++ ++ Py_XDECREF(password_bytes); ++ return 1; ++ ++error: ++ Py_XDECREF(password_bytes); ++ return 0; ++} ++ ++static int ++_password_callback(char *buf, int size, int rwflag, void *userdata) ++{ ++ _PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata; ++ PyObject *fn_ret = NULL; ++ ++ PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); ++ ++ if (pw_info->callable) { ++ fn_ret = PyObject_CallFunctionObjArgs(pw_info->callable, NULL); ++ if (!fn_ret) { ++ /* TODO: It would be nice to move _ctypes_add_traceback() into the ++ core python API, so we could use it to add a frame here */ ++ goto error; ++ } ++ ++ if (!_pwinfo_set(pw_info, fn_ret, ++ "password callback must return a string")) { ++ goto error; ++ } ++ Py_CLEAR(fn_ret); ++ } ++ ++ if (pw_info->size > size) { ++ PyErr_Format(PyExc_ValueError, ++ "password cannot be longer than %d bytes", size); ++ goto error; ++ } ++ ++ PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); ++ memcpy(buf, pw_info->password, pw_info->size); ++ return pw_info->size; ++ ++error: ++ Py_XDECREF(fn_ret); ++ PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); ++ pw_info->error = 1; ++ return -1; ++} ++ ++static PyObject * ++load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"certfile", "keyfile", "password", NULL}; ++ PyObject *password = NULL; ++ char *certfile_bytes = NULL, *keyfile_bytes = NULL; ++ pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback; ++ void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata; ++ _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; ++ int r; ++ ++ errno = 0; ++ ERR_clear_error(); ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "et|etO:load_cert_chain", kwlist, ++ Py_FileSystemDefaultEncoding, &certfile_bytes, ++ Py_FileSystemDefaultEncoding, &keyfile_bytes, ++ &password)) ++ return NULL; ++ if (password && password != Py_None) { ++ if (PyCallable_Check(password)) { ++ pw_info.callable = password; ++ } else if (!_pwinfo_set(&pw_info, password, ++ "password should be a string or callable")) { ++ goto error; ++ } ++ SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback); ++ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info); ++ } ++ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); ++ r = SSL_CTX_use_certificate_chain_file(self->ctx, certfile_bytes); ++ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); ++ if (r != 1) { ++ if (pw_info.error) { ++ ERR_clear_error(); ++ /* the password callback has already set the error information */ ++ } ++ else if (errno != 0) { ++ ERR_clear_error(); ++ PyErr_SetFromErrno(PyExc_IOError); ++ } ++ else { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ } ++ goto error; ++ } ++ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); ++ r = SSL_CTX_use_PrivateKey_file(self->ctx, ++ keyfile_bytes ? keyfile_bytes : certfile_bytes, ++ SSL_FILETYPE_PEM); ++ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); ++ if (r != 1) { ++ if (pw_info.error) { ++ ERR_clear_error(); ++ /* the password callback has already set the error information */ ++ } ++ else if (errno != 0) { ++ ERR_clear_error(); ++ PyErr_SetFromErrno(PyExc_IOError); ++ } ++ else { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ } ++ goto error; ++ } ++ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); ++ r = SSL_CTX_check_private_key(self->ctx); ++ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); ++ if (r != 1) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ goto error; ++ } ++ SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); ++ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); ++ PyMem_Free(pw_info.password); ++ Py_RETURN_NONE; ++ ++error: ++ SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); ++ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); ++ PyMem_Free(pw_info.password); ++ PyMem_Free(keyfile_bytes); ++ PyMem_Free(certfile_bytes); ++ return NULL; ++} ++ ++/* internal helper function, returns -1 on error ++ */ ++static int ++_add_ca_certs(PySSLContext *self, void *data, Py_ssize_t len, ++ int filetype) ++{ ++ BIO *biobuf = NULL; ++ X509_STORE *store; ++ int retval = 0, err, loaded = 0; ++ ++ assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); ++ ++ if (len <= 0) { ++ PyErr_SetString(PyExc_ValueError, ++ "Empty certificate data"); ++ return -1; ++ } else if (len > INT_MAX) { ++ PyErr_SetString(PyExc_OverflowError, ++ "Certificate data is too long."); ++ return -1; ++ } ++ ++ biobuf = BIO_new_mem_buf(data, (int)len); ++ if (biobuf == NULL) { ++ _setSSLError("Can't allocate buffer", 0, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ store = SSL_CTX_get_cert_store(self->ctx); ++ assert(store != NULL); ++ ++ while (1) { ++ X509 *cert = NULL; ++ int r; ++ ++ if (filetype == SSL_FILETYPE_ASN1) { ++ cert = d2i_X509_bio(biobuf, NULL); ++ } else { ++ cert = PEM_read_bio_X509(biobuf, NULL, ++ self->ctx->default_passwd_callback, ++ self->ctx->default_passwd_callback_userdata); ++ } ++ if (cert == NULL) { ++ break; ++ } ++ r = X509_STORE_add_cert(store, cert); ++ X509_free(cert); ++ if (!r) { ++ err = ERR_peek_last_error(); ++ if ((ERR_GET_LIB(err) == ERR_LIB_X509) && ++ (ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) { ++ /* cert already in hash table, not an error */ ++ ERR_clear_error(); ++ } else { ++ break; ++ } ++ } ++ loaded++; ++ } ++ ++ err = ERR_peek_last_error(); ++ if ((filetype == SSL_FILETYPE_ASN1) && ++ (loaded > 0) && ++ (ERR_GET_LIB(err) == ERR_LIB_ASN1) && ++ (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { ++ /* EOF ASN1 file, not an error */ ++ ERR_clear_error(); ++ retval = 0; ++ } else if ((filetype == SSL_FILETYPE_PEM) && ++ (loaded > 0) && ++ (ERR_GET_LIB(err) == ERR_LIB_PEM) && ++ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { ++ /* EOF PEM file, not an error */ ++ ERR_clear_error(); ++ retval = 0; ++ } else { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ retval = -1; ++ } ++ ++ BIO_free(biobuf); ++ return retval; ++} ++ ++ ++static PyObject * ++load_verify_locations(PySSLContext *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"cafile", "capath", "cadata", NULL}; ++ PyObject *cadata = NULL, *cafile = NULL, *capath = NULL; ++ PyObject *cafile_bytes = NULL, *capath_bytes = NULL; ++ const char *cafile_buf = NULL, *capath_buf = NULL; ++ int r = 0, ok = 1; ++ ++ errno = 0; ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "|OOO:load_verify_locations", kwlist, ++ &cafile, &capath, &cadata)) ++ return NULL; ++ ++ if (cafile == Py_None) ++ cafile = NULL; ++ if (capath == Py_None) ++ capath = NULL; ++ if (cadata == Py_None) ++ cadata = NULL; ++ ++ if (cafile == NULL && capath == NULL && cadata == NULL) { ++ PyErr_SetString(PyExc_TypeError, ++ "cafile, capath and cadata cannot be all omitted"); ++ goto error; ++ } ++ ++ if (cafile) { ++ cafile_bytes = PyString_AsEncodedObject( ++ cafile, Py_FileSystemDefaultEncoding, "strict"); ++ if (!cafile_bytes) { ++ goto error; ++ } ++ } ++ if (capath) { ++ capath_bytes = PyString_AsEncodedObject( ++ capath, Py_FileSystemDefaultEncoding, "strict"); ++ if (!capath_bytes) { ++ goto error; ++ } ++ } ++ ++ /* validata cadata type and load cadata */ ++ if (cadata) { ++ Py_buffer buf; ++ PyObject *cadata_ascii = NULL; ++ ++ if (!PyUnicode_Check(cadata) && PyObject_GetBuffer(cadata, &buf, PyBUF_SIMPLE) == 0) { ++ if (!PyBuffer_IsContiguous(&buf, 'C') || buf.ndim > 1) { ++ PyBuffer_Release(&buf); ++ PyErr_SetString(PyExc_TypeError, ++ "cadata should be a contiguous buffer with " ++ "a single dimension"); ++ goto error; ++ } ++ r = _add_ca_certs(self, buf.buf, buf.len, SSL_FILETYPE_ASN1); ++ PyBuffer_Release(&buf); ++ if (r == -1) { ++ goto error; ++ } ++ } else { ++ PyErr_Clear(); ++ cadata_ascii = PyUnicode_AsASCIIString(cadata); ++ if (cadata_ascii == NULL) { ++ PyErr_SetString(PyExc_TypeError, ++ "cadata should be a ASCII string or a " ++ "bytes-like object"); ++ goto error; ++ } ++ r = _add_ca_certs(self, ++ PyBytes_AS_STRING(cadata_ascii), ++ PyBytes_GET_SIZE(cadata_ascii), ++ SSL_FILETYPE_PEM); ++ Py_DECREF(cadata_ascii); ++ if (r == -1) { ++ goto error; ++ } ++ } ++ } ++ ++ /* load cafile or capath */ ++ if (cafile_bytes || capath_bytes) { ++ if (cafile) ++ cafile_buf = PyBytes_AS_STRING(cafile_bytes); ++ if (capath) ++ capath_buf = PyBytes_AS_STRING(capath_bytes); ++ PySSL_BEGIN_ALLOW_THREADS ++ r = SSL_CTX_load_verify_locations( ++ self->ctx, ++ cafile_buf, ++ capath_buf); ++ PySSL_END_ALLOW_THREADS ++ if (r != 1) { ++ ok = 0; ++ if (errno != 0) { ++ ERR_clear_error(); ++ PyErr_SetFromErrno(PyExc_IOError); ++ } ++ else { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ } ++ goto error; ++ } ++ } ++ goto end; ++ ++ error: ++ ok = 0; ++ end: ++ Py_XDECREF(cafile_bytes); ++ Py_XDECREF(capath_bytes); ++ if (ok) { ++ Py_RETURN_NONE; ++ } else { ++ return NULL; ++ } ++} ++ ++static PyObject * ++load_dh_params(PySSLContext *self, PyObject *filepath) ++{ ++ BIO *bio; ++ DH *dh; ++ char *path = PyBytes_AsString(filepath); ++ if (!path) { ++ return NULL; ++ } ++ ++ bio = BIO_new_file(path, "r"); ++ if (bio == NULL) { ++ ERR_clear_error(); ++ PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filepath); ++ return NULL; ++ } ++ errno = 0; ++ PySSL_BEGIN_ALLOW_THREADS ++ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ PySSL_END_ALLOW_THREADS ++ if (dh == NULL) { ++ if (errno != 0) { ++ ERR_clear_error(); ++ PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); ++ } ++ else { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ } ++ return NULL; ++ } ++ if (SSL_CTX_set_tmp_dh(self->ctx, dh) == 0) ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ DH_free(dh); ++ Py_RETURN_NONE; ++} ++ ++static PyObject * ++context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"sock", "server_side", "server_hostname", "ssl_sock", NULL}; ++ PySocketSockObject *sock; ++ int server_side = 0; ++ char *hostname = NULL; ++ PyObject *hostname_obj, *ssl_sock = Py_None, *res; ++ ++ /* server_hostname is either None (or absent), or to be encoded ++ using the idna encoding. */ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i|O!O:_wrap_socket", kwlist, ++ PySocketModule.Sock_Type, ++ &sock, &server_side, ++ Py_TYPE(Py_None), &hostname_obj, ++ &ssl_sock)) { ++ PyErr_Clear(); ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!iet|O:_wrap_socket", kwlist, ++ PySocketModule.Sock_Type, ++ &sock, &server_side, ++ "idna", &hostname, &ssl_sock)) ++ return NULL; ++#if !HAVE_SNI ++ PyMem_Free(hostname); ++ PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " ++ "by your OpenSSL library"); ++ return NULL; ++#endif ++ } ++ ++ res = (PyObject *) newPySSLSocket(self, sock, server_side, ++ hostname, ssl_sock); ++ if (hostname != NULL) ++ PyMem_Free(hostname); ++ return res; ++} ++ ++static PyObject * ++session_stats(PySSLContext *self, PyObject *unused) ++{ ++ int r; ++ PyObject *value, *stats = PyDict_New(); ++ if (!stats) ++ return NULL; ++ ++#define ADD_STATS(SSL_NAME, KEY_NAME) \ ++ value = PyLong_FromLong(SSL_CTX_sess_ ## SSL_NAME (self->ctx)); \ ++ if (value == NULL) \ ++ goto error; \ ++ r = PyDict_SetItemString(stats, KEY_NAME, value); \ ++ Py_DECREF(value); \ ++ if (r < 0) \ ++ goto error; ++ ++ ADD_STATS(number, "number"); ++ ADD_STATS(connect, "connect"); ++ ADD_STATS(connect_good, "connect_good"); ++ ADD_STATS(connect_renegotiate, "connect_renegotiate"); ++ ADD_STATS(accept, "accept"); ++ ADD_STATS(accept_good, "accept_good"); ++ ADD_STATS(accept_renegotiate, "accept_renegotiate"); ++ ADD_STATS(accept, "accept"); ++ ADD_STATS(hits, "hits"); ++ ADD_STATS(misses, "misses"); ++ ADD_STATS(timeouts, "timeouts"); ++ ADD_STATS(cache_full, "cache_full"); ++ ++#undef ADD_STATS ++ ++ return stats; ++ ++error: ++ Py_DECREF(stats); ++ return NULL; ++} ++ ++static PyObject * ++set_default_verify_paths(PySSLContext *self, PyObject *unused) ++{ ++ if (!SSL_CTX_set_default_verify_paths(self->ctx)) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++#ifndef OPENSSL_NO_ECDH ++static PyObject * ++set_ecdh_curve(PySSLContext *self, PyObject *name) ++{ ++ char *name_bytes; ++ int nid; ++ EC_KEY *key; ++ ++ name_bytes = PyBytes_AsString(name); ++ if (!name_bytes) { ++ return NULL; ++ } ++ nid = OBJ_sn2nid(name_bytes); ++ if (nid == 0) { ++ PyErr_Format(PyExc_ValueError, ++ "unknown elliptic curve name %R", name); ++ return NULL; ++ } ++ key = EC_KEY_new_by_curve_name(nid); ++ if (key == NULL) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return NULL; ++ } ++ SSL_CTX_set_tmp_ecdh(self->ctx, key); ++ EC_KEY_free(key); ++ Py_RETURN_NONE; ++} ++#endif ++ ++#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) ++static int ++_servername_callback(SSL *s, int *al, void *args) ++{ ++ int ret; ++ PySSLContext *ssl_ctx = (PySSLContext *) args; ++ PySSLSocket *ssl; ++ PyObject *servername_o; ++ PyObject *servername_idna; ++ PyObject *result; ++ /* The high-level ssl.SSLSocket object */ ++ PyObject *ssl_socket; ++ const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); ++#ifdef WITH_THREAD ++ PyGILState_STATE gstate = PyGILState_Ensure(); ++#endif ++ ++ if (ssl_ctx->set_hostname == NULL) { ++ /* remove race condition in this the call back while if removing the ++ * callback is in progress */ ++#ifdef WITH_THREAD ++ PyGILState_Release(gstate); ++#endif ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ ssl = SSL_get_app_data(s); ++ assert(PySSLSocket_Check(ssl)); ++ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); ++ Py_INCREF(ssl_socket); ++ if (ssl_socket == Py_None) { ++ goto error; ++ } ++ ++ if (servername == NULL) { ++ result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, ++ Py_None, ssl_ctx, NULL); ++ } ++ else { ++ servername_o = PyBytes_FromString(servername); ++ if (servername_o == NULL) { ++ PyErr_WriteUnraisable((PyObject *) ssl_ctx); ++ goto error; ++ } ++ servername_idna = PyUnicode_FromEncodedObject(servername_o, "idna", NULL); ++ if (servername_idna == NULL) { ++ PyErr_WriteUnraisable(servername_o); ++ Py_DECREF(servername_o); ++ goto error; ++ } ++ Py_DECREF(servername_o); ++ result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, ++ servername_idna, ssl_ctx, NULL); ++ Py_DECREF(servername_idna); ++ } ++ Py_DECREF(ssl_socket); ++ ++ if (result == NULL) { ++ PyErr_WriteUnraisable(ssl_ctx->set_hostname); ++ *al = SSL_AD_HANDSHAKE_FAILURE; ++ ret = SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ else { ++ if (result != Py_None) { ++ *al = (int) PyLong_AsLong(result); ++ if (PyErr_Occurred()) { ++ PyErr_WriteUnraisable(result); ++ *al = SSL_AD_INTERNAL_ERROR; ++ } ++ ret = SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ else { ++ ret = SSL_TLSEXT_ERR_OK; ++ } ++ Py_DECREF(result); ++ } ++ ++#ifdef WITH_THREAD ++ PyGILState_Release(gstate); ++#endif ++ return ret; ++ ++error: ++ Py_DECREF(ssl_socket); ++ *al = SSL_AD_INTERNAL_ERROR; ++ ret = SSL_TLSEXT_ERR_ALERT_FATAL; ++#ifdef WITH_THREAD ++ PyGILState_Release(gstate); ++#endif ++ return ret; ++} ++#endif ++ ++PyDoc_STRVAR(PySSL_set_servername_callback_doc, ++"set_servername_callback(method)\n\ ++\n\ ++This sets a callback that will be called when a server name is provided by\n\ ++the SSL/TLS client in the SNI extension.\n\ ++\n\ ++If the argument is None then the callback is disabled. The method is called\n\ ++with the SSLSocket, the server name as a string, and the SSLContext object.\n\ ++See RFC 6066 for details of the SNI extension."); ++ ++static PyObject * ++set_servername_callback(PySSLContext *self, PyObject *args) ++{ ++#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) ++ PyObject *cb; ++ ++ if (!PyArg_ParseTuple(args, "O", &cb)) ++ return NULL; ++ ++ Py_CLEAR(self->set_hostname); ++ if (cb == Py_None) { ++ SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); ++ } ++ else { ++ if (!PyCallable_Check(cb)) { ++ SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); ++ PyErr_SetString(PyExc_TypeError, ++ "not a callable object"); ++ return NULL; ++ } ++ Py_INCREF(cb); ++ self->set_hostname = cb; ++ SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); ++ SSL_CTX_set_tlsext_servername_arg(self->ctx, self); ++ } ++ Py_RETURN_NONE; ++#else ++ PyErr_SetString(PyExc_NotImplementedError, ++ "The TLS extension servername callback, " ++ "SSL_CTX_set_tlsext_servername_callback, " ++ "is not in the current OpenSSL library."); ++ return NULL; ++#endif ++} ++ ++PyDoc_STRVAR(PySSL_get_stats_doc, ++"cert_store_stats() -> {'crl': int, 'x509_ca': int, 'x509': int}\n\ ++\n\ ++Returns quantities of loaded X.509 certificates. X.509 certificates with a\n\ ++CA extension and certificate revocation lists inside the context's cert\n\ ++store.\n\ ++NOTE: Certificates in a capath directory aren't loaded unless they have\n\ ++been used at least once."); ++ ++static PyObject * ++cert_store_stats(PySSLContext *self) ++{ ++ X509_STORE *store; ++ X509_OBJECT *obj; ++ int x509 = 0, crl = 0, pkey = 0, ca = 0, i; ++ ++ store = SSL_CTX_get_cert_store(self->ctx); ++ for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { ++ obj = sk_X509_OBJECT_value(store->objs, i); ++ switch (obj->type) { ++ case X509_LU_X509: ++ x509++; ++ if (X509_check_ca(obj->data.x509)) { ++ ca++; ++ } ++ break; ++ case X509_LU_CRL: ++ crl++; ++ break; ++ case X509_LU_PKEY: ++ pkey++; ++ break; ++ default: ++ /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. ++ * As far as I can tell they are internal states and never ++ * stored in a cert store */ ++ break; ++ } ++ } ++ return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl, ++ "x509_ca", ca); ++} ++ ++PyDoc_STRVAR(PySSL_get_ca_certs_doc, ++"get_ca_certs(binary_form=False) -> list of loaded certificate\n\ ++\n\ ++Returns a list of dicts with information of loaded CA certs. If the\n\ ++optional argument is True, returns a DER-encoded copy of the CA certificate.\n\ ++NOTE: Certificates in a capath directory aren't loaded unless they have\n\ ++been used at least once."); ++ ++static PyObject * ++get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"binary_form", NULL}; ++ X509_STORE *store; ++ PyObject *ci = NULL, *rlist = NULL, *py_binary_mode = Py_False; ++ int i; ++ int binary_mode = 0; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:get_ca_certs", ++ kwlist, &py_binary_mode)) { ++ return NULL; ++ } ++ binary_mode = PyObject_IsTrue(py_binary_mode); ++ if (binary_mode < 0) { ++ return NULL; ++ } ++ ++ if ((rlist = PyList_New(0)) == NULL) { ++ return NULL; ++ } ++ ++ store = SSL_CTX_get_cert_store(self->ctx); ++ for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { ++ X509_OBJECT *obj; ++ X509 *cert; ++ ++ obj = sk_X509_OBJECT_value(store->objs, i); ++ if (obj->type != X509_LU_X509) { ++ /* not a x509 cert */ ++ continue; ++ } ++ /* CA for any purpose */ ++ cert = obj->data.x509; ++ if (!X509_check_ca(cert)) { ++ continue; ++ } ++ if (binary_mode) { ++ ci = _certificate_to_der(cert); ++ } else { ++ ci = _decode_certificate(cert); ++ } ++ if (ci == NULL) { ++ goto error; ++ } ++ if (PyList_Append(rlist, ci) == -1) { ++ goto error; ++ } ++ Py_CLEAR(ci); ++ } ++ return rlist; ++ ++ error: ++ Py_XDECREF(ci); ++ Py_XDECREF(rlist); ++ return NULL; ++} ++ ++ ++static PyGetSetDef context_getsetlist[] = { ++ {"check_hostname", (getter) get_check_hostname, ++ (setter) set_check_hostname, NULL}, ++ {"options", (getter) get_options, ++ (setter) set_options, NULL}, ++#ifdef HAVE_OPENSSL_VERIFY_PARAM ++ {"verify_flags", (getter) get_verify_flags, ++ (setter) set_verify_flags, NULL}, ++#endif ++ {"verify_mode", (getter) get_verify_mode, ++ (setter) set_verify_mode, NULL}, ++ {NULL}, /* sentinel */ ++}; ++ ++static struct PyMethodDef context_methods[] = { ++ {"_wrap_socket", (PyCFunction) context_wrap_socket, ++ METH_VARARGS | METH_KEYWORDS, NULL}, ++ {"set_ciphers", (PyCFunction) set_ciphers, ++ METH_VARARGS, NULL}, ++ {"_set_npn_protocols", (PyCFunction) _set_npn_protocols, ++ METH_VARARGS, NULL}, ++ {"load_cert_chain", (PyCFunction) load_cert_chain, ++ METH_VARARGS | METH_KEYWORDS, NULL}, ++ {"load_dh_params", (PyCFunction) load_dh_params, ++ METH_O, NULL}, ++ {"load_verify_locations", (PyCFunction) load_verify_locations, ++ METH_VARARGS | METH_KEYWORDS, NULL}, ++ {"session_stats", (PyCFunction) session_stats, ++ METH_NOARGS, NULL}, ++ {"set_default_verify_paths", (PyCFunction) set_default_verify_paths, ++ METH_NOARGS, NULL}, ++#ifndef OPENSSL_NO_ECDH ++ {"set_ecdh_curve", (PyCFunction) set_ecdh_curve, ++ METH_O, NULL}, ++#endif ++ {"set_servername_callback", (PyCFunction) set_servername_callback, ++ METH_VARARGS, PySSL_set_servername_callback_doc}, ++ {"cert_store_stats", (PyCFunction) cert_store_stats, ++ METH_NOARGS, PySSL_get_stats_doc}, ++ {"get_ca_certs", (PyCFunction) get_ca_certs, ++ METH_VARARGS | METH_KEYWORDS, PySSL_get_ca_certs_doc}, ++ {NULL, NULL} /* sentinel */ ++}; ++ ++static PyTypeObject PySSLContext_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "_ssl._SSLContext", /*tp_name*/ ++ sizeof(PySSLContext), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ (destructor)context_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_reserved*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash*/ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ ++ 0, /*tp_doc*/ ++ (traverseproc) context_traverse, /*tp_traverse*/ ++ (inquiry) context_clear, /*tp_clear*/ ++ 0, /*tp_richcompare*/ ++ 0, /*tp_weaklistoffset*/ ++ 0, /*tp_iter*/ ++ 0, /*tp_iternext*/ ++ context_methods, /*tp_methods*/ ++ 0, /*tp_members*/ ++ context_getsetlist, /*tp_getset*/ ++ 0, /*tp_base*/ ++ 0, /*tp_dict*/ ++ 0, /*tp_descr_get*/ ++ 0, /*tp_descr_set*/ ++ 0, /*tp_dictoffset*/ ++ 0, /*tp_init*/ ++ 0, /*tp_alloc*/ ++ context_new, /*tp_new*/ ++}; ++ ++ ++ ++#ifdef HAVE_OPENSSL_RAND ++ ++/* helper routines for seeding the SSL PRNG */ ++static PyObject * ++PySSL_RAND_add(PyObject *self, PyObject *args) ++{ ++ char *buf; ++ Py_ssize_t len, written; ++ double entropy; ++ ++ if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) ++ return NULL; ++ do { ++ if (len >= INT_MAX) { ++ written = INT_MAX; ++ } else { ++ written = len; ++ } ++ RAND_add(buf, (int)written, entropy); ++ buf += written; ++ len -= written; ++ } while (len); ++ Py_INCREF(Py_None); ++ return Py_None; ++} ++ ++PyDoc_STRVAR(PySSL_RAND_add_doc, ++"RAND_add(string, entropy)\n\ ++\n\ ++Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\ ++bound on the entropy contained in string. See RFC 1750."); ++ ++static PyObject * ++PySSL_RAND_status(PyObject *self) ++{ ++ return PyLong_FromLong(RAND_status()); ++} ++ ++PyDoc_STRVAR(PySSL_RAND_status_doc, ++"RAND_status() -> 0 or 1\n\ ++\n\ ++Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ ++It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ ++using the ssl() function."); ++ ++static PyObject * ++PySSL_RAND_egd(PyObject *self, PyObject *arg) ++{ ++ int bytes; ++ ++ if (!PyString_Check(arg)) ++ return PyErr_Format(PyExc_TypeError, ++ "RAND_egd() expected string, found %s", ++ Py_TYPE(arg)->tp_name); ++ bytes = RAND_egd(PyString_AS_STRING(arg)); ++ if (bytes == -1) { ++ PyErr_SetString(PySSLErrorObject, ++ "EGD connection failed or EGD did not return " ++ "enough data to seed the PRNG"); ++ return NULL; ++ } ++ return PyInt_FromLong(bytes); ++} ++ ++PyDoc_STRVAR(PySSL_RAND_egd_doc, ++"RAND_egd(path) -> bytes\n\ ++\n\ ++Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ ++Returns number of bytes read. Raises SSLError if connection to EGD\n\ ++fails or if it does not provide enough data to seed PRNG."); ++ ++#endif /* HAVE_OPENSSL_RAND */ ++ ++ ++PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, ++"get_default_verify_paths() -> tuple\n\ ++\n\ ++Return search paths and environment vars that are used by SSLContext's\n\ ++set_default_verify_paths() to load default CAs. The values are\n\ ++'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'."); ++ ++static PyObject * ++PySSL_get_default_verify_paths(PyObject *self) ++{ ++ PyObject *ofile_env = NULL; ++ PyObject *ofile = NULL; ++ PyObject *odir_env = NULL; ++ PyObject *odir = NULL; ++ ++#define convert(info, target) { \ ++ const char *tmp = (info); \ ++ target = NULL; \ ++ if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \ ++ else { target = PyBytes_FromString(tmp); } \ ++ if (!target) goto error; \ ++ } while(0) ++ ++ convert(X509_get_default_cert_file_env(), ofile_env); ++ convert(X509_get_default_cert_file(), ofile); ++ convert(X509_get_default_cert_dir_env(), odir_env); ++ convert(X509_get_default_cert_dir(), odir); ++#undef convert ++ ++ return Py_BuildValue("NNNN", ofile_env, ofile, odir_env, odir); ++ ++ error: ++ Py_XDECREF(ofile_env); ++ Py_XDECREF(ofile); ++ Py_XDECREF(odir_env); ++ Py_XDECREF(odir); ++ return NULL; ++} ++ ++static PyObject* ++asn1obj2py(ASN1_OBJECT *obj) ++{ ++ int nid; ++ const char *ln, *sn; ++ char buf[100]; ++ Py_ssize_t buflen; ++ ++ nid = OBJ_obj2nid(obj); ++ if (nid == NID_undef) { ++ PyErr_Format(PyExc_ValueError, "Unknown object"); ++ return NULL; ++ } ++ sn = OBJ_nid2sn(nid); ++ ln = OBJ_nid2ln(nid); ++ buflen = OBJ_obj2txt(buf, sizeof(buf), obj, 1); ++ if (buflen < 0) { ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ return NULL; ++ } ++ if (buflen) { ++ return Py_BuildValue("isss#", nid, sn, ln, buf, buflen); ++ } else { ++ return Py_BuildValue("issO", nid, sn, ln, Py_None); ++ } ++} ++ ++PyDoc_STRVAR(PySSL_txt2obj_doc, ++"txt2obj(txt, name=False) -> (nid, shortname, longname, oid)\n\ ++\n\ ++Lookup NID, short name, long name and OID of an ASN1_OBJECT. By default\n\ ++objects are looked up by OID. With name=True short and long name are also\n\ ++matched."); ++ ++static PyObject* ++PySSL_txt2obj(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"txt", "name", NULL}; ++ PyObject *result = NULL; ++ char *txt; ++ PyObject *pyname = Py_None; ++ int name = 0; ++ ASN1_OBJECT *obj; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O:txt2obj", ++ kwlist, &txt, &pyname)) { ++ return NULL; ++ } ++ name = PyObject_IsTrue(pyname); ++ if (name < 0) ++ return NULL; ++ obj = OBJ_txt2obj(txt, name ? 0 : 1); ++ if (obj == NULL) { ++ PyErr_Format(PyExc_ValueError, "unknown object '%.100s'", txt); ++ return NULL; ++ } ++ result = asn1obj2py(obj); ++ ASN1_OBJECT_free(obj); ++ return result; ++} ++ ++PyDoc_STRVAR(PySSL_nid2obj_doc, ++"nid2obj(nid) -> (nid, shortname, longname, oid)\n\ ++\n\ ++Lookup NID, short name, long name and OID of an ASN1_OBJECT by NID."); ++ ++static PyObject* ++PySSL_nid2obj(PyObject *self, PyObject *args) ++{ ++ PyObject *result = NULL; ++ int nid; ++ ASN1_OBJECT *obj; ++ ++ if (!PyArg_ParseTuple(args, "i:nid2obj", &nid)) { ++ return NULL; ++ } ++ if (nid < NID_undef) { ++ PyErr_SetString(PyExc_ValueError, "NID must be positive."); ++ return NULL; ++ } ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) { ++ PyErr_Format(PyExc_ValueError, "unknown NID %i", nid); ++ return NULL; ++ } ++ result = asn1obj2py(obj); ++ ASN1_OBJECT_free(obj); ++ return result; ++} ++ ++#ifdef _MSC_VER ++ ++static PyObject* ++certEncodingType(DWORD encodingType) ++{ ++ static PyObject *x509_asn = NULL; ++ static PyObject *pkcs_7_asn = NULL; ++ ++ if (x509_asn == NULL) { ++ x509_asn = PyString_InternFromString("x509_asn"); ++ if (x509_asn == NULL) ++ return NULL; ++ } ++ if (pkcs_7_asn == NULL) { ++ pkcs_7_asn = PyString_InternFromString("pkcs_7_asn"); ++ if (pkcs_7_asn == NULL) ++ return NULL; ++ } ++ switch(encodingType) { ++ case X509_ASN_ENCODING: ++ Py_INCREF(x509_asn); ++ return x509_asn; ++ case PKCS_7_ASN_ENCODING: ++ Py_INCREF(pkcs_7_asn); ++ return pkcs_7_asn; ++ default: ++ return PyInt_FromLong(encodingType); ++ } ++} ++ ++static PyObject* ++parseKeyUsage(PCCERT_CONTEXT pCertCtx, DWORD flags) ++{ ++ CERT_ENHKEY_USAGE *usage; ++ DWORD size, error, i; ++ PyObject *retval; ++ ++ if (!CertGetEnhancedKeyUsage(pCertCtx, flags, NULL, &size)) { ++ error = GetLastError(); ++ if (error == CRYPT_E_NOT_FOUND) { ++ Py_RETURN_TRUE; ++ } ++ return PyErr_SetFromWindowsErr(error); ++ } ++ ++ usage = (CERT_ENHKEY_USAGE*)PyMem_Malloc(size); ++ if (usage == NULL) { ++ return PyErr_NoMemory(); ++ } ++ ++ /* Now get the actual enhanced usage property */ ++ if (!CertGetEnhancedKeyUsage(pCertCtx, flags, usage, &size)) { ++ PyMem_Free(usage); ++ error = GetLastError(); ++ if (error == CRYPT_E_NOT_FOUND) { ++ Py_RETURN_TRUE; ++ } ++ return PyErr_SetFromWindowsErr(error); ++ } ++ retval = PySet_New(NULL); ++ if (retval == NULL) { ++ goto error; ++ } ++ for (i = 0; i < usage->cUsageIdentifier; ++i) { ++ if (usage->rgpszUsageIdentifier[i]) { ++ PyObject *oid; ++ int err; ++ oid = PyString_FromString(usage->rgpszUsageIdentifier[i]); ++ if (oid == NULL) { ++ Py_CLEAR(retval); ++ goto error; ++ } ++ err = PySet_Add(retval, oid); ++ Py_DECREF(oid); ++ if (err == -1) { ++ Py_CLEAR(retval); ++ goto error; ++ } ++ } ++ } ++ error: ++ PyMem_Free(usage); ++ return retval; ++} ++ ++PyDoc_STRVAR(PySSL_enum_certificates_doc, ++"enum_certificates(store_name) -> []\n\ ++\n\ ++Retrieve certificates from Windows' cert store. store_name may be one of\n\ ++'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ ++The function returns a list of (bytes, encoding_type, trust) tuples. The\n\ ++encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ ++PKCS_7_ASN_ENCODING. The trust setting is either a set of OIDs or the\n\ ++boolean True."); ++ ++static PyObject * ++PySSL_enum_certificates(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"store_name", NULL}; ++ char *store_name; ++ HCERTSTORE hStore = NULL; ++ PCCERT_CONTEXT pCertCtx = NULL; ++ PyObject *keyusage = NULL, *cert = NULL, *enc = NULL, *tup = NULL; ++ PyObject *result = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:enum_certificates", ++ kwlist, &store_name)) { ++ return NULL; ++ } ++ result = PyList_New(0); ++ if (result == NULL) { ++ return NULL; ++ } ++ hStore = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); ++ if (hStore == NULL) { ++ Py_DECREF(result); ++ return PyErr_SetFromWindowsErr(GetLastError()); ++ } ++ ++ while (pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) { ++ cert = PyBytes_FromStringAndSize((const char*)pCertCtx->pbCertEncoded, ++ pCertCtx->cbCertEncoded); ++ if (!cert) { ++ Py_CLEAR(result); ++ break; ++ } ++ if ((enc = certEncodingType(pCertCtx->dwCertEncodingType)) == NULL) { ++ Py_CLEAR(result); ++ break; ++ } ++ keyusage = parseKeyUsage(pCertCtx, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG); ++ if (keyusage == Py_True) { ++ Py_DECREF(keyusage); ++ keyusage = parseKeyUsage(pCertCtx, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG); ++ } ++ if (keyusage == NULL) { ++ Py_CLEAR(result); ++ break; ++ } ++ if ((tup = PyTuple_New(3)) == NULL) { ++ Py_CLEAR(result); ++ break; ++ } ++ PyTuple_SET_ITEM(tup, 0, cert); ++ cert = NULL; ++ PyTuple_SET_ITEM(tup, 1, enc); ++ enc = NULL; ++ PyTuple_SET_ITEM(tup, 2, keyusage); ++ keyusage = NULL; ++ if (PyList_Append(result, tup) < 0) { ++ Py_CLEAR(result); ++ break; ++ } ++ Py_CLEAR(tup); ++ } ++ if (pCertCtx) { ++ /* loop ended with an error, need to clean up context manually */ ++ CertFreeCertificateContext(pCertCtx); ++ } ++ ++ /* In error cases cert, enc and tup may not be NULL */ ++ Py_XDECREF(cert); ++ Py_XDECREF(enc); ++ Py_XDECREF(keyusage); ++ Py_XDECREF(tup); ++ ++ if (!CertCloseStore(hStore, 0)) { ++ /* This error case might shadow another exception.*/ ++ Py_XDECREF(result); ++ return PyErr_SetFromWindowsErr(GetLastError()); ++ } ++ return result; ++} ++ ++PyDoc_STRVAR(PySSL_enum_crls_doc, ++"enum_crls(store_name) -> []\n\ ++\n\ ++Retrieve CRLs from Windows' cert store. store_name may be one of\n\ ++'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ ++The function returns a list of (bytes, encoding_type) tuples. The\n\ ++encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ ++PKCS_7_ASN_ENCODING."); ++ ++static PyObject * ++PySSL_enum_crls(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"store_name", NULL}; ++ char *store_name; ++ HCERTSTORE hStore = NULL; ++ PCCRL_CONTEXT pCrlCtx = NULL; ++ PyObject *crl = NULL, *enc = NULL, *tup = NULL; ++ PyObject *result = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:enum_crls", ++ kwlist, &store_name)) { ++ return NULL; ++ } ++ result = PyList_New(0); ++ if (result == NULL) { ++ return NULL; ++ } ++ hStore = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); ++ if (hStore == NULL) { ++ Py_DECREF(result); ++ return PyErr_SetFromWindowsErr(GetLastError()); ++ } ++ ++ while (pCrlCtx = CertEnumCRLsInStore(hStore, pCrlCtx)) { ++ crl = PyBytes_FromStringAndSize((const char*)pCrlCtx->pbCrlEncoded, ++ pCrlCtx->cbCrlEncoded); ++ if (!crl) { ++ Py_CLEAR(result); ++ break; ++ } ++ if ((enc = certEncodingType(pCrlCtx->dwCertEncodingType)) == NULL) { ++ Py_CLEAR(result); ++ break; ++ } ++ if ((tup = PyTuple_New(2)) == NULL) { ++ Py_CLEAR(result); ++ break; ++ } ++ PyTuple_SET_ITEM(tup, 0, crl); ++ crl = NULL; ++ PyTuple_SET_ITEM(tup, 1, enc); ++ enc = NULL; ++ ++ if (PyList_Append(result, tup) < 0) { ++ Py_CLEAR(result); ++ break; ++ } ++ Py_CLEAR(tup); ++ } ++ if (pCrlCtx) { ++ /* loop ended with an error, need to clean up context manually */ ++ CertFreeCRLContext(pCrlCtx); ++ } ++ ++ /* In error cases cert, enc and tup may not be NULL */ ++ Py_XDECREF(crl); ++ Py_XDECREF(enc); ++ Py_XDECREF(tup); ++ ++ if (!CertCloseStore(hStore, 0)) { ++ /* This error case might shadow another exception.*/ ++ Py_XDECREF(result); ++ return PyErr_SetFromWindowsErr(GetLastError()); ++ } ++ return result; ++} ++ ++#endif /* _MSC_VER */ ++ ++/* List of functions exported by this module. */ + + static PyMethodDef PySSL_methods[] = { +- {"sslwrap", PySSL_sslwrap, +- METH_VARARGS, ssl_doc}, + {"_test_decode_cert", PySSL_test_decode_certificate, + METH_VARARGS}, + #ifdef HAVE_OPENSSL_RAND + {"RAND_add", PySSL_RAND_add, METH_VARARGS, + PySSL_RAND_add_doc}, +- {"RAND_egd", PySSL_RAND_egd, METH_O, ++ {"RAND_egd", PySSL_RAND_egd, METH_VARARGS, + PySSL_RAND_egd_doc}, + {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, + PySSL_RAND_status_doc}, + #endif ++ {"get_default_verify_paths", (PyCFunction)PySSL_get_default_verify_paths, ++ METH_NOARGS, PySSL_get_default_verify_paths_doc}, ++#ifdef _MSC_VER ++ {"enum_certificates", (PyCFunction)PySSL_enum_certificates, ++ METH_VARARGS | METH_KEYWORDS, PySSL_enum_certificates_doc}, ++ {"enum_crls", (PyCFunction)PySSL_enum_crls, ++ METH_VARARGS | METH_KEYWORDS, PySSL_enum_crls_doc}, ++#endif ++ {"txt2obj", (PyCFunction)PySSL_txt2obj, ++ METH_VARARGS | METH_KEYWORDS, PySSL_txt2obj_doc}, ++ {"nid2obj", (PyCFunction)PySSL_nid2obj, ++ METH_VARARGS, PySSL_nid2obj_doc}, + {NULL, NULL} /* Sentinel */ + }; + +@@ -1656,16 +3701,17 @@ static unsigned long _ssl_thread_id_func + return PyThread_get_thread_ident(); + } + +-static void _ssl_thread_locking_function (int mode, int n, const char *file, int line) { ++static void _ssl_thread_locking_function ++ (int mode, int n, const char *file, int line) { + /* this function is needed to perform locking on shared data + structures. (Note that OpenSSL uses a number of global data +- structures that will be implicitly shared whenever multiple threads +- use OpenSSL.) Multi-threaded applications will crash at random if +- it is not set. +- +- locking_function() must be able to handle up to CRYPTO_num_locks() +- different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and +- releases it otherwise. ++ structures that will be implicitly shared whenever multiple ++ threads use OpenSSL.) Multi-threaded applications will ++ crash at random if it is not set. ++ ++ locking_function() must be able to handle up to ++ CRYPTO_num_locks() different mutex locks. It sets the n-th ++ lock if mode & CRYPTO_LOCK, and releases it otherwise. + + file and line are the file number of the function setting the + lock. They can be useful for debugging. +@@ -1689,10 +3735,11 @@ static int _setup_ssl_threads(void) { + if (_ssl_locks == NULL) { + _ssl_locks_count = CRYPTO_num_locks(); + _ssl_locks = (PyThread_type_lock *) +- malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); ++ PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); + if (_ssl_locks == NULL) + return 0; +- memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); ++ memset(_ssl_locks, 0, ++ sizeof(PyThread_type_lock) * _ssl_locks_count); + for (i = 0; i < _ssl_locks_count; i++) { + _ssl_locks[i] = PyThread_allocate_lock(); + if (_ssl_locks[i] == NULL) { +@@ -1700,7 +3747,7 @@ static int _setup_ssl_threads(void) { + for (j = 0; j < i; j++) { + PyThread_free_lock(_ssl_locks[j]); + } +- free(_ssl_locks); ++ PyMem_Free(_ssl_locks); + return 0; + } + } +@@ -1716,14 +3763,39 @@ PyDoc_STRVAR(module_doc, + "Implementation module for SSL socket operations. See the socket module\n\ + for documentation."); + ++ ++ ++ ++static void ++parse_openssl_version(unsigned long libver, ++ unsigned int *major, unsigned int *minor, ++ unsigned int *fix, unsigned int *patch, ++ unsigned int *status) ++{ ++ *status = libver & 0xF; ++ libver >>= 4; ++ *patch = libver & 0xFF; ++ libver >>= 8; ++ *fix = libver & 0xFF; ++ libver >>= 8; ++ *minor = libver & 0xFF; ++ libver >>= 8; ++ *major = libver & 0xFF; ++} ++ + PyMODINIT_FUNC + init_ssl(void) + { + PyObject *m, *d, *r; + unsigned long libver; + unsigned int major, minor, fix, patch, status; ++ struct py_ssl_error_code *errcode; ++ struct py_ssl_library_code *libcode; + +- Py_TYPE(&PySSL_Type) = &PyType_Type; ++ if (PyType_Ready(&PySSLContext_Type) < 0) ++ return; ++ if (PyType_Ready(&PySSLSocket_Type) < 0) ++ return; + + m = Py_InitModule3("_ssl", PySSL_methods, module_doc); + if (m == NULL) +@@ -1746,15 +3818,53 @@ init_ssl(void) + OpenSSL_add_all_algorithms(); + + /* Add symbols to module dict */ +- PySSLErrorObject = PyErr_NewException("ssl.SSLError", +- PySocketModule.error, +- NULL); ++ PySSLErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLError", SSLError_doc, ++ PySocketModule.error, NULL); + if (PySSLErrorObject == NULL) + return; +- if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0) ++ ((PyTypeObject *)PySSLErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ++ PySSLZeroReturnErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLZeroReturnError", SSLZeroReturnError_doc, ++ PySSLErrorObject, NULL); ++ PySSLWantReadErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLWantReadError", SSLWantReadError_doc, ++ PySSLErrorObject, NULL); ++ PySSLWantWriteErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLWantWriteError", SSLWantWriteError_doc, ++ PySSLErrorObject, NULL); ++ PySSLSyscallErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLSyscallError", SSLSyscallError_doc, ++ PySSLErrorObject, NULL); ++ PySSLEOFErrorObject = PyErr_NewExceptionWithDoc( ++ "ssl.SSLEOFError", SSLEOFError_doc, ++ PySSLErrorObject, NULL); ++ if (PySSLZeroReturnErrorObject == NULL ++ || PySSLWantReadErrorObject == NULL ++ || PySSLWantWriteErrorObject == NULL ++ || PySSLSyscallErrorObject == NULL ++ || PySSLEOFErrorObject == NULL) ++ return; ++ ++ ((PyTypeObject *)PySSLZeroReturnErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ((PyTypeObject *)PySSLWantReadErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ((PyTypeObject *)PySSLWantWriteErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ((PyTypeObject *)PySSLSyscallErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ((PyTypeObject *)PySSLEOFErrorObject)->tp_str = (reprfunc)SSLError_str; ++ ++ if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0 ++ || PyDict_SetItemString(d, "SSLZeroReturnError", PySSLZeroReturnErrorObject) != 0 ++ || PyDict_SetItemString(d, "SSLWantReadError", PySSLWantReadErrorObject) != 0 ++ || PyDict_SetItemString(d, "SSLWantWriteError", PySSLWantWriteErrorObject) != 0 ++ || PyDict_SetItemString(d, "SSLSyscallError", PySSLSyscallErrorObject) != 0 ++ || PyDict_SetItemString(d, "SSLEOFError", PySSLEOFErrorObject) != 0) ++ return; ++ if (PyDict_SetItemString(d, "_SSLContext", ++ (PyObject *)&PySSLContext_Type) != 0) + return; +- if (PyDict_SetItemString(d, "SSLType", +- (PyObject *)&PySSL_Type) != 0) ++ if (PyDict_SetItemString(d, "_SSLSocket", ++ (PyObject *)&PySSLSocket_Type) != 0) + return; + PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", + PY_SSL_ERROR_ZERO_RETURN); +@@ -1782,6 +3892,66 @@ init_ssl(void) + PY_SSL_CERT_OPTIONAL); + PyModule_AddIntConstant(m, "CERT_REQUIRED", + PY_SSL_CERT_REQUIRED); ++ /* CRL verification for verification_flags */ ++ PyModule_AddIntConstant(m, "VERIFY_DEFAULT", ++ 0); ++ PyModule_AddIntConstant(m, "VERIFY_CRL_CHECK_LEAF", ++ X509_V_FLAG_CRL_CHECK); ++ PyModule_AddIntConstant(m, "VERIFY_CRL_CHECK_CHAIN", ++ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); ++ PyModule_AddIntConstant(m, "VERIFY_X509_STRICT", ++ X509_V_FLAG_X509_STRICT); ++ ++ /* Alert Descriptions from ssl.h */ ++ /* note RESERVED constants no longer intended for use have been removed */ ++ /* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 */ ++ ++#define ADD_AD_CONSTANT(s) \ ++ PyModule_AddIntConstant(m, "ALERT_DESCRIPTION_"#s, \ ++ SSL_AD_##s) ++ ++ ADD_AD_CONSTANT(CLOSE_NOTIFY); ++ ADD_AD_CONSTANT(UNEXPECTED_MESSAGE); ++ ADD_AD_CONSTANT(BAD_RECORD_MAC); ++ ADD_AD_CONSTANT(RECORD_OVERFLOW); ++ ADD_AD_CONSTANT(DECOMPRESSION_FAILURE); ++ ADD_AD_CONSTANT(HANDSHAKE_FAILURE); ++ ADD_AD_CONSTANT(BAD_CERTIFICATE); ++ ADD_AD_CONSTANT(UNSUPPORTED_CERTIFICATE); ++ ADD_AD_CONSTANT(CERTIFICATE_REVOKED); ++ ADD_AD_CONSTANT(CERTIFICATE_EXPIRED); ++ ADD_AD_CONSTANT(CERTIFICATE_UNKNOWN); ++ ADD_AD_CONSTANT(ILLEGAL_PARAMETER); ++ ADD_AD_CONSTANT(UNKNOWN_CA); ++ ADD_AD_CONSTANT(ACCESS_DENIED); ++ ADD_AD_CONSTANT(DECODE_ERROR); ++ ADD_AD_CONSTANT(DECRYPT_ERROR); ++ ADD_AD_CONSTANT(PROTOCOL_VERSION); ++ ADD_AD_CONSTANT(INSUFFICIENT_SECURITY); ++ ADD_AD_CONSTANT(INTERNAL_ERROR); ++ ADD_AD_CONSTANT(USER_CANCELLED); ++ ADD_AD_CONSTANT(NO_RENEGOTIATION); ++ /* Not all constants are in old OpenSSL versions */ ++#ifdef SSL_AD_UNSUPPORTED_EXTENSION ++ ADD_AD_CONSTANT(UNSUPPORTED_EXTENSION); ++#endif ++#ifdef SSL_AD_CERTIFICATE_UNOBTAINABLE ++ ADD_AD_CONSTANT(CERTIFICATE_UNOBTAINABLE); ++#endif ++#ifdef SSL_AD_UNRECOGNIZED_NAME ++ ADD_AD_CONSTANT(UNRECOGNIZED_NAME); ++#endif ++#ifdef SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE ++ ADD_AD_CONSTANT(BAD_CERTIFICATE_STATUS_RESPONSE); ++#endif ++#ifdef SSL_AD_BAD_CERTIFICATE_HASH_VALUE ++ ADD_AD_CONSTANT(BAD_CERTIFICATE_HASH_VALUE); ++#endif ++#ifdef SSL_AD_UNKNOWN_PSK_IDENTITY ++ ADD_AD_CONSTANT(UNKNOWN_PSK_IDENTITY); ++#endif ++ ++#undef ADD_AD_CONSTANT + + /* protocol versions */ + #ifndef OPENSSL_NO_SSL2 +@@ -1794,6 +3964,109 @@ init_ssl(void) + PY_SSL_VERSION_SSL23); + PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", + PY_SSL_VERSION_TLS1); ++#if HAVE_TLSv1_2 ++ PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_1", ++ PY_SSL_VERSION_TLS1_1); ++ PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", ++ PY_SSL_VERSION_TLS1_2); ++#endif ++ ++ /* protocol options */ ++ PyModule_AddIntConstant(m, "OP_ALL", ++ SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); ++ PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); ++ PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); ++ PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); ++#if HAVE_TLSv1_2 ++ PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); ++ PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); ++#endif ++ PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", ++ SSL_OP_CIPHER_SERVER_PREFERENCE); ++ PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); ++#ifdef SSL_OP_SINGLE_ECDH_USE ++ PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); ++#endif ++#ifdef SSL_OP_NO_COMPRESSION ++ PyModule_AddIntConstant(m, "OP_NO_COMPRESSION", ++ SSL_OP_NO_COMPRESSION); ++#endif ++ ++#if HAVE_SNI ++ r = Py_True; ++#else ++ r = Py_False; ++#endif ++ Py_INCREF(r); ++ PyModule_AddObject(m, "HAS_SNI", r); ++ ++#if HAVE_OPENSSL_FINISHED ++ r = Py_True; ++#else ++ r = Py_False; ++#endif ++ Py_INCREF(r); ++ PyModule_AddObject(m, "HAS_TLS_UNIQUE", r); ++ ++#ifdef OPENSSL_NO_ECDH ++ r = Py_False; ++#else ++ r = Py_True; ++#endif ++ Py_INCREF(r); ++ PyModule_AddObject(m, "HAS_ECDH", r); ++ ++#ifdef OPENSSL_NPN_NEGOTIATED ++ r = Py_True; ++#else ++ r = Py_False; ++#endif ++ Py_INCREF(r); ++ PyModule_AddObject(m, "HAS_NPN", r); ++ ++ /* Mappings for error codes */ ++ err_codes_to_names = PyDict_New(); ++ err_names_to_codes = PyDict_New(); ++ if (err_codes_to_names == NULL || err_names_to_codes == NULL) ++ return; ++ errcode = error_codes; ++ while (errcode->mnemonic != NULL) { ++ PyObject *mnemo, *key; ++ mnemo = PyUnicode_FromString(errcode->mnemonic); ++ key = Py_BuildValue("ii", errcode->library, errcode->reason); ++ if (mnemo == NULL || key == NULL) ++ return; ++ if (PyDict_SetItem(err_codes_to_names, key, mnemo)) ++ return; ++ if (PyDict_SetItem(err_names_to_codes, mnemo, key)) ++ return; ++ Py_DECREF(key); ++ Py_DECREF(mnemo); ++ errcode++; ++ } ++ if (PyModule_AddObject(m, "err_codes_to_names", err_codes_to_names)) ++ return; ++ if (PyModule_AddObject(m, "err_names_to_codes", err_names_to_codes)) ++ return; ++ ++ lib_codes_to_names = PyDict_New(); ++ if (lib_codes_to_names == NULL) ++ return; ++ libcode = library_codes; ++ while (libcode->library != NULL) { ++ PyObject *mnemo, *key; ++ key = PyLong_FromLong(libcode->code); ++ mnemo = PyUnicode_FromString(libcode->library); ++ if (key == NULL || mnemo == NULL) ++ return; ++ if (PyDict_SetItem(lib_codes_to_names, key, mnemo)) ++ return; ++ Py_DECREF(key); ++ Py_DECREF(mnemo); ++ libcode++; ++ } ++ if (PyModule_AddObject(m, "lib_codes_to_names", lib_codes_to_names)) ++ return; + + /* OpenSSL version */ + /* SSLeay() gives us the version of the library linked against, +@@ -1805,19 +4078,17 @@ init_ssl(void) + return; + if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + return; +- status = libver & 0xF; +- libver >>= 4; +- patch = libver & 0xFF; +- libver >>= 8; +- fix = libver & 0xFF; +- libver >>= 8; +- minor = libver & 0xFF; +- libver >>= 8; +- major = libver & 0xFF; ++ parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) + return; + r = PyString_FromString(SSLeay_version(SSLEAY_VERSION)); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + return; ++ ++ libver = OPENSSL_VERSION_NUMBER; ++ parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); ++ r = Py_BuildValue("IIIII", major, minor, fix, patch, status); ++ if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) ++ return; + } +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -1,8 +1,7 @@ + # Wrapper module for _ssl, providing some additional facilities + # implemented in Python. Written by Bill Janssen. + +-"""\ +-This module provides some more Pythonic support for SSL. ++"""This module provides some more Pythonic support for SSL. + + Object types: + +@@ -53,62 +52,461 @@ PROTOCOL_SSLv2 + PROTOCOL_SSLv3 + PROTOCOL_SSLv23 + PROTOCOL_TLSv1 ++PROTOCOL_TLSv1_1 ++PROTOCOL_TLSv1_2 ++ ++The following constants identify various SSL alert message descriptions as per ++http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 ++ ++ALERT_DESCRIPTION_CLOSE_NOTIFY ++ALERT_DESCRIPTION_UNEXPECTED_MESSAGE ++ALERT_DESCRIPTION_BAD_RECORD_MAC ++ALERT_DESCRIPTION_RECORD_OVERFLOW ++ALERT_DESCRIPTION_DECOMPRESSION_FAILURE ++ALERT_DESCRIPTION_HANDSHAKE_FAILURE ++ALERT_DESCRIPTION_BAD_CERTIFICATE ++ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE ++ALERT_DESCRIPTION_CERTIFICATE_REVOKED ++ALERT_DESCRIPTION_CERTIFICATE_EXPIRED ++ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN ++ALERT_DESCRIPTION_ILLEGAL_PARAMETER ++ALERT_DESCRIPTION_UNKNOWN_CA ++ALERT_DESCRIPTION_ACCESS_DENIED ++ALERT_DESCRIPTION_DECODE_ERROR ++ALERT_DESCRIPTION_DECRYPT_ERROR ++ALERT_DESCRIPTION_PROTOCOL_VERSION ++ALERT_DESCRIPTION_INSUFFICIENT_SECURITY ++ALERT_DESCRIPTION_INTERNAL_ERROR ++ALERT_DESCRIPTION_USER_CANCELLED ++ALERT_DESCRIPTION_NO_RENEGOTIATION ++ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION ++ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE ++ALERT_DESCRIPTION_UNRECOGNIZED_NAME ++ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE ++ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE ++ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY + """ + + import textwrap ++import re ++import sys ++import os ++from collections import namedtuple ++from contextlib import closing + + import _ssl # if we can't import it, let the error propagate + + from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION +-from _ssl import SSLError ++from _ssl import _SSLContext ++from _ssl import ( ++ SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError, ++ SSLSyscallError, SSLEOFError, ++ ) + from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED ++from _ssl import (VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN, ++ VERIFY_X509_STRICT) ++from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj + from _ssl import RAND_status, RAND_egd, RAND_add +-from _ssl import \ +- SSL_ERROR_ZERO_RETURN, \ +- SSL_ERROR_WANT_READ, \ +- SSL_ERROR_WANT_WRITE, \ +- SSL_ERROR_WANT_X509_LOOKUP, \ +- SSL_ERROR_SYSCALL, \ +- SSL_ERROR_SSL, \ +- SSL_ERROR_WANT_CONNECT, \ +- SSL_ERROR_EOF, \ +- SSL_ERROR_INVALID_ERROR_CODE +-from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +-_PROTOCOL_NAMES = { +- PROTOCOL_TLSv1: "TLSv1", +- PROTOCOL_SSLv23: "SSLv23", +- PROTOCOL_SSLv3: "SSLv3", +-} ++ ++def _import_symbols(prefix): ++ for n in dir(_ssl): ++ if n.startswith(prefix): ++ globals()[n] = getattr(_ssl, n) ++ ++_import_symbols('OP_') ++_import_symbols('ALERT_DESCRIPTION_') ++_import_symbols('SSL_ERROR_') ++_import_symbols('PROTOCOL_') ++ ++from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN ++ ++from _ssl import _OPENSSL_API_VERSION ++ ++_PROTOCOL_NAMES = {value: name for name, value in globals().items() if name.startswith('PROTOCOL_')} ++ + try: +- from _ssl import PROTOCOL_SSLv2 + _SSLv2_IF_EXISTS = PROTOCOL_SSLv2 +-except ImportError: ++except NameError: + _SSLv2_IF_EXISTS = None +-else: +- _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" + + from socket import socket, _fileobject, _delegate_methods, error as socket_error +-from socket import getnameinfo as _getnameinfo +-from socket import SOL_SOCKET, SO_TYPE, SOCK_STREAM ++if sys.platform == "win32": ++ from _ssl import enum_certificates, enum_crls ++ ++from socket import socket, AF_INET, SOCK_STREAM, create_connection ++from socket import SOL_SOCKET, SO_TYPE + import base64 # for DER-to-PEM translation + import errno + ++if _ssl.HAS_TLS_UNIQUE: ++ CHANNEL_BINDING_TYPES = ['tls-unique'] ++else: ++ CHANNEL_BINDING_TYPES = [] ++ + # Disable weak or insecure ciphers by default + # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') +-_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2' ++# Enable a better set of ciphers by default ++# This list has been explicitly chosen to: ++# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) ++# * Prefer ECDHE over DHE for better performance ++# * Prefer any AES-GCM over any AES-CBC for better performance and security ++# * Then Use HIGH cipher suites as a fallback ++# * Then Use 3DES as fallback which is secure but slow ++# * Finally use RC4 as a fallback which is problematic but needed for ++# compatibility some times. ++# * Disable NULL authentication, NULL encryption, and MD5 MACs for security ++# reasons ++_DEFAULT_CIPHERS = ( ++ 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' ++ 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' ++ 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' ++) + ++# Restricted and more secure ciphers for the server side ++# This list has been explicitly chosen to: ++# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) ++# * Prefer ECDHE over DHE for better performance ++# * Prefer any AES-GCM over any AES-CBC for better performance and security ++# * Then Use HIGH cipher suites as a fallback ++# * Then Use 3DES as fallback which is secure but slow ++# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for ++# security reasons ++_RESTRICTED_SERVER_CIPHERS = ( ++ 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' ++ 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' ++ '!eNULL:!MD5:!DSS:!RC4' ++) ++ ++ ++class CertificateError(ValueError): ++ pass ++ ++ ++def _dnsname_match(dn, hostname, max_wildcards=1): ++ """Matching according to RFC 6125, section 6.4.3 ++ ++ http://tools.ietf.org/html/rfc6125#section-6.4.3 ++ """ ++ pats = [] ++ if not dn: ++ return False ++ ++ pieces = dn.split(r'.') ++ leftmost = pieces[0] ++ remainder = pieces[1:] ++ ++ wildcards = leftmost.count('*') ++ if wildcards > max_wildcards: ++ # Issue #17980: avoid denials of service by refusing more ++ # than one wildcard per fragment. A survery of established ++ # policy among SSL implementations showed it to be a ++ # reasonable choice. ++ raise CertificateError( ++ "too many wildcards in certificate DNS name: " + repr(dn)) ++ ++ # speed up common case w/o wildcards ++ if not wildcards: ++ return dn.lower() == hostname.lower() ++ ++ # RFC 6125, section 6.4.3, subitem 1. ++ # The client SHOULD NOT attempt to match a presented identifier in which ++ # the wildcard character comprises a label other than the left-most label. ++ if leftmost == '*': ++ # When '*' is a fragment by itself, it matches a non-empty dotless ++ # fragment. ++ pats.append('[^.]+') ++ elif leftmost.startswith('xn--') or hostname.startswith('xn--'): ++ # RFC 6125, section 6.4.3, subitem 3. ++ # The client SHOULD NOT attempt to match a presented identifier ++ # where the wildcard character is embedded within an A-label or ++ # U-label of an internationalized domain name. ++ pats.append(re.escape(leftmost)) ++ else: ++ # Otherwise, '*' matches any dotless string, e.g. www* ++ pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) ++ ++ # add the remaining fragments, ignore any wildcards ++ for frag in remainder: ++ pats.append(re.escape(frag)) ++ ++ pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) ++ return pat.match(hostname) ++ ++ ++def match_hostname(cert, hostname): ++ """Verify that *cert* (in decoded format as returned by ++ SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 ++ rules are followed, but IP addresses are not accepted for *hostname*. ++ ++ CertificateError is raised on failure. On success, the function ++ returns nothing. ++ """ ++ if not cert: ++ raise ValueError("empty or no certificate, match_hostname needs a " ++ "SSL socket or SSL context with either " ++ "CERT_OPTIONAL or CERT_REQUIRED") ++ dnsnames = [] ++ san = cert.get('subjectAltName', ()) ++ for key, value in san: ++ if key == 'DNS': ++ if _dnsname_match(value, hostname): ++ return ++ dnsnames.append(value) ++ if not dnsnames: ++ # The subject is only checked when there is no dNSName entry ++ # in subjectAltName ++ for sub in cert.get('subject', ()): ++ for key, value in sub: ++ # XXX according to RFC 2818, the most specific Common Name ++ # must be used. ++ if key == 'commonName': ++ if _dnsname_match(value, hostname): ++ return ++ dnsnames.append(value) ++ if len(dnsnames) > 1: ++ raise CertificateError("hostname %r " ++ "doesn't match either of %s" ++ % (hostname, ', '.join(map(repr, dnsnames)))) ++ elif len(dnsnames) == 1: ++ raise CertificateError("hostname %r " ++ "doesn't match %r" ++ % (hostname, dnsnames[0])) ++ else: ++ raise CertificateError("no appropriate commonName or " ++ "subjectAltName fields were found") ++ ++ ++DefaultVerifyPaths = namedtuple("DefaultVerifyPaths", ++ "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env " ++ "openssl_capath") ++ ++def get_default_verify_paths(): ++ """Return paths to default cafile and capath. ++ """ ++ parts = _ssl.get_default_verify_paths() ++ ++ # environment vars shadow paths ++ cafile = os.environ.get(parts[0], parts[1]) ++ capath = os.environ.get(parts[2], parts[3]) ++ ++ return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None, ++ capath if os.path.isdir(capath) else None, ++ *parts) ++ ++ ++class _ASN1Object(namedtuple("_ASN1Object", "nid shortname longname oid")): ++ """ASN.1 object identifier lookup ++ """ ++ __slots__ = () ++ ++ def __new__(cls, oid): ++ return super(_ASN1Object, cls).__new__(cls, *_txt2obj(oid, name=False)) ++ ++ @classmethod ++ def fromnid(cls, nid): ++ """Create _ASN1Object from OpenSSL numeric ID ++ """ ++ return super(_ASN1Object, cls).__new__(cls, *_nid2obj(nid)) ++ ++ @classmethod ++ def fromname(cls, name): ++ """Create _ASN1Object from short name, long name or OID ++ """ ++ return super(_ASN1Object, cls).__new__(cls, *_txt2obj(name, name=True)) ++ ++ ++class Purpose(_ASN1Object): ++ """SSLContext purpose flags with X509v3 Extended Key Usage objects ++ """ ++ ++Purpose.SERVER_AUTH = Purpose('1.3.6.1.5.5.7.3.1') ++Purpose.CLIENT_AUTH = Purpose('1.3.6.1.5.5.7.3.2') ++ ++ ++class SSLContext(_SSLContext): ++ """An SSLContext holds various SSL-related configuration options and ++ data, such as certificates and possibly a private key.""" ++ ++ __slots__ = ('protocol', '__weakref__') ++ _windows_cert_stores = ("CA", "ROOT") ++ ++ def __new__(cls, protocol, *args, **kwargs): ++ self = _SSLContext.__new__(cls, protocol) ++ if protocol != _SSLv2_IF_EXISTS: ++ self.set_ciphers(_DEFAULT_CIPHERS) ++ return self ++ ++ def __init__(self, protocol): ++ self.protocol = protocol ++ ++ def wrap_socket(self, sock, server_side=False, ++ do_handshake_on_connect=True, ++ suppress_ragged_eofs=True, ++ server_hostname=None): ++ return SSLSocket(sock=sock, server_side=server_side, ++ do_handshake_on_connect=do_handshake_on_connect, ++ suppress_ragged_eofs=suppress_ragged_eofs, ++ server_hostname=server_hostname, ++ _context=self) ++ ++ def set_npn_protocols(self, npn_protocols): ++ protos = bytearray() ++ for protocol in npn_protocols: ++ b = protocol.encode('ascii') ++ if len(b) == 0 or len(b) > 255: ++ raise SSLError('NPN protocols must be 1 to 255 in length') ++ protos.append(len(b)) ++ protos.extend(b) ++ ++ self._set_npn_protocols(protos) ++ ++ def _load_windows_store_certs(self, storename, purpose): ++ certs = bytearray() ++ for cert, encoding, trust in enum_certificates(storename): ++ # CA certs are never PKCS#7 encoded ++ if encoding == "x509_asn": ++ if trust is True or purpose.oid in trust: ++ certs.extend(cert) ++ self.load_verify_locations(cadata=certs) ++ return certs ++ ++ def load_default_certs(self, purpose=Purpose.SERVER_AUTH): ++ if not isinstance(purpose, _ASN1Object): ++ raise TypeError(purpose) ++ if sys.platform == "win32": ++ for storename in self._windows_cert_stores: ++ self._load_windows_store_certs(storename, purpose) ++ else: ++ self.set_default_verify_paths() ++ ++ ++def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, ++ capath=None, cadata=None): ++ """Create a SSLContext object with default settings. ++ ++ NOTE: The protocol and settings may change anytime without prior ++ deprecation. The values represent a fair balance between maximum ++ compatibility and security. ++ """ ++ if not isinstance(purpose, _ASN1Object): ++ raise TypeError(purpose) ++ ++ context = SSLContext(PROTOCOL_SSLv23) ++ ++ # SSLv2 considered harmful. ++ context.options |= OP_NO_SSLv2 ++ ++ # SSLv3 has problematic security and is only required for really old ++ # clients such as IE6 on Windows XP ++ context.options |= OP_NO_SSLv3 ++ ++ # disable compression to prevent CRIME attacks (OpenSSL 1.0+) ++ context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0) ++ ++ if purpose == Purpose.SERVER_AUTH: ++ # verify certs and host name in client mode ++ context.verify_mode = CERT_REQUIRED ++ context.check_hostname = True ++ elif purpose == Purpose.CLIENT_AUTH: ++ # Prefer the server's ciphers by default so that we get stronger ++ # encryption ++ context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) ++ ++ # Use single use keys in order to improve forward secrecy ++ context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0) ++ context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0) ++ ++ # disallow ciphers with known vulnerabilities ++ context.set_ciphers(_RESTRICTED_SERVER_CIPHERS) ++ ++ if cafile or capath or cadata: ++ context.load_verify_locations(cafile, capath, cadata) ++ elif context.verify_mode != CERT_NONE: ++ # no explicit cafile, capath or cadata but the verify mode is ++ # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system ++ # root CA certificates for the given purpose. This may fail silently. ++ context.load_default_certs(purpose) ++ return context ++ ++ ++def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, ++ check_hostname=False, purpose=Purpose.SERVER_AUTH, ++ certfile=None, keyfile=None, ++ cafile=None, capath=None, cadata=None): ++ """Create a SSLContext object for Python stdlib modules ++ ++ All Python stdlib modules shall use this function to create SSLContext ++ objects in order to keep common settings in one place. The configuration ++ is less restrict than create_default_context()'s to increase backward ++ compatibility. ++ """ ++ if not isinstance(purpose, _ASN1Object): ++ raise TypeError(purpose) ++ ++ context = SSLContext(protocol) ++ # SSLv2 considered harmful. ++ context.options |= OP_NO_SSLv2 ++ ++ if cert_reqs is not None: ++ context.verify_mode = cert_reqs ++ context.check_hostname = check_hostname ++ ++ if keyfile and not certfile: ++ raise ValueError("certfile must be specified") ++ if certfile or keyfile: ++ context.load_cert_chain(certfile, keyfile) ++ ++ # load CA root certs ++ if cafile or capath or cadata: ++ context.load_verify_locations(cafile, capath, cadata) ++ elif context.verify_mode != CERT_NONE: ++ # no explicit cafile, capath or cadata but the verify mode is ++ # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system ++ # root CA certificates for the given purpose. This may fail silently. ++ context.load_default_certs(purpose) ++ ++ return context + + class SSLSocket(socket): +- + """This class implements a subtype of socket.socket that wraps + the underlying OS socket in an SSL context when necessary, and + provides read and write methods over that channel.""" + +- def __init__(self, sock, keyfile=None, certfile=None, ++ def __init__(self, sock=None, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, +- suppress_ragged_eofs=True, ciphers=None): ++ family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, ++ suppress_ragged_eofs=True, npn_protocols=None, ciphers=None, ++ server_hostname=None, ++ _context=None): ++ ++ if _context: ++ self._context = _context ++ else: ++ if server_side and not certfile: ++ raise ValueError("certfile must be specified for server-side " ++ "operations") ++ if keyfile and not certfile: ++ raise ValueError("certfile must be specified") ++ if certfile and not keyfile: ++ keyfile = certfile ++ self._context = SSLContext(ssl_version) ++ self._context.verify_mode = cert_reqs ++ if ca_certs: ++ self._context.load_verify_locations(ca_certs) ++ if certfile: ++ self._context.load_cert_chain(certfile, keyfile) ++ if npn_protocols: ++ self._context.set_npn_protocols(npn_protocols) ++ if ciphers: ++ self._context.set_ciphers(ciphers) ++ self.keyfile = keyfile ++ self.certfile = certfile ++ self.cert_reqs = cert_reqs ++ self.ssl_version = ssl_version ++ self.ca_certs = ca_certs ++ self.ciphers = ciphers + # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get + # mixed in. + if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: +@@ -122,98 +520,161 @@ class SSLSocket(socket): + delattr(self, attr) + except AttributeError: + pass ++ if server_side and server_hostname: ++ raise ValueError("server_hostname can only be specified " ++ "in client mode") ++ if self._context.check_hostname and not server_hostname: ++ if HAS_SNI: ++ raise ValueError("check_hostname requires server_hostname") ++ else: ++ raise ValueError("check_hostname requires server_hostname, " ++ "but it's not supported by your OpenSSL " ++ "library") ++ self.server_side = server_side ++ self.server_hostname = server_hostname ++ self.do_handshake_on_connect = do_handshake_on_connect ++ self.suppress_ragged_eofs = suppress_ragged_eofs + +- if ciphers is None and ssl_version != _SSLv2_IF_EXISTS: +- ciphers = _DEFAULT_CIPHERS +- +- if certfile and not keyfile: +- keyfile = certfile +- # see if it's connected ++ # See if we are connected + try: +- socket.getpeername(self) +- except socket_error, e: ++ self.getpeername() ++ except socket_error as e: + if e.errno != errno.ENOTCONN: + raise +- # no, no connection yet +- self._connected = False +- self._sslobj = None ++ connected = False + else: +- # yes, create the SSL object +- self._connected = True +- self._sslobj = _ssl.sslwrap(self._sock, server_side, +- keyfile, certfile, +- cert_reqs, ssl_version, ca_certs, +- ciphers) +- if do_handshake_on_connect: +- self.do_handshake() +- self.keyfile = keyfile +- self.certfile = certfile +- self.cert_reqs = cert_reqs +- self.ssl_version = ssl_version +- self.ca_certs = ca_certs +- self.ciphers = ciphers +- self.do_handshake_on_connect = do_handshake_on_connect +- self.suppress_ragged_eofs = suppress_ragged_eofs ++ connected = True ++ ++ self._closed = False ++ self._sslobj = None ++ self._connected = connected ++ if connected: ++ # create the SSL object ++ try: ++ self._sslobj = self._context._wrap_socket(self._sock, server_side, ++ server_hostname, ssl_sock=self) ++ if do_handshake_on_connect: ++ timeout = self.gettimeout() ++ if timeout == 0.0: ++ # non-blocking ++ raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets") ++ self.do_handshake() ++ ++ except (OSError, ValueError): ++ self.close() ++ raise + self._makefile_refs = 0 + +- def read(self, len=1024): ++ @property ++ def context(self): ++ return self._context + ++ @context.setter ++ def context(self, ctx): ++ self._context = ctx ++ self._sslobj.context = ctx ++ ++ def dup(self): ++ raise NotImplemented("Can't dup() %s instances" % ++ self.__class__.__name__) ++ ++ def _checkClosed(self, msg=None): ++ # raise an exception here if you wish to check for spurious closes ++ pass ++ ++ def _check_connected(self): ++ if not self._connected: ++ # getpeername() will raise ENOTCONN if the socket is really ++ # not connected; note that we can be connected even without ++ # _connected being set, e.g. if connect() first returned ++ # EAGAIN. ++ self.getpeername() ++ ++ def read(self, len=0, buffer=None): + """Read up to LEN bytes and return them. + Return zero-length string on EOF.""" + ++ self._checkClosed() ++ if not self._sslobj: ++ raise ValueError("Read on closed or unwrapped SSL socket.") + try: +- return self._sslobj.read(len) +- except SSLError, x: ++ if buffer is not None: ++ v = self._sslobj.read(len, buffer) ++ else: ++ v = self._sslobj.read(len or 1024) ++ return v ++ except SSLError as x: + if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: +- return '' ++ if buffer is not None: ++ return 0 ++ else: ++ return b'' + else: + raise + + def write(self, data): +- + """Write DATA to the underlying SSL channel. Returns + number of bytes of DATA actually transmitted.""" + ++ self._checkClosed() ++ if not self._sslobj: ++ raise ValueError("Write on closed or unwrapped SSL socket.") + return self._sslobj.write(data) + + def getpeercert(self, binary_form=False): +- + """Returns a formatted version of the data in the + certificate provided by the other end of the SSL channel. + Return None if no certificate was provided, {} if a + certificate was provided, but not validated.""" + ++ self._checkClosed() ++ self._check_connected() + return self._sslobj.peer_certificate(binary_form) + ++ def selected_npn_protocol(self): ++ self._checkClosed() ++ if not self._sslobj or not _ssl.HAS_NPN: ++ return None ++ else: ++ return self._sslobj.selected_npn_protocol() ++ + def cipher(self): +- ++ self._checkClosed() + if not self._sslobj: + return None + else: + return self._sslobj.cipher() + ++ def compression(self): ++ self._checkClosed() ++ if not self._sslobj: ++ return None ++ else: ++ return self._sslobj.compression() ++ + def send(self, data, flags=0): ++ self._checkClosed() + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to send() on %s" % + self.__class__) +- while True: +- try: +- v = self._sslobj.write(data) +- except SSLError, x: +- if x.args[0] == SSL_ERROR_WANT_READ: +- return 0 +- elif x.args[0] == SSL_ERROR_WANT_WRITE: +- return 0 +- else: +- raise ++ try: ++ v = self._sslobj.write(data) ++ except SSLError as x: ++ if x.args[0] == SSL_ERROR_WANT_READ: ++ return 0 ++ elif x.args[0] == SSL_ERROR_WANT_WRITE: ++ return 0 + else: +- return v ++ raise ++ else: ++ return v + else: + return self._sock.send(data, flags) + + def sendto(self, data, flags_or_addr, addr=None): ++ self._checkClosed() + if self._sslobj: + raise ValueError("sendto not allowed on instances of %s" % + self.__class__) +@@ -222,7 +683,9 @@ class SSLSocket(socket): + else: + return self._sock.sendto(data, flags_or_addr, addr) + ++ + def sendall(self, data, flags=0): ++ self._checkClosed() + if self._sslobj: + if flags != 0: + raise ValueError( +@@ -238,6 +701,7 @@ class SSLSocket(socket): + return socket.sendall(self, data, flags) + + def recv(self, buflen=1024, flags=0): ++ self._checkClosed() + if self._sslobj: + if flags != 0: + raise ValueError( +@@ -248,6 +712,7 @@ class SSLSocket(socket): + return self._sock.recv(buflen, flags) + + def recv_into(self, buffer, nbytes=None, flags=0): ++ self._checkClosed() + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: +@@ -257,14 +722,12 @@ class SSLSocket(socket): + raise ValueError( + "non-zero flags not allowed in calls to recv_into() on %s" % + self.__class__) +- tmp_buffer = self.read(nbytes) +- v = len(tmp_buffer) +- buffer[:v] = tmp_buffer +- return v ++ return self.read(nbytes, buffer) + else: + return self._sock.recv_into(buffer, nbytes, flags) + + def recvfrom(self, buflen=1024, flags=0): ++ self._checkClosed() + if self._sslobj: + raise ValueError("recvfrom not allowed on instances of %s" % + self.__class__) +@@ -272,27 +735,23 @@ class SSLSocket(socket): + return self._sock.recvfrom(buflen, flags) + + def recvfrom_into(self, buffer, nbytes=None, flags=0): ++ self._checkClosed() + if self._sslobj: + raise ValueError("recvfrom_into not allowed on instances of %s" % + self.__class__) + else: + return self._sock.recvfrom_into(buffer, nbytes, flags) + ++ + def pending(self): ++ self._checkClosed() + if self._sslobj: + return self._sslobj.pending() + else: + return 0 + +- def unwrap(self): +- if self._sslobj: +- s = self._sslobj.shutdown() +- self._sslobj = None +- return s +- else: +- raise ValueError("No SSL wrapper around " + str(self)) +- + def shutdown(self, how): ++ self._checkClosed() + self._sslobj = None + socket.shutdown(self, how) + +@@ -303,32 +762,55 @@ class SSLSocket(socket): + else: + self._makefile_refs -= 1 + +- def do_handshake(self): ++ def unwrap(self): ++ if self._sslobj: ++ s = self._sslobj.shutdown() ++ self._sslobj = None ++ return s ++ else: ++ raise ValueError("No SSL wrapper around " + str(self)) + ++ def _real_close(self): ++ self._sslobj = None ++ socket._real_close(self) ++ ++ def do_handshake(self, block=False): + """Perform a TLS/SSL handshake.""" ++ self._check_connected() ++ timeout = self.gettimeout() ++ try: ++ if timeout == 0.0 and block: ++ self.settimeout(None) ++ self._sslobj.do_handshake() ++ finally: ++ self.settimeout(timeout) + +- self._sslobj.do_handshake() ++ if self.context.check_hostname: ++ if not self.server_hostname: ++ raise ValueError("check_hostname needs server_hostname " ++ "argument") ++ match_hostname(self.getpeercert(), self.server_hostname) + +- def _real_connect(self, addr, return_errno): ++ def _real_connect(self, addr, connect_ex): ++ if self.server_side: ++ raise ValueError("can't connect in server-side mode") + # Here we assume that the socket is client-side, and not + # connected at the time of the call. We connect it, then wrap it. + if self._connected: + raise ValueError("attempt to connect already-connected SSLSocket!") +- self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, +- self.cert_reqs, self.ssl_version, +- self.ca_certs, self.ciphers) ++ self._sslobj = self.context._wrap_socket(self._sock, False, self.server_hostname, ssl_sock=self) + try: +- if return_errno: ++ if connect_ex: + rc = socket.connect_ex(self, addr) + else: + rc = None + socket.connect(self, addr) + if not rc: ++ self._connected = True + if self.do_handshake_on_connect: + self.do_handshake() +- self._connected = True + return rc +- except socket_error: ++ except (OSError, ValueError): + self._sslobj = None + raise + +@@ -343,27 +825,16 @@ class SSLSocket(socket): + return self._real_connect(addr, True) + + def accept(self): +- + """Accepts a new connection from a remote client, and returns + a tuple containing that new connection wrapped with a server-side + SSL channel, and the address of the remote client.""" + + newsock, addr = socket.accept(self) +- try: +- return (SSLSocket(newsock, +- keyfile=self.keyfile, +- certfile=self.certfile, +- server_side=True, +- cert_reqs=self.cert_reqs, +- ssl_version=self.ssl_version, +- ca_certs=self.ca_certs, +- ciphers=self.ciphers, +- do_handshake_on_connect=self.do_handshake_on_connect, +- suppress_ragged_eofs=self.suppress_ragged_eofs), +- addr) +- except socket_error as e: +- newsock.close() +- raise e ++ newsock = self.context.wrap_socket(newsock, ++ do_handshake_on_connect=self.do_handshake_on_connect, ++ suppress_ragged_eofs=self.suppress_ragged_eofs, ++ server_side=True) ++ return newsock, addr + + def makefile(self, mode='r', bufsize=-1): + +@@ -376,54 +847,81 @@ class SSLSocket(socket): + # the file-like object. + return _fileobject(self, mode, bufsize, close=True) + ++ def get_channel_binding(self, cb_type="tls-unique"): ++ """Get channel binding data for current connection. Raise ValueError ++ if the requested `cb_type` is not supported. Return bytes of the data ++ or None if the data is not available (e.g. before the handshake). ++ """ ++ if cb_type not in CHANNEL_BINDING_TYPES: ++ raise ValueError("Unsupported channel binding type") ++ if cb_type != "tls-unique": ++ raise NotImplementedError( ++ "{0} channel binding type not implemented" ++ .format(cb_type)) ++ if self._sslobj is None: ++ return None ++ return self._sslobj.tls_unique_cb() + + + def wrap_socket(sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, +- suppress_ragged_eofs=True, ciphers=None): ++ suppress_ragged_eofs=True, ++ ciphers=None): + +- return SSLSocket(sock, keyfile=keyfile, certfile=certfile, ++ return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, + server_side=server_side, cert_reqs=cert_reqs, + ssl_version=ssl_version, ca_certs=ca_certs, + do_handshake_on_connect=do_handshake_on_connect, + suppress_ragged_eofs=suppress_ragged_eofs, + ciphers=ciphers) + +- + # some utility functions + + def cert_time_to_seconds(cert_time): ++ """Return the time in seconds since the Epoch, given the timestring ++ representing the "notBefore" or "notAfter" date from a certificate ++ in ``"%b %d %H:%M:%S %Y %Z"`` strptime format (C locale). + +- """Takes a date-time string in standard ASN1_print form +- ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return +- a Python time value in seconds past the epoch.""" ++ "notBefore" or "notAfter" dates must use UTC (RFC 5280). + +- import time +- return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT")) ++ Month is one of: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ++ UTC should be specified as GMT (see ASN1_TIME_print()) ++ """ ++ from time import strptime ++ from calendar import timegm ++ ++ months = ( ++ "Jan","Feb","Mar","Apr","May","Jun", ++ "Jul","Aug","Sep","Oct","Nov","Dec" ++ ) ++ time_format = ' %d %H:%M:%S %Y GMT' # NOTE: no month, fixed GMT ++ try: ++ month_number = months.index(cert_time[:3].title()) + 1 ++ except ValueError: ++ raise ValueError('time data %r does not match ' ++ 'format "%%b%s"' % (cert_time, time_format)) ++ else: ++ # found valid month ++ tt = strptime(cert_time[3:], time_format) ++ # return an integer, the previous mktime()-based implementation ++ # returned a float (fractional seconds are always zero here). ++ return timegm((tt[0], month_number) + tt[2:6]) + + PEM_HEADER = "-----BEGIN CERTIFICATE-----" + PEM_FOOTER = "-----END CERTIFICATE-----" + + def DER_cert_to_PEM_cert(der_cert_bytes): +- + """Takes a certificate in binary DER format and returns the + PEM version of it as a string.""" + +- if hasattr(base64, 'standard_b64encode'): +- # preferred because older API gets line-length wrong +- f = base64.standard_b64encode(der_cert_bytes) +- return (PEM_HEADER + '\n' + +- textwrap.fill(f, 64) + '\n' + +- PEM_FOOTER + '\n') +- else: +- return (PEM_HEADER + '\n' + +- base64.encodestring(der_cert_bytes) + +- PEM_FOOTER + '\n') ++ f = base64.standard_b64encode(der_cert_bytes).decode('ascii') ++ return (PEM_HEADER + '\n' + ++ textwrap.fill(f, 64) + '\n' + ++ PEM_FOOTER + '\n') + + def PEM_cert_to_DER_cert(pem_cert_string): +- + """Takes a certificate in ASCII PEM format and returns the + DER-encoded version of it as a byte sequence""" + +@@ -434,25 +932,25 @@ def PEM_cert_to_DER_cert(pem_cert_string + raise ValueError("Invalid PEM encoding; must end with %s" + % PEM_FOOTER) + d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] +- return base64.decodestring(d) ++ return base64.decodestring(d.encode('ASCII', 'strict')) + +-def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): +- ++def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None): + """Retrieve the certificate from the server at the specified address, + and return it as a PEM-encoded string. + If 'ca_certs' is specified, validate the server cert against it. + If 'ssl_version' is specified, use it in the connection attempt.""" + + host, port = addr +- if (ca_certs is not None): ++ if ca_certs is not None: + cert_reqs = CERT_REQUIRED + else: + cert_reqs = CERT_NONE +- s = wrap_socket(socket(), ssl_version=ssl_version, +- cert_reqs=cert_reqs, ca_certs=ca_certs) +- s.connect(addr) +- dercert = s.getpeercert(True) +- s.close() ++ context = _create_stdlib_context(ssl_version, ++ cert_reqs=cert_reqs, ++ cafile=ca_certs) ++ with closing(create_connection(addr)) as sock: ++ with closing(context.wrap_socket(sock)) as sslsock: ++ dercert = sslsock.getpeercert(True) + return DER_cert_to_PEM_cert(dercert) + + def get_protocol_name(protocol_code): +diff -up Python-2.7.5/Lib/ssl.py.makefile Python-2.7.5/Lib/ssl.py +--- Python-2.7.5/Lib/ssl.py.makefile 2015-03-04 16:48:10.040698640 +0100 ++++ Python-2.7.5/Lib/ssl.py 2015-03-04 16:48:32.885909530 +0100 +@@ -481,6 +481,7 @@ class SSLSocket(socket): + server_hostname=None, + _context=None): + ++ self._makefile_refs = 0 + if _context: + self._context = _context + else: +@@ -563,7 +564,6 @@ class SSLSocket(socket): + except (OSError, ValueError): + self.close() + raise +- self._makefile_refs = 0 + + @property + def context(self): + +diff --git a/Lib/test/capath/4e1295a3.0 b/Lib/test/capath/4e1295a3.0 +new file mode 100644 +--- /dev/null ++++ b/Lib/test/capath/4e1295a3.0 +@@ -0,0 +1,14 @@ ++-----BEGIN CERTIFICATE----- ++MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD ++VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv ++bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy ++dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X ++DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw ++EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l ++dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT ++EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp ++MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw ++L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN ++BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX ++9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= ++-----END CERTIFICATE----- +diff --git a/Lib/test/capath/5ed36f99.0 b/Lib/test/capath/5ed36f99.0 +new file mode 100644 +--- /dev/null ++++ b/Lib/test/capath/5ed36f99.0 +@@ -0,0 +1,41 @@ ++-----BEGIN CERTIFICATE----- ++MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 ++IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB ++IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA ++Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO ++BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi ++MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ ++ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC ++CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ ++8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 ++zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y ++fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 ++w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc ++G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k ++epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q ++laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ ++QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU ++fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 ++YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w ++ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY ++gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe ++MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 ++IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy ++dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw ++czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 ++dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl ++aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC ++AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg ++b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB ++ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc ++nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg ++18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c ++gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl ++Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY ++sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T ++SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF ++CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum ++GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk ++zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW ++omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ++-----END CERTIFICATE----- +diff --git a/Lib/test/capath/6e88d7b8.0 b/Lib/test/capath/6e88d7b8.0 +new file mode 100644 +--- /dev/null ++++ b/Lib/test/capath/6e88d7b8.0 +@@ -0,0 +1,14 @@ ++-----BEGIN CERTIFICATE----- ++MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD ++VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv ++bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy ++dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X ++DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw ++EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l ++dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT ++EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp ++MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw ++L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN ++BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX ++9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= ++-----END CERTIFICATE----- +diff --git a/Lib/test/capath/99d0fa06.0 b/Lib/test/capath/99d0fa06.0 +new file mode 100644 +--- /dev/null ++++ b/Lib/test/capath/99d0fa06.0 +@@ -0,0 +1,41 @@ ++-----BEGIN CERTIFICATE----- ++MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 ++IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB ++IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA ++Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO ++BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi ++MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ ++ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC ++CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ ++8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 ++zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y ++fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 ++w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc ++G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k ++epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q ++laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ ++QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU ++fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 ++YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w ++ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY ++gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe ++MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 ++IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy ++dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw ++czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 ++dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl ++aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC ++AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg ++b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB ++ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc ++nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg ++18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c ++gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl ++Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY ++sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T ++SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF ++CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum ++GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk ++zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW ++omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ++-----END CERTIFICATE----- +diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/dh512.pem +@@ -0,0 +1,9 @@ ++-----BEGIN DH PARAMETERS----- ++MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak ++XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC ++-----END DH PARAMETERS----- ++ ++These are the 512 bit DH parameters from "Assigned Number for SKIP Protocols" ++(http://www.skip-vpn.org/spec/numbers.html). ++See there for how they were generated. ++Note that g is not a generator, but this is not a problem since p is a safe prime. +diff --git a/Lib/test/keycert.passwd.pem b/Lib/test/keycert.passwd.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/keycert.passwd.pem +@@ -0,0 +1,33 @@ ++-----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/Lib/test/keycert3.pem b/Lib/test/keycert3.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/keycert3.pem +@@ -0,0 +1,73 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP ++jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM ++9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ ++aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe ++yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j ++y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+ ++AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW ++5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL ++9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9 ++1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT ++DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh ++1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m ++JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3 ++RnJdHOMXWem7/w== ++-----END PRIVATE KEY----- ++Certificate: ++ Data: ++ Version: 1 (0x0) ++ Serial Number: 12723342612721443281 (0xb09264b1f2da21d1) ++ Signature Algorithm: sha1WithRSAEncryption ++ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server ++ Validity ++ Not Before: Jan 4 19:47:07 2013 GMT ++ Not After : Nov 13 19:47:07 2022 GMT ++ Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost ++ Subject Public Key Info: ++ Public Key Algorithm: rsaEncryption ++ Public-Key: (1024 bit) ++ Modulus: ++ 00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d: ++ 7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb: ++ c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99: ++ 96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c: ++ f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93: ++ 34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23: ++ f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5: ++ af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6: ++ 21:82:a5:3c:88:e5:be:1b:b1 ++ Exponent: 65537 (0x10001) ++ Signature Algorithm: sha1WithRSAEncryption ++ 2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a: ++ e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93: ++ f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13: ++ e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92: ++ d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59: ++ 00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8: ++ ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1: ++ 21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75: ++ 8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96: ++ 0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48: ++ 8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a: ++ f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6: ++ 3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41: ++ a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb: ++ fc:a9:94:71 ++-----BEGIN CERTIFICATE----- ++MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY ++WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV ++BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3 ++WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV ++BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv ++c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C ++tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola ++N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1 ++TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR ++iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG ++xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo ++5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv ++mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF ++YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh ++2EJ36/yplHE= ++-----END CERTIFICATE----- +diff --git a/Lib/test/keycert4.pem b/Lib/test/keycert4.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/keycert4.pem +@@ -0,0 +1,73 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5UQiMI5VkNs2Qv ++L7gUaiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2 ++NkX0ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1 ++L2OQhEx1GM6RydHdgX69G64LXcY5AgMBAAECgYAhsRMfJkb9ERLMl/oG/5sLQu9L ++pWDKt6+ZwdxzlZbggQ85CMYshjLKIod2DLL/sLf2x1PRXyRG131M1E3k8zkkz6de ++R1uDrIN/x91iuYzfLQZGh8bMY7Yjd2eoroa6R/7DjpElGejLxOAaDWO0ST2IFQy9 ++myTGS2jSM97wcXfsSQJBANP3jelJoS5X6BRjTSneY21wcocxVuQh8pXpErALVNsT ++drrFTeaBuZp7KvbtnIM5g2WRNvaxLZlAY/hXPJvi6ncCQQDSix1cebml6EmPlEZS ++Mm8gwI2F9ufUunwJmBJcz826Do0ZNGByWDAM/JQZH4FX4GfAFNuj8PUb+GQfadkx ++i1DPAkEA0lVsNHojvuDsIo8HGuzarNZQT2beWjJ1jdxh9t7HrTx7LIps6rb/fhOK ++Zs0R6gVAJaEbcWAPZ2tFyECInAdnsQJAUjaeXXjuxFkjOFym5PvqpvhpivEx78Bu ++JPTr3rAKXmfGMxxfuOa0xK1wSyshP6ZR/RBn/+lcXPKubhHQDOegwwJAJF1DBQnN +++/tLmOPULtDwfP4Zixn+/8GmGOahFoRcu6VIGHmRilJTn6MOButw7Glv2YdeC6l/ ++e83Gq6ffLVfKNQ== ++-----END PRIVATE KEY----- ++Certificate: ++ Data: ++ Version: 1 (0x0) ++ Serial Number: 12723342612721443282 (0xb09264b1f2da21d2) ++ Signature Algorithm: sha1WithRSAEncryption ++ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server ++ Validity ++ Not Before: Jan 4 19:47:07 2013 GMT ++ Not After : Nov 13 19:47:07 2022 GMT ++ Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname ++ Subject Public Key Info: ++ Public Key Algorithm: rsaEncryption ++ Public-Key: (1024 bit) ++ Modulus: ++ 00:ae:54:42:23:08:e5:59:0d:b3:64:2f:2f:b8:14: ++ 6a:20:dd:15:eb:cd:51:74:63:53:80:c7:01:ed:d9: ++ cf:36:0b:64:d1:3a:f6:1f:60:3b:d5:42:49:2d:7a: ++ b4:9e:5f:4f:95:44:bb:41:19:c8:6a:f4:7b:75:76: ++ 36:45:f4:66:85:34:1d:cf:d4:69:8e:2a:c7:b2:c7: ++ 9a:7e:52:61:9a:48:c6:12:67:91:fe:d2:c8:72:4a: ++ d7:35:1a:1a:55:34:fc:bc:58:a8:8b:86:0a:d1:79: ++ 76:ac:75:2f:63:90:84:4c:75:18:ce:91:c9:d1:dd: ++ 81:7e:bd:1b:ae:0b:5d:c6:39 ++ Exponent: 65537 (0x10001) ++ Signature Algorithm: sha1WithRSAEncryption ++ ad:45:8a:8e:ef:c6:ef:04:41:5c:2c:4a:84:dc:02:76:0c:d0: ++ 66:0f:f0:16:04:58:4d:fd:68:b7:b8:d3:a8:41:a5:5c:3c:6f: ++ 65:3c:d1:f8:ce:43:35:e7:41:5f:53:3d:c9:2c:c3:7d:fc:56: ++ 4a:fa:47:77:38:9d:bb:97:28:0a:3b:91:19:7f:bc:74:ae:15: ++ 6b:bd:20:36:67:45:a5:1e:79:d7:75:e6:89:5c:6d:54:84:d1: ++ 95:d7:a7:b4:33:3c:af:37:c4:79:8f:5e:75:dc:75:c2:18:fb: ++ 61:6f:2d:dc:38:65:5b:ba:67:28:d0:88:d7:8d:b9:23:5a:8e: ++ e8:c6:bb:db:ce:d5:b8:41:2a:ce:93:08:b6:95:ad:34:20:18: ++ d5:3b:37:52:74:50:0b:07:2c:b0:6d:a4:4c:7b:f4:e0:fd:d1: ++ af:17:aa:20:cd:62:e3:f0:9d:37:69:db:41:bd:d4:1c:fb:53: ++ 20:da:88:9d:76:26:67:ce:01:90:a7:80:1d:a9:5b:39:73:68: ++ 54:0a:d1:2a:03:1b:8f:3c:43:5d:5d:c4:51:f1:a7:e7:11:da: ++ 31:2c:49:06:af:04:f4:b8:3c:99:c4:20:b9:06:36:a2:00:92: ++ 61:1d:0c:6d:24:05:e2:82:e1:47:db:a0:5f:ba:b9:fb:ba:fa: ++ 49:12:1e:ce ++-----BEGIN CERTIFICATE----- ++MIICpzCCAY8CCQCwkmSx8toh0jANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY ++WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV ++BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3 ++WjBiMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV ++BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRUwEwYDVQQDEwxmYWtlaG9z ++dG5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK5UQiMI5VkNs2QvL7gU ++aiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2NkX0 ++ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1L2OQ ++hEx1GM6RydHdgX69G64LXcY5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAK1Fio7v ++xu8EQVwsSoTcAnYM0GYP8BYEWE39aLe406hBpVw8b2U80fjOQzXnQV9TPcksw338 ++Vkr6R3c4nbuXKAo7kRl/vHSuFWu9IDZnRaUeedd15olcbVSE0ZXXp7QzPK83xHmP ++XnXcdcIY+2FvLdw4ZVu6ZyjQiNeNuSNajujGu9vO1bhBKs6TCLaVrTQgGNU7N1J0 ++UAsHLLBtpEx79OD90a8XqiDNYuPwnTdp20G91Bz7UyDaiJ12JmfOAZCngB2pWzlz ++aFQK0SoDG488Q11dxFHxp+cR2jEsSQavBPS4PJnEILkGNqIAkmEdDG0kBeKC4Ufb ++oF+6ufu6+kkSHs4= ++-----END CERTIFICATE----- +diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py +new file mode 100644 +--- /dev/null ++++ b/Lib/test/make_ssl_certs.py +@@ -0,0 +1,176 @@ ++"""Make the custom certificate and private key files used by test_ssl ++and friends.""" ++ ++import os ++import shutil ++import sys ++import tempfile ++from subprocess import * ++ ++req_template = """ ++ [req] ++ distinguished_name = req_distinguished_name ++ x509_extensions = req_x509_extensions ++ prompt = no ++ ++ [req_distinguished_name] ++ C = XY ++ L = Castle Anthrax ++ O = Python Software Foundation ++ CN = {hostname} ++ ++ [req_x509_extensions] ++ subjectAltName = DNS:{hostname} ++ ++ [ ca ] ++ default_ca = CA_default ++ ++ [ CA_default ] ++ dir = cadir ++ database = $dir/index.txt ++ crlnumber = $dir/crl.txt ++ default_md = sha1 ++ default_days = 3600 ++ default_crl_days = 3600 ++ certificate = pycacert.pem ++ private_key = pycakey.pem ++ serial = $dir/serial ++ RANDFILE = $dir/.rand ++ ++ policy = policy_match ++ ++ [ policy_match ] ++ countryName = match ++ stateOrProvinceName = optional ++ organizationName = match ++ organizationalUnitName = optional ++ commonName = supplied ++ emailAddress = optional ++ ++ [ policy_anything ] ++ countryName = optional ++ stateOrProvinceName = optional ++ localityName = optional ++ organizationName = optional ++ organizationalUnitName = optional ++ commonName = supplied ++ emailAddress = optional ++ ++ ++ [ v3_ca ] ++ ++ subjectKeyIdentifier=hash ++ authorityKeyIdentifier=keyid:always,issuer ++ basicConstraints = CA:true ++ ++ """ ++ ++here = os.path.abspath(os.path.dirname(__file__)) ++ ++def make_cert_key(hostname, sign=False): ++ print("creating cert for " + hostname) ++ tempnames = [] ++ for i in range(3): ++ with tempfile.NamedTemporaryFile(delete=False) as f: ++ tempnames.append(f.name) ++ req_file, cert_file, key_file = tempnames ++ try: ++ with open(req_file, 'w') as f: ++ f.write(req_template.format(hostname=hostname)) ++ args = ['req', '-new', '-days', '3650', '-nodes', ++ '-newkey', 'rsa:1024', '-keyout', key_file, ++ '-config', req_file] ++ if sign: ++ with tempfile.NamedTemporaryFile(delete=False) as f: ++ tempnames.append(f.name) ++ reqfile = f.name ++ args += ['-out', reqfile ] ++ ++ else: ++ args += ['-x509', '-out', cert_file ] ++ check_call(['openssl'] + args) ++ ++ if sign: ++ args = ['ca', '-config', req_file, '-out', cert_file, '-outdir', 'cadir', ++ '-policy', 'policy_anything', '-batch', '-infiles', reqfile ] ++ check_call(['openssl'] + args) ++ ++ ++ with open(cert_file, 'r') as f: ++ cert = f.read() ++ with open(key_file, 'r') as f: ++ key = f.read() ++ return cert, key ++ finally: ++ for name in tempnames: ++ os.remove(name) ++ ++TMP_CADIR = 'cadir' ++ ++def unmake_ca(): ++ shutil.rmtree(TMP_CADIR) ++ ++def make_ca(): ++ os.mkdir(TMP_CADIR) ++ with open(os.path.join('cadir','index.txt'),'a+') as f: ++ pass # empty file ++ with open(os.path.join('cadir','crl.txt'),'a+') as f: ++ f.write("00") ++ with open(os.path.join('cadir','index.txt.attr'),'w+') as f: ++ f.write('unique_subject = no') ++ ++ with tempfile.NamedTemporaryFile("w") as t: ++ t.write(req_template.format(hostname='our-ca-server')) ++ t.flush() ++ with tempfile.NamedTemporaryFile() as f: ++ args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes', ++ '-newkey', 'rsa:2048', '-keyout', 'pycakey.pem', ++ '-out', f.name, ++ '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server'] ++ check_call(['openssl'] + args) ++ args = ['ca', '-config', t.name, '-create_serial', ++ '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR, ++ '-keyfile', 'pycakey.pem', '-days', '3650', ++ '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ] ++ check_call(['openssl'] + args) ++ args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl'] ++ check_call(['openssl'] + args) ++ ++if __name__ == '__main__': ++ os.chdir(here) ++ cert, key = make_cert_key('localhost') ++ with open('ssl_cert.pem', 'w') as f: ++ f.write(cert) ++ with open('ssl_key.pem', 'w') as f: ++ f.write(key) ++ print("password protecting ssl_key.pem in ssl_key.passwd.pem") ++ check_call(['openssl','rsa','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-des3','-passout','pass:somepass']) ++ check_call(['openssl','rsa','-in','ssl_key.pem','-out','keycert.passwd.pem','-des3','-passout','pass:somepass']) ++ ++ with open('keycert.pem', 'w') as f: ++ f.write(key) ++ f.write(cert) ++ ++ with open('keycert.passwd.pem', 'a+') as f: ++ f.write(cert) ++ ++ # For certificate matching tests ++ make_ca() ++ cert, key = make_cert_key('fakehostname') ++ with open('keycert2.pem', 'w') as f: ++ f.write(key) ++ f.write(cert) ++ ++ cert, key = make_cert_key('localhost', True) ++ with open('keycert3.pem', 'w') as f: ++ f.write(key) ++ f.write(cert) ++ ++ cert, key = make_cert_key('fakehostname', True) ++ with open('keycert4.pem', 'w') as f: ++ f.write(key) ++ f.write(cert) ++ ++ unmake_ca() ++ print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber") ++ check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout']) +diff --git a/Lib/test/pycacert.pem b/Lib/test/pycacert.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/pycacert.pem +@@ -0,0 +1,78 @@ ++Certificate: ++ Data: ++ Version: 3 (0x2) ++ Serial Number: 12723342612721443280 (0xb09264b1f2da21d0) ++ Signature Algorithm: sha1WithRSAEncryption ++ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server ++ Validity ++ Not Before: Jan 4 19:47:07 2013 GMT ++ Not After : Jan 2 19:47:07 2023 GMT ++ Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server ++ Subject Public Key Info: ++ Public Key Algorithm: rsaEncryption ++ Public-Key: (2048 bit) ++ Modulus: ++ 00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2: ++ 6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4: ++ e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f: ++ e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f: ++ 14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf: ++ 00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d: ++ a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3: ++ e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4: ++ 02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf: ++ 5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c: ++ e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6: ++ c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a: ++ cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01: ++ 3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87: ++ 5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f: ++ 2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14: ++ e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4: ++ c5:4d ++ Exponent: 65537 (0x10001) ++ X509v3 extensions: ++ X509v3 Subject Key Identifier: ++ BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B ++ X509v3 Authority Key Identifier: ++ keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B ++ ++ X509v3 Basic Constraints: ++ CA:TRUE ++ Signature Algorithm: sha1WithRSAEncryption ++ 7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6: ++ 27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d: ++ a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95: ++ 54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17: ++ 28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c: ++ 23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4: ++ fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7: ++ 40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24: ++ 06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33: ++ 9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61: ++ ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f: ++ 5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64: ++ b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb: ++ 32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3: ++ 5e:58:c8:9e ++-----BEGIN CERTIFICATE----- ++MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV ++BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW ++MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx ++OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg ++Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI ++hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV ++q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/ ++AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA ++Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni ++0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx ++6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w ++HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2 ++2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB ++AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4 ++QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1 ++Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O ++JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR ++f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf ++9mmvtk57HVjsO6lTo15YyJ4= ++-----END CERTIFICATE----- +diff --git a/Lib/test/revocation.crl b/Lib/test/revocation.crl +new file mode 100644 +--- /dev/null ++++ b/Lib/test/revocation.crl +@@ -0,0 +1,11 @@ ++-----BEGIN X509 CRL----- ++MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE ++CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j ++YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud ++FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH +++i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m ++unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK ++fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC ++UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc ++HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed ++-----END X509 CRL----- +diff --git a/Lib/test/sha256.pem b/Lib/test/sha256.pem +--- a/Lib/test/sha256.pem ++++ b/Lib/test/sha256.pem +@@ -1,128 +1,128 @@ + # Certificate chain for https://sha256.tbs-internet.com +- 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=Certificats TBS X509/CN=ecom.tbs-x509.com +- i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business ++ 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com ++ i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC + -----BEGIN CERTIFICATE----- +-MIIGTjCCBTagAwIBAgIQOh3d9dNDPq1cSdJmEiMpqDANBgkqhkiG9w0BAQUFADCB +-yTELMAkGA1UEBhMCRlIxETAPBgNVBAgTCENhbHZhZG9zMQ0wCwYDVQQHEwRDYWVu +-MRUwEwYDVQQKEwxUQlMgSU5URVJORVQxSDBGBgNVBAsTP1Rlcm1zIGFuZCBDb25k +-aXRpb25zOiBodHRwOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0EvcmVwb3NpdG9y +-eTEYMBYGA1UECxMPVEJTIElOVEVSTkVUIENBMR0wGwYDVQQDExRUQlMgWDUwOSBD +-QSBidXNpbmVzczAeFw0xMTAxMjUwMDAwMDBaFw0xMzAyMDUyMzU5NTlaMIHHMQsw +-CQYDVQQGEwJGUjEOMAwGA1UEERMFMTQwMDAxETAPBgNVBAgTCENhbHZhZG9zMQ0w +-CwYDVQQHEwRDQUVOMRswGQYDVQQJExIyMiBydWUgZGUgQnJldGFnbmUxFTATBgNV +-BAoTDFRCUyBJTlRFUk5FVDEXMBUGA1UECxMOMDAwMiA0NDA0NDM4MTAxHTAbBgNV +-BAsTFENlcnRpZmljYXRzIFRCUyBYNTA5MRowGAYDVQQDExFlY29tLnRicy14NTA5 +-LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRrlHUnJ++1lpcg +-jtYco7cdmRe+EEfTmwPfCdfV3G1QfsTSvY6FfMpm/83pqHfT+4ANwr18wD9ZrAEN +-G16mf9VdCGK12+TP7DmqeZyGIqlFFoahQnmb8EarvE43/1UeQ2CV9XmzwZvpqeli +-LfXsFonawrY3H6ZnMwS64St61Z+9gdyuZ/RbsoZBbT5KUjDEG844QRU4OT1IGeEI +-eY5NM5RNIh6ZNhVtqeeCxMS7afONkHQrOco73RdSTRck/Hj96Ofl3MHNHryr+AMK +-DGFk1kLCZGpPdXtkxXvaDeQoiYDlil26CWc+YK6xyDPMdsWvoG14ZLyCpzMXA7/7 +-4YAQRH0CAwEAAaOCAjAwggIsMB8GA1UdIwQYMBaAFBoJBMz5CY+7HqDO1KQUf0vV +-I1jNMB0GA1UdDgQWBBQgOU8HsWzbmD4WZP5Wtdw7jca2WDAOBgNVHQ8BAf8EBAMC +-BaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +-TAYDVR0gBEUwQzBBBgsrBgEEAYDlNwIBATAyMDAGCCsGAQUFBwIBFiRodHRwczov +-L3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL0NQUzEwdwYDVR0fBHAwbjA3oDWgM4Yx +-aHR0cDovL2NybC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNy +-bDAzoDGgL4YtaHR0cDovL2NybC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5l +-c3MuY3JsMIGwBggrBgEFBQcBAQSBozCBoDA9BggrBgEFBQcwAoYxaHR0cDovL2Ny +-dC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNydDA5BggrBgEF +-BQcwAoYtaHR0cDovL2NydC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5lc3Mu +-Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wMwYDVR0R +-BCwwKoIRZWNvbS50YnMteDUwOS5jb22CFXd3dy5lY29tLnRicy14NTA5LmNvbTAN +-BgkqhkiG9w0BAQUFAAOCAQEArT4NHfbY87bGAw8lPV4DmHlmuDuVp/y7ltO3Ynse +-3Rz8RxW2AzuO0Oy2F0Cu4yWKtMyEyMXyHqWtae7ElRbdTu5w5GwVBLJHClCzC8S9 +-SpgMMQTx3Rgn8vjkHuU9VZQlulZyiPK7yunjc7c310S9FRZ7XxOwf8Nnx4WnB+No +-WrfApzhhQl31w+RyrNxZe58hCfDDHmevRvwLjQ785ZoQXJDj2j3qAD4aI2yB8lB5 +-oaE1jlCJzC7Kmz/Y9jzfmv/zAs1LQTm9ktevv4BTUFaGjv9jxnQ1xnS862ZiouLW +-zZYIlYPf4F6JjXGiIQgQRglILUfq3ftJd9/ok9W9ZF8h8w== ++MIIGXDCCBUSgAwIBAgIRAKpVmHgg9nfCodAVwcP4siwwDQYJKoZIhvcNAQELBQAw ++gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl ++bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u ++ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv ++cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg ++Q0EgU0dDMB4XDTEyMDEwNDAwMDAwMFoXDTE0MDIxNzIzNTk1OVowgcsxCzAJBgNV ++BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV ++BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM ++VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS ++c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 ++LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQIX/zdJcyxty0m ++PM1XQSoSSifueS3AVcgqMsaIKS/u+rYzsv4hQ/qA6vLn5m5/ewUcZDj7zdi6rBVf ++PaVNXJ6YinLX0tkaW8TEjeVuZG5yksGZlhCt1CJ1Ho9XLiLaP4uJ7MCoNUntpJ+E ++LfrOdgsIj91kPmwjDJeztVcQCvKzhjVJA/KxdInc0JvOATn7rpaSmQI5bvIjufgo ++qVsTPwVFzuUYULXBk7KxRT7MiEqnd5HvviNh0285QC478zl3v0I0Fb5El4yD3p49 ++IthcRnxzMKc0UhU5ogi0SbONyBfm/mzONVfSxpM+MlyvZmJqrbuuLoEDzJD+t8PU ++xSuzgbcCAwEAAaOCAj4wggI6MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf ++2YIfMB0GA1UdDgQWBBT/qTGYdaj+f61c2IRFL/B1eEsM8DAOBgNVHQ8BAf8EBAMC ++BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG ++CisGAQQBgjcKAwMGCWCGSAGG+EIEATBLBgNVHSAERDBCMEAGCisGAQQB5TcCBAEw ++MjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cudGJzLWludGVybmV0LmNvbS9DQS9D ++UFM0MG0GA1UdHwRmMGQwMqAwoC6GLGh0dHA6Ly9jcmwudGJzLWludGVybmV0LmNv ++bS9UQlNYNTA5Q0FTR0MuY3JsMC6gLKAqhihodHRwOi8vY3JsLnRicy14NTA5LmNv ++bS9UQlNYNTA5Q0FTR0MuY3JsMIGmBggrBgEFBQcBAQSBmTCBljA4BggrBgEFBQcw ++AoYsaHR0cDovL2NydC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQVNHQy5jcnQw ++NAYIKwYBBQUHMAKGKGh0dHA6Ly9jcnQudGJzLXg1MDkuY29tL1RCU1g1MDlDQVNH ++Qy5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnRicy14NTA5LmNvbTA/BgNV ++HREEODA2ghdzaGEyNTYudGJzLWludGVybmV0LmNvbYIbd3d3LnNoYTI1Ni50YnMt ++aW50ZXJuZXQuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA0pOuL8QvAa5yksTbGShzX ++ABApagunUGoEydv4YJT1MXy9tTp7DrWaozZSlsqBxrYAXP1d9r2fuKbEniYHxaQ0 ++UYaf1VSIlDo1yuC8wE7wxbHDIpQ/E5KAyxiaJ8obtDhFstWAPAH+UoGXq0kj2teN ++21sFQ5dXgA95nldvVFsFhrRUNB6xXAcaj0VZFhttI0ZfQZmQwEI/P+N9Jr40OGun ++aa+Dn0TMeUH4U20YntfLbu2nDcJcYfyurm+8/0Tr4HznLnedXu9pCPYj0TaddrgT ++XO0oFiyy7qGaY6+qKh71yD64Y3ycCJ/HR9Wm39mjZYc9ezYwT4noP6r7Lk8YO7/q + -----END CERTIFICATE----- +- 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business ++ 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC + i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root + -----BEGIN CERTIFICATE----- +-MIIFPzCCBCegAwIBAgIQDlBz/++iRSmLDeVRHT/hADANBgkqhkiG9w0BAQUFADBv ++MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv + MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk + ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +-eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDcwOTE4MTkyMlow +-gckxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl ++eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow ++gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl + bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u + ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEdMBsGA1UEAxMUVEJTIFg1MDkg +-Q0EgYnVzaW5lc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB1PAU +-qudCcz3tmyGcf+u6EkZqonKKHrV4gZYbvVkIRojmmlhfi/jwvpHvo8bqSt/9Rj5S +-jhCDW0pcbI+IPPtD1Jy+CHNSfnMqVDy6CKQ3p5maTzCMG6ZT+XjnvcND5v+FtaiB +-xk1iCX6uvt0jeUtdZvYbyytsSDE6c3Y5//wRxOF8tM1JxibwO3pyER26jbbN2gQz +-m/EkdGjLdJ4svPk23WDAvQ6G0/z2LcAaJB+XLfqRwfQpHQvfKa1uTi8PivC8qtip +-rmNQMMPMjxSK2azX8cKjjTDJiUKaCb4VHlJDWKEsCFRpgJAoAuX8f7Yfs1M4esGo +-sWb3PGspK3O22uIlAgMBAAGjggF6MIIBdjAdBgNVHQ4EFgQUGgkEzPkJj7seoM7U +-pBR/S9UjWM0wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwGAYD +-VR0gBBEwDzANBgsrBgEEAYDlNwIBATB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8v +-Y3JsLmNvbW9kb2NhLmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDA2oDSg +-MoYwaHR0cDovL2NybC5jb21vZG8ubmV0L0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu +-Y3JsMIGGBggrBgEFBQcBAQR6MHgwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t +-b2RvY2EuY29tL0FkZFRydXN0VVROU2VydmVyQ0EuY3J0MDkGCCsGAQUFBzAChi1o +-dHRwOi8vY3J0LmNvbW9kby5uZXQvQWRkVHJ1c3RVVE5TZXJ2ZXJDQS5jcnQwEQYJ +-YIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBBQUAA4IBAQA7mqrMgk/MrE6QnbNA +-h4nRCn2ti4bg4w2C3lB6bSvRPnYwuNw9Jb8vuKkNFzRDxNJXqVDZdfFW5CVQJuyd +-nfAx83+wk+spzvFaE1KhFYfN9G9pQfXUfvDRoIcJgPEKUXL1wRiOG+IjU3VVI8pg +-IgqHkr7ylln5i5zCiFAPuIJmYUSFg/gxH5xkCNcjJqqrHrHatJr6Qrrke93joupw +-oU1njfAcZtYp6fbiK6u2b1pJqwkVBE8RsfLnPhRj+SFbpvjv8Od7o/ieJhFIYQNU +-k2jX2u8qZnAiNw93LZW9lpYjtuvMXq8QQppENNja5b53q7UwI+lU7ZGjZ7quuESp +-J6/5 ++cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg ++Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6 ++rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0 ++9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ ++ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk ++owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G ++Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk ++9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf ++2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ ++MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3 ++AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk ++ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k ++by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw ++cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV ++VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B ++ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN ++AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232 ++euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY ++1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98 ++RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz ++8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV ++v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E= + -----END CERTIFICATE----- + 2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root +- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware ++ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC + -----BEGIN CERTIFICATE----- +-MIIETzCCAzegAwIBAgIQHM5EYpUZep1jUvnyI6m2mDANBgkqhkiG9w0BAQUFADCB +-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug ++MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB ++kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug + Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +-SGFyZHdhcmUwHhcNMDUwNjA3MDgwOTEwWhcNMTkwNzA5MTgxOTIyWjBvMQswCQYD +-VQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0 +-IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h +-bCBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt/caM+by +-AAQtOeBOW+0fvGwPzbX6I7bO3psRM5ekKUx9k5+9SryT7QMa44/P5W1QWtaXKZRa +-gLBJetsulf24yr83OC0ePpFBrXBWx/BPP+gynnTKyJBU6cZfD3idmkA8Dqxhql4U +-j56HoWpQ3NeaTq8Fs6ZxlJxxs1BgCscTnTgHhgKo6ahpJhiQq0ywTyOrOk+E2N/O +-n+Fpb7vXQtdrROTHre5tQV9yWnEIN7N5ZaRZoJQ39wAvDcKSctrQOHLbFKhFxF0q +-fbe01sTurM0TRLfJK91DACX6YblpalgjEbenM49WdVn1zSnXRrcKK2W200JvFbK4 +-e/vv6V1T1TRaJwIDAQABo4G9MIG6MB8GA1UdIwQYMBaAFKFyXyYbKJhDlV0HN9WF +-lp1L0sNFMB0GA1UdDgQWBBStvZh6NLQm9/rEJlTvA73gJMtUGjAOBgNVHQ8BAf8E +-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQIwRAYDVR0f +-BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly +-c3QtSGFyZHdhcmUuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQByQhANOs4kClrwF8BW +-onvUOGCSjRK52zYZgDXYNjDtmr5rJ6NyPFDNn+JxkLpjYetIFMTbSRe679Bt8m7a +-gIAoQYFQtxMuyLnJegB2aEbQiIxh/tC21UcFF7ktdnDoTlA6w3pLuvunaI84Of3o +-2YBrhzkTbCfaYk5JRlTpudW9DkUkHBsyx3nknPKnplkIGaK0jgn8E0n+SFabYaHk +-I9LroYT/+JtLefh9lgBdAgVv0UPbzoGfuDsrk/Zh+UrgbLFpHoVnElhzbkh64Z0X +-OGaJunQc68cCZu5HTn/aK7fBGMcVflRCXLVEQpU9PIAdGA8Ynvg684t8GMaKsRl1 +-jIGZ ++dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw ++IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT ++AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0 ++ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB ++IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05 ++4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6 ++2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh ++alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv ++u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW ++xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p ++XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd ++tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB ++BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX ++BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov ++L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN ++AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO ++rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd ++FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM +++bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI ++3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb +++M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g= + -----END CERTIFICATE----- +- 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware +- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware ++ 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC ++ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC + -----BEGIN CERTIFICATE----- +-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug ++MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB ++kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug + Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +-SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +-MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +-d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +-cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +-0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +-M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +-MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +-oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +-DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +-oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +-dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +-bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +-BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +-CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +-CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +-3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +-KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ++dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw ++IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG ++EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD ++VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu ++dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN ++BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 ++E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ ++D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK ++4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq ++lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW ++bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB ++o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT ++MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js ++LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr ++BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB ++AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft ++Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj ++j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH ++KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv ++2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 ++mfnGV/TJVTl4uix5yaaIK/QI + -----END CERTIFICATE----- +diff --git a/Lib/test/ssl_cert.pem b/Lib/test/ssl_cert.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/ssl_cert.pem +@@ -0,0 +1,15 @@ ++-----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/Lib/test/ssl_key.passwd.pem b/Lib/test/ssl_key.passwd.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/ssl_key.passwd.pem +@@ -0,0 +1,18 @@ ++-----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----- +diff --git a/Lib/test/ssl_key.pem b/Lib/test/ssl_key.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/ssl_key.pem +@@ -0,0 +1,16 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm ++LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0 ++ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP ++USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt ++CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq ++SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK ++UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y ++BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ ++ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5 ++oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik ++eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F ++0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS ++x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/ ++SPIXQuT8RMPDVNQ= ++-----END PRIVATE KEY----- +diff --git a/Lib/test/ssl_servers.py b/Lib/test/ssl_servers.py +new file mode 100644 +--- /dev/null ++++ b/Lib/test/ssl_servers.py +@@ -0,0 +1,209 @@ ++import os ++import sys ++import ssl ++import pprint ++import urllib ++import urlparse ++# Rename HTTPServer to _HTTPServer so as to avoid confusion with HTTPSServer. ++from BaseHTTPServer import HTTPServer as _HTTPServer, BaseHTTPRequestHandler ++from SimpleHTTPServer import SimpleHTTPRequestHandler ++ ++from test import test_support as support ++threading = support.import_module("threading") ++ ++here = os.path.dirname(__file__) ++ ++HOST = support.HOST ++CERTFILE = os.path.join(here, 'keycert.pem') ++ ++# This one's based on HTTPServer, which is based on SocketServer ++ ++class HTTPSServer(_HTTPServer): ++ ++ def __init__(self, server_address, handler_class, context): ++ _HTTPServer.__init__(self, server_address, handler_class) ++ self.context = context ++ ++ def __str__(self): ++ return ('<%s %s:%s>' % ++ (self.__class__.__name__, ++ self.server_name, ++ self.server_port)) ++ ++ def get_request(self): ++ # override this to wrap socket with SSL ++ try: ++ sock, addr = self.socket.accept() ++ sslconn = self.context.wrap_socket(sock, server_side=True) ++ except OSError as e: ++ # socket errors are silenced by the caller, print them here ++ if support.verbose: ++ sys.stderr.write("Got an error:\n%s\n" % e) ++ raise ++ return sslconn, addr ++ ++class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): ++ # need to override translate_path to get a known root, ++ # instead of using os.curdir, since the test could be ++ # run from anywhere ++ ++ server_version = "TestHTTPS/1.0" ++ root = here ++ # Avoid hanging when a request gets interrupted by the client ++ timeout = 5 ++ ++ def translate_path(self, path): ++ """Translate a /-separated PATH to the local filename syntax. ++ ++ Components that mean special things to the local file system ++ (e.g. drive or directory names) are ignored. (XXX They should ++ probably be diagnosed.) ++ ++ """ ++ # abandon query parameters ++ path = urlparse.urlparse(path)[2] ++ path = os.path.normpath(urllib.unquote(path)) ++ words = path.split('/') ++ words = filter(None, words) ++ path = self.root ++ for word in words: ++ drive, word = os.path.splitdrive(word) ++ head, word = os.path.split(word) ++ path = os.path.join(path, word) ++ return path ++ ++ def log_message(self, format, *args): ++ # we override this to suppress logging unless "verbose" ++ if support.verbose: ++ sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" % ++ (self.server.server_address, ++ self.server.server_port, ++ self.request.cipher(), ++ self.log_date_time_string(), ++ format%args)) ++ ++ ++class StatsRequestHandler(BaseHTTPRequestHandler): ++ """Example HTTP request handler which returns SSL statistics on GET ++ requests. ++ """ ++ ++ server_version = "StatsHTTPS/1.0" ++ ++ def do_GET(self, send_body=True): ++ """Serve a GET request.""" ++ sock = self.rfile.raw._sock ++ context = sock.context ++ stats = { ++ 'session_cache': context.session_stats(), ++ 'cipher': sock.cipher(), ++ 'compression': sock.compression(), ++ } ++ body = pprint.pformat(stats) ++ body = body.encode('utf-8') ++ self.send_response(200) ++ self.send_header("Content-type", "text/plain; charset=utf-8") ++ self.send_header("Content-Length", str(len(body))) ++ self.end_headers() ++ if send_body: ++ self.wfile.write(body) ++ ++ def do_HEAD(self): ++ """Serve a HEAD request.""" ++ self.do_GET(send_body=False) ++ ++ def log_request(self, format, *args): ++ if support.verbose: ++ BaseHTTPRequestHandler.log_request(self, format, *args) ++ ++ ++class HTTPSServerThread(threading.Thread): ++ ++ def __init__(self, context, host=HOST, handler_class=None): ++ self.flag = None ++ self.server = HTTPSServer((host, 0), ++ handler_class or RootedHTTPRequestHandler, ++ context) ++ self.port = self.server.server_port ++ threading.Thread.__init__(self) ++ self.daemon = True ++ ++ def __str__(self): ++ return "<%s %s>" % (self.__class__.__name__, self.server) ++ ++ def start(self, flag=None): ++ self.flag = flag ++ threading.Thread.start(self) ++ ++ def run(self): ++ if self.flag: ++ self.flag.set() ++ try: ++ self.server.serve_forever(0.05) ++ finally: ++ self.server.server_close() ++ ++ def stop(self): ++ self.server.shutdown() ++ ++ ++def make_https_server(case, context=None, certfile=CERTFILE, ++ host=HOST, handler_class=None): ++ if context is None: ++ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ++ # We assume the certfile contains both private key and certificate ++ context.load_cert_chain(certfile) ++ server = HTTPSServerThread(context, host, handler_class) ++ flag = threading.Event() ++ server.start(flag) ++ flag.wait() ++ def cleanup(): ++ if support.verbose: ++ sys.stdout.write('stopping HTTPS server\n') ++ server.stop() ++ if support.verbose: ++ sys.stdout.write('joining HTTPS thread\n') ++ server.join() ++ case.addCleanup(cleanup) ++ return server ++ ++ ++if __name__ == "__main__": ++ import argparse ++ parser = argparse.ArgumentParser( ++ description='Run a test HTTPS server. ' ++ 'By default, the current directory is served.') ++ parser.add_argument('-p', '--port', type=int, default=4433, ++ help='port to listen on (default: %(default)s)') ++ parser.add_argument('-q', '--quiet', dest='verbose', default=True, ++ action='store_false', help='be less verbose') ++ parser.add_argument('-s', '--stats', dest='use_stats_handler', default=False, ++ action='store_true', help='always return stats page') ++ parser.add_argument('--curve-name', dest='curve_name', type=str, ++ action='store', ++ help='curve name for EC-based Diffie-Hellman') ++ parser.add_argument('--ciphers', dest='ciphers', type=str, ++ help='allowed cipher list') ++ parser.add_argument('--dh', dest='dh_file', type=str, action='store', ++ help='PEM file containing DH parameters') ++ args = parser.parse_args() ++ ++ support.verbose = args.verbose ++ if args.use_stats_handler: ++ handler_class = StatsRequestHandler ++ else: ++ handler_class = RootedHTTPRequestHandler ++ handler_class.root = os.getcwd() ++ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ++ context.load_cert_chain(CERTFILE) ++ if args.curve_name: ++ context.set_ecdh_curve(args.curve_name) ++ if args.dh_file: ++ context.load_dh_params(args.dh_file) ++ if args.ciphers: ++ context.set_ciphers(args.ciphers) ++ ++ server = HTTPSServer(("", args.port), handler_class, context) ++ if args.verbose: ++ print("Listening on https://localhost:{0.port}".format(args)) ++ server.serve_forever(0.1) +diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py +--- a/Lib/test/test_support.py ++++ b/Lib/test/test_support.py +@@ -39,7 +39,7 @@ except ImportError: + "threading_cleanup", "reap_children", "cpython_only", + "check_impl_detail", "get_attribute", "py3k_bytes", + "import_fresh_module", "threading_cleanup", "reap_children", +- "strip_python_stderr"] ++ "strip_python_stderr", "IPV6_ENABLED"] + + class Error(Exception): + """Base class for regression test exceptions.""" +@@ -465,6 +465,23 @@ def bind_port(sock, host=HOST): + port = sock.getsockname()[1] + return port + ++def _is_ipv6_enabled(): ++ """Check whether IPv6 is enabled on this host.""" ++ if socket.has_ipv6: ++ sock = None ++ try: ++ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) ++ sock.bind((HOSTv6, 0)) ++ return True ++ except OSError: ++ pass ++ finally: ++ if sock: ++ sock.close() ++ return False ++ ++IPV6_ENABLED = _is_ipv6_enabled() ++ + FUZZ = 1e-6 + + def fcmp(x, y): # fuzzy comparison function +diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py +new file mode 100755 +--- /dev/null ++++ b/Tools/ssl/make_ssl_data.py +@@ -0,0 +1,68 @@ ++#! /usr/bin/env python3 ++ ++""" ++This script should be called *manually* when we want to upgrade SSLError ++`library` and `reason` mnemnonics to a more recent OpenSSL version. ++ ++It takes two arguments: ++- the path to the OpenSSL include files' directory ++ (e.g. openssl-1.0.1-beta3/include/openssl/) ++- the path to the C file to be generated ++ (probably Modules/_ssl_data.h) ++""" ++ ++import datetime ++import os ++import re ++import sys ++ ++ ++def parse_error_codes(h_file, prefix): ++ pat = re.compile(r"#define\W+(%s([\w]+))\W+(\d+)\b" % re.escape(prefix)) ++ codes = [] ++ with open(h_file, "r", encoding="latin1") as f: ++ for line in f: ++ match = pat.search(line) ++ if match: ++ code, name, num = match.groups() ++ num = int(num) ++ codes.append((code, name, num)) ++ return codes ++ ++if __name__ == "__main__": ++ openssl_inc = sys.argv[1] ++ outfile = sys.argv[2] ++ use_stdout = outfile == '-' ++ f = sys.stdout if use_stdout else open(outfile, "w") ++ error_libraries = ( ++ # (library code, mnemonic, error prefix, header file) ++ ('ERR_LIB_PEM', 'PEM', 'PEM_R_', 'pem.h'), ++ ('ERR_LIB_SSL', 'SSL', 'SSL_R_', 'ssl.h'), ++ ('ERR_LIB_X509', 'X509', 'X509_R_', 'x509.h'), ++ ) ++ def w(l): ++ f.write(l + "\n") ++ w("/* File generated by Tools/ssl/make_ssl_data.py */") ++ w("/* Generated on %s */" % datetime.datetime.now().isoformat()) ++ w("") ++ ++ w("static struct py_ssl_library_code library_codes[] = {") ++ for libcode, mnemo, _, _ in error_libraries: ++ w(' {"%s", %s},' % (mnemo, libcode)) ++ w(' { NULL }') ++ w('};') ++ w("") ++ ++ w("static struct py_ssl_error_code error_codes[] = {") ++ for libcode, _, prefix, h_file in error_libraries: ++ codes = parse_error_codes(os.path.join(openssl_inc, h_file), prefix) ++ for code, name, num in sorted(codes): ++ w(' #ifdef %s' % (code)) ++ w(' {"%s", %s, %s},' % (name, libcode, code)) ++ w(' #else') ++ w(' {"%s", %s, %d},' % (name, libcode, num)) ++ w(' #endif') ++ w(' { NULL }') ++ w('};') ++ if not use_stdout: ++ f.close() +diff --git a/Tools/ssl/test_multiple_versions.py b/Tools/ssl/test_multiple_versions.py +new file mode 100644 +--- /dev/null ++++ b/Tools/ssl/test_multiple_versions.py +@@ -0,0 +1,241 @@ ++#./python ++"""Run Python tests with multiple installations of OpenSSL ++ ++The script ++ ++ (1) downloads OpenSSL tar bundle ++ (2) extracts it to ../openssl/src/openssl-VERSION/ ++ (3) compiles OpenSSL ++ (4) installs OpenSSL into ../openssl/VERSION/ ++ (5) forces a recompilation of Python modules using the ++ header and library files from ../openssl/VERSION/ ++ (6) runs Python's test suite ++ ++The script must be run with Python's build directory as current working ++directory: ++ ++ ./python Tools/ssl/test_multiple_versions.py ++ ++The script uses LD_RUN_PATH, LD_LIBRARY_PATH, CPPFLAGS and LDFLAGS to bend ++search paths for header files and shared libraries. It's known to work on ++Linux with GCC 4.x. ++ ++(c) 2013 Christian Heimes ++""" ++import logging ++import os ++import tarfile ++import shutil ++import subprocess ++import sys ++from urllib import urlopen ++ ++log = logging.getLogger("multissl") ++ ++OPENSSL_VERSIONS = [ ++ "0.9.7m", "0.9.8i", "0.9.8l", "0.9.8m", "0.9.8y", "1.0.0k", "1.0.1e" ++] ++FULL_TESTS = [ ++ "test_asyncio", "test_ftplib", "test_hashlib", "test_httplib", ++ "test_imaplib", "test_nntplib", "test_poplib", "test_smtplib", ++ "test_smtpnet", "test_urllib2_localnet", "test_venv" ++] ++MINIMAL_TESTS = ["test_ssl", "test_hashlib"] ++CADEFAULT = True ++HERE = os.path.abspath(os.getcwd()) ++DEST_DIR = os.path.abspath(os.path.join(HERE, os.pardir, "openssl")) ++ ++ ++class BuildSSL(object): ++ url_template = "https://www.openssl.org/source/openssl-{}.tar.gz" ++ ++ module_files = ["Modules/_ssl.c", ++ "Modules/socketmodule.c", ++ "Modules/_hashopenssl.c"] ++ ++ def __init__(self, version, openssl_compile_args=(), destdir=DEST_DIR): ++ self._check_python_builddir() ++ self.version = version ++ self.openssl_compile_args = openssl_compile_args ++ # installation directory ++ self.install_dir = os.path.join(destdir, version) ++ # source file ++ self.src_file = os.path.join(destdir, "src", ++ "openssl-{}.tar.gz".format(version)) ++ # build directory (removed after install) ++ self.build_dir = os.path.join(destdir, "src", ++ "openssl-{}".format(version)) ++ ++ @property ++ def openssl_cli(self): ++ """openssl CLI binary""" ++ return os.path.join(self.install_dir, "bin", "openssl") ++ ++ @property ++ def openssl_version(self): ++ """output of 'bin/openssl version'""" ++ env = os.environ.copy() ++ env["LD_LIBRARY_PATH"] = self.lib_dir ++ cmd = [self.openssl_cli, "version"] ++ return self._subprocess_output(cmd, env=env) ++ ++ @property ++ def pyssl_version(self): ++ """Value of ssl.OPENSSL_VERSION""" ++ env = os.environ.copy() ++ env["LD_LIBRARY_PATH"] = self.lib_dir ++ cmd = ["./python", "-c", "import ssl; print(ssl.OPENSSL_VERSION)"] ++ return self._subprocess_output(cmd, env=env) ++ ++ @property ++ def include_dir(self): ++ return os.path.join(self.install_dir, "include") ++ ++ @property ++ def lib_dir(self): ++ return os.path.join(self.install_dir, "lib") ++ ++ @property ++ def has_openssl(self): ++ return os.path.isfile(self.openssl_cli) ++ ++ @property ++ def has_src(self): ++ return os.path.isfile(self.src_file) ++ ++ def _subprocess_call(self, cmd, stdout=subprocess.DEVNULL, env=None, ++ **kwargs): ++ log.debug("Call '{}'".format(" ".join(cmd))) ++ return subprocess.check_call(cmd, stdout=stdout, env=env, **kwargs) ++ ++ def _subprocess_output(self, cmd, env=None, **kwargs): ++ log.debug("Call '{}'".format(" ".join(cmd))) ++ out = subprocess.check_output(cmd, env=env) ++ return out.strip().decode("utf-8") ++ ++ def _check_python_builddir(self): ++ if not os.path.isfile("python") or not os.path.isfile("setup.py"): ++ raise ValueError("Script must be run in Python build directory") ++ ++ def _download_openssl(self): ++ """Download OpenSSL source dist""" ++ src_dir = os.path.dirname(self.src_file) ++ if not os.path.isdir(src_dir): ++ os.makedirs(src_dir) ++ url = self.url_template.format(self.version) ++ log.info("Downloading OpenSSL from {}".format(url)) ++ req = urlopen(url, cadefault=CADEFAULT) ++ # KISS, read all, write all ++ data = req.read() ++ log.info("Storing {}".format(self.src_file)) ++ with open(self.src_file, "wb") as f: ++ f.write(data) ++ ++ def _unpack_openssl(self): ++ """Unpack tar.gz bundle""" ++ # cleanup ++ if os.path.isdir(self.build_dir): ++ shutil.rmtree(self.build_dir) ++ os.makedirs(self.build_dir) ++ ++ tf = tarfile.open(self.src_file) ++ base = "openssl-{}/".format(self.version) ++ # force extraction into build dir ++ members = tf.getmembers() ++ for member in members: ++ if not member.name.startswith(base): ++ raise ValueError(member.name) ++ member.name = member.name[len(base):] ++ log.info("Unpacking files to {}".format(self.build_dir)) ++ tf.extractall(self.build_dir, members) ++ ++ def _build_openssl(self): ++ """Now build openssl""" ++ log.info("Running build in {}".format(self.install_dir)) ++ cwd = self.build_dir ++ cmd = ["./config", "shared", "--prefix={}".format(self.install_dir)] ++ cmd.extend(self.openssl_compile_args) ++ self._subprocess_call(cmd, cwd=cwd) ++ self._subprocess_call(["make"], cwd=cwd) ++ ++ def _install_openssl(self, remove=True): ++ self._subprocess_call(["make", "install"], cwd=self.build_dir) ++ if remove: ++ shutil.rmtree(self.build_dir) ++ ++ def install_openssl(self): ++ if not self.has_openssl: ++ if not self.has_src: ++ self._download_openssl() ++ else: ++ log.debug("Already has src {}".format(self.src_file)) ++ self._unpack_openssl() ++ self._build_openssl() ++ self._install_openssl() ++ else: ++ log.info("Already has installation {}".format(self.install_dir)) ++ # validate installation ++ version = self.openssl_version ++ if self.version not in version: ++ raise ValueError(version) ++ ++ def touch_pymods(self): ++ # force a rebuild of all modules that use OpenSSL APIs ++ for fname in self.module_files: ++ os.utime(fname) ++ ++ def recompile_pymods(self): ++ log.info("Using OpenSSL build from {}".format(self.build_dir)) ++ # overwrite header and library search paths ++ env = os.environ.copy() ++ env["CPPFLAGS"] = "-I{}".format(self.include_dir) ++ env["LDFLAGS"] = "-L{}".format(self.lib_dir) ++ # set rpath ++ env["LD_RUN_PATH"] = self.lib_dir ++ ++ log.info("Rebuilding Python modules") ++ self.touch_pymods() ++ cmd = ["./python", "setup.py", "build"] ++ self._subprocess_call(cmd, env=env) ++ ++ def check_pyssl(self): ++ version = self.pyssl_version ++ if self.version not in version: ++ raise ValueError(version) ++ ++ def run_pytests(self, *args): ++ cmd = ["./python", "-m", "test"] ++ cmd.extend(args) ++ self._subprocess_call(cmd, stdout=None) ++ ++ def run_python_tests(self, *args): ++ self.recompile_pymods() ++ self.check_pyssl() ++ self.run_pytests(*args) ++ ++ ++def main(*args): ++ builders = [] ++ for version in OPENSSL_VERSIONS: ++ if version in ("0.9.8i", "0.9.8l"): ++ openssl_compile_args = ("no-asm",) ++ else: ++ openssl_compile_args = () ++ builder = BuildSSL(version, openssl_compile_args) ++ builder.install_openssl() ++ builders.append(builder) ++ ++ for builder in builders: ++ builder.run_python_tests(*args) ++ # final touch ++ builder.touch_pymods() ++ ++ ++if __name__ == "__main__": ++ logging.basicConfig(level=logging.INFO, ++ format="*** %(levelname)s %(message)s") ++ args = sys.argv[1:] ++ if not args: ++ args = ["-unetwork", "-v"] ++ args.extend(FULL_TESTS) ++ main(*args) + +diff -up Python-2.7.5/Doc/library/ssl.rst.ssl Python-2.7.5/Doc/library/ssl.rst +--- Python-2.7.5/Doc/library/ssl.rst.ssl 2015-02-24 11:37:44.278196135 +0100 ++++ Python-2.7.5/Doc/library/ssl.rst 2015-02-24 09:24:25.135911989 +0100 +@@ -28,7 +28,8 @@ probably additional platforms, as long a + + Some behavior may be platform dependent, since calls are made to the + operating system socket APIs. The installed version of OpenSSL may also +- cause variations in behavior. ++ cause variations in behavior. For example, TLSv1.1 and TLSv1.2 come with ++ openssl version 1.0.1. + + This section documents the objects and functions in the ``ssl`` module; for more + general information about TLS, SSL, and certificates, the reader is referred to +@@ -37,23 +38,101 @@ the documents in the "See Also" section + This module provides a class, :class:`ssl.SSLSocket`, which is derived from the + :class:`socket.socket` type, and provides a socket-like wrapper that also + encrypts and decrypts the data going over the socket with SSL. It supports +-additional :meth:`read` and :meth:`write` methods, along with a method, +-:meth:`getpeercert`, to retrieve the certificate of the other side of the +-connection, and a method, :meth:`cipher`, to retrieve the cipher being used for +-the secure connection. ++additional methods such as :meth:`getpeercert`, which retrieves the ++certificate of the other side of the connection, and :meth:`cipher`,which ++retrieves the cipher being used for the secure connection. ++ ++For more sophisticated applications, the :class:`ssl.SSLContext` class ++helps manage settings and certificates, which can then be inherited ++by SSL sockets created through the :meth:`SSLContext.wrap_socket` method. ++ + + Functions, Constants, and Exceptions + ------------------------------------ + + .. exception:: SSLError + +- Raised to signal an error from the underlying SSL implementation. This +- signifies some problem in the higher-level encryption and authentication +- layer that's superimposed on the underlying network connection. This error +- is a subtype of :exc:`socket.error`, which in turn is a subtype of +- :exc:`IOError`. ++ Raised to signal an error from the underlying SSL implementation (currently ++ provided by the OpenSSL library). This signifies some problem in the ++ higher-level encryption and authentication layer that's superimposed on the ++ underlying network connection. This error is a subtype of ++ :exc:`socket.error`, which in turn is a subtype of :exc:`IOError`. The ++ error code and message of :exc:`SSLError` instances are provided by the ++ OpenSSL library. ++ ++ .. attribute:: library ++ ++ A string mnemonic designating the OpenSSL submodule in which the error ++ occurred, such as ``SSL``, ``PEM`` or ``X509``. The range of possible ++ values depends on the OpenSSL version. ++ ++ .. versionadded:: 2.7.9 ++ ++ .. attribute:: reason ++ ++ A string mnemonic designating the reason this error occurred, for ++ example ``CERTIFICATE_VERIFY_FAILED``. The range of possible ++ values depends on the OpenSSL version. ++ ++ .. versionadded:: 2.7.9 ++ ++.. exception:: SSLZeroReturnError ++ ++ A subclass of :exc:`SSLError` raised when trying to read or write and ++ the SSL connection has been closed cleanly. Note that this doesn't ++ mean that the underlying transport (read TCP) has been closed. ++ ++ .. versionadded:: 2.7.9 ++ ++.. exception:: SSLWantReadError ++ ++ A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket ++ ` when trying to read or write data, but more data needs ++ to be received on the underlying TCP transport before the request can be ++ fulfilled. ++ ++ .. versionadded:: 2.7.9 ++ ++.. exception:: SSLWantWriteError ++ ++ A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket ++ ` when trying to read or write data, but more data needs ++ to be sent on the underlying TCP transport before the request can be ++ fulfilled. ++ ++ .. versionadded:: 2.7.9 + +-.. function:: wrap_socket (sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) ++.. exception:: SSLSyscallError ++ ++ A subclass of :exc:`SSLError` raised when a system error was encountered ++ while trying to fulfill an operation on a SSL socket. Unfortunately, ++ there is no easy way to inspect the original errno number. ++ ++ .. versionadded:: 2.7.9 ++ ++.. exception:: SSLEOFError ++ ++ A subclass of :exc:`SSLError` raised when the SSL connection has been ++ terminated abruptly. Generally, you shouldn't try to reuse the underlying ++ transport when this error is encountered. ++ ++ .. versionadded:: 2.7.9 ++ ++.. exception:: CertificateError ++ ++ Raised to signal an error with a certificate (such as mismatching ++ hostname). Certificate errors detected by OpenSSL, though, raise ++ an :exc:`SSLError`. ++ ++ ++Socket creation ++^^^^^^^^^^^^^^^ ++ ++The following function allows for standalone socket creation. Starting from ++Python 2.7.9, it can be more flexible to use :meth:`SSLContext.wrap_socket` ++instead. ++ ++.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) + + Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance + of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps +@@ -70,19 +149,6 @@ Functions, Constants, and Exceptions + connection. See the discussion of :ref:`ssl-certificates` for more + information on how the certificate is stored in the ``certfile``. + +- Often the private key is stored in the same file as the certificate; in this +- case, only the ``certfile`` parameter need be passed. If the private key is +- stored in a separate file, both parameters must be used. If the private key +- is stored in the ``certfile``, it should come before the first certificate in +- the certificate chain:: +- +- -----BEGIN RSA PRIVATE KEY----- +- ... (private key in base64 encoding) ... +- -----END RSA PRIVATE KEY----- +- -----BEGIN CERTIFICATE----- +- ... (certificate in base64 PEM encoding) ... +- -----END CERTIFICATE----- +- + The parameter ``server_side`` is a boolean which identifies whether + server-side or client-side behavior is desired from this socket. + +@@ -112,14 +178,16 @@ Functions, Constants, and Exceptions + + .. table:: + +- ======================== ========= ========= ========== ========= +- *client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1** +- ------------------------ --------- --------- ---------- --------- +- *SSLv2* yes no yes no +- *SSLv3* no yes yes no +- *SSLv23* yes no yes no +- *TLSv1* no no yes yes +- ======================== ========= ========= ========== ========= ++ ======================== ========= ========= ========== ========= =========== =========== ++ *client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1** **TLSv1.1** **TLSv1.2** ++ ------------------------ --------- --------- ---------- --------- ----------- ----------- ++ *SSLv2* yes no yes no no no ++ *SSLv3* no yes yes no no no ++ *SSLv23* yes no yes no no no ++ *TLSv1* no no yes yes no no ++ *TLSv1.1* no no yes no yes no ++ *TLSv1.2* no no yes no no yes ++ ======================== ========= ========= ========== ========= =========== =========== + + .. note:: + +@@ -146,22 +214,79 @@ Functions, Constants, and Exceptions + The parameter ``suppress_ragged_eofs`` specifies how the + :meth:`SSLSocket.read` method should signal unexpected EOF from the other end + of the connection. If specified as :const:`True` (the default), it returns a +- normal EOF in response to unexpected EOF errors raised from the underlying +- socket; if :const:`False`, it will raise the exceptions back to the caller. ++ normal EOF (an empty bytes object) in response to unexpected EOF errors ++ raised from the underlying socket; if :const:`False`, it will raise the ++ exceptions back to the caller. + + .. versionchanged:: 2.7 + New optional argument *ciphers*. + ++ ++Context creation ++^^^^^^^^^^^^^^^^ ++ ++A convenience function helps create :class:`SSLContext` objects for common ++purposes. ++ ++.. function:: create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None) ++ ++ Return a new :class:`SSLContext` object with default settings for ++ the given *purpose*. The settings are chosen by the :mod:`ssl` module, ++ and usually represent a higher security level than when calling the ++ :class:`SSLContext` constructor directly. ++ ++ *cafile*, *capath*, *cadata* represent optional CA certificates to ++ trust for certificate verification, as in ++ :meth:`SSLContext.load_verify_locations`. If all three are ++ :const:`None`, this function can choose to trust the system's default ++ CA certificates instead. ++ ++ The settings in Python 2.7.9 are: :data:`PROTOCOL_SSLv23`, ++ :data:`OP_NO_SSLv2`, and :data:`OP_NO_SSLv3` with high encryption cipher ++ suites without RC4 and without unauthenticated cipher suites. Passing ++ :data:`~Purpose.SERVER_AUTH` as *purpose* sets ++ :data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED` and either loads CA ++ certificates (when at least one of *cafile*, *capath* or *cadata* is given) ++ or uses :meth:`SSLContext.load_default_certs` to load default CA ++ certificates. ++ ++ .. note:: ++ The protocol, options, cipher and other settings may change to more ++ restrictive values anytime without prior deprecation. The values ++ represent a fair balance between compatibility and security. ++ ++ If your application needs specific settings, you should create a ++ :class:`SSLContext` and apply the settings yourself. ++ ++ .. note:: ++ If you find that when certain older clients or servers attempt to connect ++ with a :class:`SSLContext` created by this function that they get an ++ error stating "Protocol or cipher suite mismatch", it may be that they ++ only support SSL3.0 which this function excludes using the ++ :data:`OP_NO_SSLv3`. SSL3.0 has problematic security due to a number of ++ poor implementations and it's reliance on MD5 within the protocol. If you ++ wish to continue to use this function but still allow SSL 3.0 connections ++ you can re-enable them using:: ++ ++ ctx = ssl.create_default_context(Purpose.CLIENT_AUTH) ++ ctx.options &= ~ssl.OP_NO_SSLv3 ++ ++ .. versionadded:: 2.7.9 ++ ++ ++Random generation ++^^^^^^^^^^^^^^^^^ ++ + .. function:: RAND_status() + + Returns True if the SSL pseudo-random number generator has been seeded with +- 'enough' randomness, and False otherwise. You can use :func:`ssl.RAND_egd` ++ 'enough' randomness, and ``False`` otherwise. You can use :func:`ssl.RAND_egd` + and :func:`ssl.RAND_add` to increase the randomness of the pseudo-random + number generator. + + .. function:: RAND_egd(path) + +- If you are running an entropy-gathering daemon (EGD) somewhere, and ``path`` ++ If you are running an entropy-gathering daemon (EGD) somewhere, and *path* + is the pathname of a socket connection open to it, this will read 256 bytes + of randomness from the socket, and add it to the SSL pseudo-random number + generator to increase the security of generated secret keys. This is +@@ -172,28 +297,66 @@ Functions, Constants, and Exceptions + + .. function:: RAND_add(bytes, entropy) + +- Mixes the given ``bytes`` into the SSL pseudo-random number generator. The +- parameter ``entropy`` (a float) is a lower bound on the entropy contained in ++ Mixes the given *bytes* into the SSL pseudo-random number generator. The ++ parameter *entropy* (a float) is a lower bound on the entropy contained in + string (so you can always use :const:`0.0`). See :rfc:`1750` for more + information on sources of entropy. + +-.. function:: cert_time_to_seconds(timestring) ++Certificate handling ++^^^^^^^^^^^^^^^^^^^^ ++ ++.. function:: match_hostname(cert, hostname) ++ ++ Verify that *cert* (in decoded format as returned by ++ :meth:`SSLSocket.getpeercert`) matches the given *hostname*. The rules ++ applied are those for checking the identity of HTTPS servers as outlined ++ in :rfc:`2818` and :rfc:`6125`, except that IP addresses are not currently ++ supported. In addition to HTTPS, this function should be suitable for ++ checking the identity of servers in various SSL-based protocols such as ++ FTPS, IMAPS, POPS and others. + +- Returns a floating-point value containing a normal seconds-after-the-epoch +- time value, given the time-string representing the "notBefore" or "notAfter" +- date from a certificate. +- +- Here's an example:: +- +- >>> import ssl +- >>> ssl.cert_time_to_seconds("May 9 00:00:00 2007 GMT") +- 1178694000.0 +- >>> import time +- >>> time.ctime(ssl.cert_time_to_seconds("May 9 00:00:00 2007 GMT")) +- 'Wed May 9 00:00:00 2007' +- >>> ++ :exc:`CertificateError` is raised on failure. On success, the function ++ returns nothing:: + +-.. function:: get_server_certificate (addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None) ++ >>> cert = {'subject': ((('commonName', 'example.com'),),)} ++ >>> ssl.match_hostname(cert, "example.com") ++ >>> ssl.match_hostname(cert, "example.org") ++ Traceback (most recent call last): ++ File "", line 1, in ++ File "/home/py3k/Lib/ssl.py", line 130, in match_hostname ++ ssl.CertificateError: hostname 'example.org' doesn't match 'example.com' ++ ++ .. versionadded:: 2.7.9 ++ ++ ++.. function:: cert_time_to_seconds(cert_time) ++ ++ Return the time in seconds since the Epoch, given the ``cert_time`` ++ string representing the "notBefore" or "notAfter" date from a ++ certificate in ``"%b %d %H:%M:%S %Y %Z"`` strptime format (C ++ locale). ++ ++ Here's an example: ++ ++ .. doctest:: newcontext ++ ++ >>> import ssl ++ >>> timestamp = ssl.cert_time_to_seconds("Jan 5 09:34:43 2018 GMT") ++ >>> timestamp ++ 1515144883 ++ >>> from datetime import datetime ++ >>> print(datetime.utcfromtimestamp(timestamp)) ++ 2018-01-05 09:34:43 ++ ++ "notBefore" or "notAfter" dates must use GMT (:rfc:`5280`). ++ ++ .. versionchanged:: 2.7.9 ++ Interpret the input time as a time in UTC as specified by 'GMT' ++ timezone in the input string. Local timezone was used ++ previously. Return an integer (no fractions of a second in the ++ input format) ++ ++.. function:: get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None) + + Given the address ``addr`` of an SSL-protected server, as a (*hostname*, + *port-number*) pair, fetches the server's certificate, and returns it as a +@@ -204,36 +367,144 @@ Functions, Constants, and Exceptions + will attempt to validate the server certificate against that set of root + certificates, and will fail if the validation attempt fails. + +-.. function:: DER_cert_to_PEM_cert (DER_cert_bytes) ++ .. versionchanged:: 2.7.9 ++ ++ This function is now IPv6-compatible, and the default *ssl_version* is ++ changed from :data:`PROTOCOL_SSLv3` to :data:`PROTOCOL_SSLv23` for ++ maximum compatibility with modern servers. ++ ++.. function:: DER_cert_to_PEM_cert(DER_cert_bytes) + + Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded + string version of the same certificate. + +-.. function:: PEM_cert_to_DER_cert (PEM_cert_string) ++.. function:: PEM_cert_to_DER_cert(PEM_cert_string) + + Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of + bytes for that same certificate. + ++.. function:: get_default_verify_paths() ++ ++ Returns a named tuple with paths to OpenSSL's default cafile and capath. ++ The paths are the same as used by ++ :meth:`SSLContext.set_default_verify_paths`. The return value is a ++ :term:`named tuple` ``DefaultVerifyPaths``: ++ ++ * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, ++ * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, ++ * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, ++ * :attr:`openssl_cafile` - hard coded path to a cafile, ++ * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, ++ * :attr:`openssl_capath` - hard coded path to a capath directory ++ ++ .. versionadded:: 2.7.9 ++ ++.. function:: enum_certificates(store_name) ++ ++ Retrieve certificates from Windows' system cert store. *store_name* may be ++ one of ``CA``, ``ROOT`` or ``MY``. Windows may provide additional cert ++ stores, too. ++ ++ The function returns a list of (cert_bytes, encoding_type, trust) tuples. ++ The encoding_type specifies the encoding of cert_bytes. It is either ++ :const:`x509_asn` for X.509 ASN.1 data or :const:`pkcs_7_asn` for ++ PKCS#7 ASN.1 data. Trust specifies the purpose of the certificate as a set ++ of OIDS or exactly ``True`` if the certificate is trustworthy for all ++ purposes. ++ ++ Example:: ++ ++ >>> ssl.enum_certificates("CA") ++ [(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}), ++ (b'data...', 'x509_asn', True)] ++ ++ Availability: Windows. ++ ++ .. versionadded:: 2.7.9 ++ ++.. function:: enum_crls(store_name) ++ ++ Retrieve CRLs from Windows' system cert store. *store_name* may be ++ one of ``CA``, ``ROOT`` or ``MY``. Windows may provide additional cert ++ stores, too. ++ ++ The function returns a list of (cert_bytes, encoding_type, trust) tuples. ++ The encoding_type specifies the encoding of cert_bytes. It is either ++ :const:`x509_asn` for X.509 ASN.1 data or :const:`pkcs_7_asn` for ++ PKCS#7 ASN.1 data. ++ ++ Availability: Windows. ++ ++ .. versionadded:: 2.7.9 ++ ++ ++Constants ++^^^^^^^^^ ++ + .. data:: CERT_NONE + +- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no +- certificates will be required or validated from the other side of the socket +- connection. ++ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` ++ parameter to :func:`wrap_socket`. In this mode (the default), no ++ certificates will be required from the other side of the socket connection. ++ If a certificate is received from the other end, no attempt to validate it ++ is made. ++ ++ See the discussion of :ref:`ssl-security` below. + + .. data:: CERT_OPTIONAL + +- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no +- certificates will be required from the other side of the socket connection, +- but if they are provided, will be validated. Note that use of this setting +- requires a valid certificate validation file also be passed as a value of the +- ``ca_certs`` parameter. ++ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` ++ parameter to :func:`wrap_socket`. In this mode no certificates will be ++ required from the other side of the socket connection; but if they ++ are provided, validation will be attempted and an :class:`SSLError` ++ will be raised on failure. ++ ++ Use of this setting requires a valid set of CA certificates to ++ be passed, either to :meth:`SSLContext.load_verify_locations` or as a ++ value of the ``ca_certs`` parameter to :func:`wrap_socket`. + + .. data:: CERT_REQUIRED + +- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when +- certificates will be required from the other side of the socket connection. +- Note that use of this setting requires a valid certificate validation file +- also be passed as a value of the ``ca_certs`` parameter. ++ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` ++ parameter to :func:`wrap_socket`. In this mode, certificates are ++ required from the other side of the socket connection; an :class:`SSLError` ++ will be raised if no certificate is provided, or if its validation fails. ++ ++ Use of this setting requires a valid set of CA certificates to ++ be passed, either to :meth:`SSLContext.load_verify_locations` or as a ++ value of the ``ca_certs`` parameter to :func:`wrap_socket`. ++ ++.. data:: VERIFY_DEFAULT ++ ++ Possible value for :attr:`SSLContext.verify_flags`. In this mode, ++ certificate revocation lists (CRLs) are not checked. By default OpenSSL ++ does neither require nor verify CRLs. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: VERIFY_CRL_CHECK_LEAF ++ ++ Possible value for :attr:`SSLContext.verify_flags`. In this mode, only the ++ peer cert is check but non of the intermediate CA certificates. The mode ++ requires a valid CRL that is signed by the peer cert's issuer (its direct ++ ancestor CA). If no proper has been loaded ++ :attr:`SSLContext.load_verify_locations`, validation will fail. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: VERIFY_CRL_CHECK_CHAIN ++ ++ Possible value for :attr:`SSLContext.verify_flags`. In this mode, CRLs of ++ all certificates in the peer cert chain are checked. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: VERIFY_X509_STRICT ++ ++ Possible value for :attr:`SSLContext.verify_flags` to disable workarounds ++ for broken X.509 certificates. ++ ++ .. versionadded:: 2.7.9 + + .. data:: PROTOCOL_SSLv2 + +@@ -260,9 +531,136 @@ Functions, Constants, and Exceptions + + .. data:: PROTOCOL_TLSv1 + +- Selects TLS version 1 as the channel encryption protocol. This is the most ++ Selects TLS version 1.0 as the channel encryption protocol. ++ ++.. data:: PROTOCOL_TLSv1_1 ++ ++ Selects TLS version 1.1 as the channel encryption protocol. ++ Available only with openssl version 1.0.1+. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: PROTOCOL_TLSv1_2 ++ ++ Selects TLS version 1.2 as the channel encryption protocol. This is the most + modern version, and probably the best choice for maximum protection, if both +- sides can speak it. ++ sides can speak it. Available only with openssl version 1.0.1+. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_ALL ++ ++ Enables workarounds for various bugs present in other SSL implementations. ++ This option is set by default. It does not necessarily set the same ++ flags as OpenSSL's ``SSL_OP_ALL`` constant. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_SSLv2 ++ ++ Prevents an SSLv2 connection. This option is only applicable in ++ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from ++ choosing SSLv2 as the protocol version. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_SSLv3 ++ ++ Prevents an SSLv3 connection. This option is only applicable in ++ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from ++ choosing SSLv3 as the protocol version. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_TLSv1 ++ ++ Prevents a TLSv1 connection. This option is only applicable in ++ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from ++ choosing TLSv1 as the protocol version. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_TLSv1_1 ++ ++ Prevents a TLSv1.1 connection. This option is only applicable in conjunction ++ with :const:`PROTOCOL_SSLv23`. It prevents the peers from choosing TLSv1.1 as ++ the protocol version. Available only with openssl version 1.0.1+. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_TLSv1_2 ++ ++ Prevents a TLSv1.2 connection. This option is only applicable in conjunction ++ with :const:`PROTOCOL_SSLv23`. It prevents the peers from choosing TLSv1.2 as ++ the protocol version. Available only with openssl version 1.0.1+. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_CIPHER_SERVER_PREFERENCE ++ ++ Use the server's cipher ordering preference, rather than the client's. ++ This option has no effect on client sockets and SSLv2 server sockets. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_SINGLE_DH_USE ++ ++ Prevents re-use of the same DH key for distinct SSL sessions. This ++ improves forward secrecy but requires more computational resources. ++ This option only applies to server sockets. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_SINGLE_ECDH_USE ++ ++ Prevents re-use of the same ECDH key for distinct SSL sessions. This ++ improves forward secrecy but requires more computational resources. ++ This option only applies to server sockets. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: OP_NO_COMPRESSION ++ ++ Disable compression on the SSL channel. This is useful if the application ++ protocol supports its own compression scheme. ++ ++ This option is only available with OpenSSL 1.0.0 and later. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: HAS_ECDH ++ ++ Whether the OpenSSL library has built-in support for Elliptic Curve-based ++ Diffie-Hellman key exchange. This should be true unless the feature was ++ explicitly disabled by the distributor. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: HAS_SNI ++ ++ Whether the OpenSSL library has built-in support for the *Server Name ++ Indication* extension to the SSLv3 and TLSv1 protocols (as defined in ++ :rfc:`4366`). When true, you can use the *server_hostname* argument to ++ :meth:`SSLContext.wrap_socket`. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: HAS_NPN ++ ++ Whether the OpenSSL library has built-in support for *Next Protocol ++ Negotiation* as described in the `NPN draft specification ++ `_. When true, ++ you can use the :meth:`SSLContext.set_npn_protocols` method to advertise ++ which protocols you want to support. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: CHANNEL_BINDING_TYPES ++ ++ List of supported TLS channel binding types. Strings in this list ++ can be used as arguments to :meth:`SSLSocket.get_channel_binding`. ++ ++ .. versionadded:: 2.7.9 + + .. data:: OPENSSL_VERSION + +@@ -294,9 +692,40 @@ Functions, Constants, and Exceptions + + .. versionadded:: 2.7 + ++.. data:: ALERT_DESCRIPTION_HANDSHAKE_FAILURE ++ ALERT_DESCRIPTION_INTERNAL_ERROR ++ ALERT_DESCRIPTION_* ++ ++ Alert Descriptions from :rfc:`5246` and others. The `IANA TLS Alert Registry ++ `_ ++ contains this list and references to the RFCs where their meaning is defined. ++ ++ Used as the return value of the callback function in ++ :meth:`SSLContext.set_servername_callback`. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: Purpose.SERVER_AUTH ++ ++ Option for :func:`create_default_context` and ++ :meth:`SSLContext.load_default_certs`. This value indicates that the ++ context may be used to authenticate Web servers (therefore, it will ++ be used to create client-side sockets). ++ ++ .. versionadded:: 2.7.9 + +-SSLSocket Objects +------------------ ++.. data:: Purpose.CLIENT_AUTH ++ ++ Option for :func:`create_default_context` and ++ :meth:`SSLContext.load_default_certs`. This value indicates that the ++ context may be used to authenticate Web clients (therefore, it will ++ be used to create server-side sockets). ++ ++ .. versionadded:: 2.7.9 ++ ++ ++SSL Sockets ++----------- + + SSL sockets provide the following methods of :ref:`socket-objects`: + +@@ -319,37 +748,64 @@ SSL sockets provide the following method + + However, since the SSL (and TLS) protocol has its own framing atop + of TCP, the SSL sockets abstraction can, in certain respects, diverge from +-the specification of normal, OS-level sockets. ++the specification of normal, OS-level sockets. See especially the ++:ref:`notes on non-blocking sockets `. + + SSL sockets also have the following additional methods and attributes: + ++.. method:: SSLSocket.do_handshake() ++ ++ Perform the SSL setup handshake. ++ ++ .. versionchanged:: 2.7.9 ++ ++ The handshake method also performs :func:`match_hostname` when the ++ :attr:`~SSLContext.check_hostname` attribute of the socket's ++ :attr:`~SSLSocket.context` is true. ++ + .. method:: SSLSocket.getpeercert(binary_form=False) + + If there is no certificate for the peer on the other end of the connection, +- returns ``None``. ++ return ``None``. If the SSL handshake hasn't been done yet, raise ++ :exc:`ValueError`. + + If the ``binary_form`` parameter is :const:`False`, and a certificate was + received from the peer, this method returns a :class:`dict` instance. If the + certificate was not validated, the dict is empty. If the certificate was +- validated, it returns a dict with the keys ``subject`` (the principal for +- which the certificate was issued), and ``notAfter`` (the time after which the +- certificate should not be trusted). The certificate was already validated, +- so the ``notBefore`` and ``issuer`` fields are not returned. If a +- certificate contains an instance of the *Subject Alternative Name* extension +- (see :rfc:`3280`), there will also be a ``subjectAltName`` key in the +- dictionary. +- +- The "subject" field is a tuple containing the sequence of relative +- distinguished names (RDNs) given in the certificate's data structure for the +- principal, and each RDN is a sequence of name-value pairs:: +- +- {'notAfter': 'Feb 16 16:54:50 2013 GMT', +- 'subject': ((('countryName', u'US'),), +- (('stateOrProvinceName', u'Delaware'),), +- (('localityName', u'Wilmington'),), +- (('organizationName', u'Python Software Foundation'),), +- (('organizationalUnitName', u'SSL'),), +- (('commonName', u'somemachine.python.org'),))} ++ validated, it returns a dict with several keys, amongst them ``subject`` ++ (the principal for which the certificate was issued) and ``issuer`` ++ (the principal issuing the certificate). If a certificate contains an ++ instance of the *Subject Alternative Name* extension (see :rfc:`3280`), ++ there will also be a ``subjectAltName`` key in the dictionary. ++ ++ The ``subject`` and ``issuer`` fields are tuples containing the sequence ++ of relative distinguished names (RDNs) given in the certificate's data ++ structure for the respective fields, and each RDN is a sequence of ++ name-value pairs. Here is a real-world example:: ++ ++ {'issuer': ((('countryName', 'IL'),), ++ (('organizationName', 'StartCom Ltd.'),), ++ (('organizationalUnitName', ++ 'Secure Digital Certificate Signing'),), ++ (('commonName', ++ 'StartCom Class 2 Primary Intermediate Server CA'),)), ++ 'notAfter': 'Nov 22 08:15:19 2013 GMT', ++ 'notBefore': 'Nov 21 03:09:52 2011 GMT', ++ 'serialNumber': '95F0', ++ 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),), ++ (('countryName', 'US'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'San Francisco'),), ++ (('organizationName', 'Electronic Frontier Foundation, Inc.'),), ++ (('commonName', '*.eff.org'),), ++ (('emailAddress', 'hostmaster@eff.org'),)), ++ 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')), ++ 'version': 3} ++ ++ .. note:: ++ ++ To validate a certificate for a particular service, you can use the ++ :func:`match_hostname` function. + + If the ``binary_form`` parameter is :const:`True`, and a certificate was + provided, this method returns the DER-encoded form of the entire certificate +@@ -365,40 +821,388 @@ SSL sockets also have the following addi + :const:`None` if you used :const:`CERT_NONE` (rather than + :const:`CERT_OPTIONAL` or :const:`CERT_REQUIRED`). + ++ .. versionchanged:: 2.7.9 ++ The returned dictionary includes additional items such as ``issuer`` and ++ ``notBefore``. Additionall :exc:`ValueError` is raised when the handshake ++ isn't done. The returned dictionary includes additional X509v3 extension ++ items such as ``crlDistributionPoints``, ``caIssuers`` and ``OCSP`` URIs. ++ + .. method:: SSLSocket.cipher() + + Returns a three-value tuple containing the name of the cipher being used, the + version of the SSL protocol that defines its use, and the number of secret + bits being used. If no connection has been established, returns ``None``. + +-.. method:: SSLSocket.do_handshake() ++.. method:: SSLSocket.compression() ++ ++ Return the compression algorithm being used as a string, or ``None`` ++ if the connection isn't compressed. ++ ++ If the higher-level protocol supports its own compression mechanism, ++ you can use :data:`OP_NO_COMPRESSION` to disable SSL-level compression. ++ ++ .. versionadded:: 2.7.9 ++ ++.. method:: SSLSocket.get_channel_binding(cb_type="tls-unique") ++ ++ Get channel binding data for current connection, as a bytes object. Returns ++ ``None`` if not connected or the handshake has not been completed. ++ ++ The *cb_type* parameter allow selection of the desired channel binding ++ type. Valid channel binding types are listed in the ++ :data:`CHANNEL_BINDING_TYPES` list. Currently only the 'tls-unique' channel ++ binding, defined by :rfc:`5929`, is supported. :exc:`ValueError` will be ++ raised if an unsupported channel binding type is requested. ++ ++ .. versionadded:: 2.7.9 ++ ++.. method:: SSLSocket.selected_npn_protocol() ++ ++ Returns the protocol that was selected during the TLS/SSL handshake. If ++ :meth:`SSLContext.set_npn_protocols` was not called, or if the other party ++ does not support NPN, or if the handshake has not yet happened, this will ++ return ``None``. + +- Perform a TLS/SSL handshake. If this is used with a non-blocking socket, it +- may raise :exc:`SSLError` with an ``arg[0]`` of :const:`SSL_ERROR_WANT_READ` +- or :const:`SSL_ERROR_WANT_WRITE`, in which case it must be called again until +- it completes successfully. For example, to simulate the behavior of a +- blocking socket, one might write:: +- +- while True: +- try: +- s.do_handshake() +- break +- except ssl.SSLError as err: +- if err.args[0] == ssl.SSL_ERROR_WANT_READ: +- select.select([s], [], []) +- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: +- select.select([], [s], []) +- else: +- raise ++ .. versionadded:: 2.7.9 + + .. method:: SSLSocket.unwrap() + + Performs the SSL shutdown handshake, which removes the TLS layer from the + underlying socket, and returns the underlying socket object. This can be + used to go from encrypted operation over a connection to unencrypted. The +- socket instance returned should always be used for further communication with +- the other side of the connection, rather than the original socket instance +- (which may not function properly after the unwrap). ++ returned socket should always be used for further communication with the ++ other side of the connection, rather than the original socket. ++ ++.. attribute:: SSLSocket.context ++ ++ The :class:`SSLContext` object this SSL socket is tied to. If the SSL ++ socket was created using the top-level :func:`wrap_socket` function ++ (rather than :meth:`SSLContext.wrap_socket`), this is a custom context ++ object created for this SSL socket. ++ ++ .. versionadded:: 2.7.9 ++ ++ ++SSL Contexts ++------------ ++ ++.. versionadded:: 2.7.9 ++ ++An SSL context holds various data longer-lived than single SSL connections, ++such as SSL configuration options, certificate(s) and private key(s). ++It also manages a cache of SSL sessions for server-side sockets, in order ++to speed up repeated connections from the same clients. ++ ++.. class:: SSLContext(protocol) ++ ++ Create a new SSL context. You must pass *protocol* which must be one ++ of the ``PROTOCOL_*`` constants defined in this module. ++ :data:`PROTOCOL_SSLv23` is currently recommended for maximum ++ interoperability. ++ ++ .. seealso:: ++ :func:`create_default_context` lets the :mod:`ssl` module choose ++ security settings for a given purpose. ++ ++ ++:class:`SSLContext` objects have the following methods and attributes: ++ ++.. method:: SSLContext.cert_store_stats() ++ ++ Get statistics about quantities of loaded X.509 certificates, count of ++ X.509 certificates flagged as CA certificates and certificate revocation ++ lists as dictionary. ++ ++ Example for a context with one CA cert and one other cert:: ++ ++ >>> context.cert_store_stats() ++ {'crl': 0, 'x509_ca': 1, 'x509': 2} ++ ++ ++.. method:: SSLContext.load_cert_chain(certfile, keyfile=None, password=None) ++ ++ Load a private key and the corresponding certificate. The *certfile* ++ string must be the path to a single file in PEM format containing the ++ certificate as well as any number of CA certificates needed to establish ++ the certificate's authenticity. The *keyfile* string, if present, must ++ point to a file containing the private key in. Otherwise the private ++ key will be taken from *certfile* as well. See the discussion of ++ :ref:`ssl-certificates` for more information on how the certificate ++ is stored in the *certfile*. ++ ++ The *password* argument may be a function to call to get the password for ++ decrypting the private key. It will only be called if the private key is ++ encrypted and a password is necessary. It will be called with no arguments, ++ and it should return a string, bytes, or bytearray. If the return value is ++ a string it will be encoded as UTF-8 before using it to decrypt the key. ++ Alternatively a string, bytes, or bytearray value may be supplied directly ++ as the *password* argument. It will be ignored if the private key is not ++ encrypted and no password is needed. ++ ++ If the *password* argument is not specified and a password is required, ++ OpenSSL's built-in password prompting mechanism will be used to ++ interactively prompt the user for a password. ++ ++ An :class:`SSLError` is raised if the private key doesn't ++ match with the certificate. ++ ++.. method:: SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH) ++ ++ Load a set of default "certification authority" (CA) certificates from ++ default locations. On Windows it loads CA certs from the ``CA`` and ++ ``ROOT`` system stores. On other systems it calls ++ :meth:`SSLContext.set_default_verify_paths`. In the future the method may ++ load CA certificates from other locations, too. ++ ++ The *purpose* flag specifies what kind of CA certificates are loaded. The ++ default settings :data:`Purpose.SERVER_AUTH` loads certificates, that are ++ flagged and trusted for TLS web server authentication (client side ++ sockets). :data:`Purpose.CLIENT_AUTH` loads CA certificates for client ++ certificate verification on the server side. ++ ++.. method:: SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None) ++ ++ Load a set of "certification authority" (CA) certificates used to validate ++ other peers' certificates when :data:`verify_mode` is other than ++ :data:`CERT_NONE`. At least one of *cafile* or *capath* must be specified. ++ ++ This method can also load certification revocation lists (CRLs) in PEM or ++ DER format. In order to make use of CRLs, :attr:`SSLContext.verify_flags` ++ must be configured properly. ++ ++ The *cafile* string, if present, is the path to a file of concatenated ++ CA certificates in PEM format. See the discussion of ++ :ref:`ssl-certificates` for more information about how to arrange the ++ certificates in this file. ++ ++ The *capath* string, if present, is ++ the path to a directory containing several CA certificates in PEM format, ++ following an `OpenSSL specific layout ++ `_. ++ ++ The *cadata* object, if present, is either an ASCII string of one or more ++ PEM-encoded certificates or a bytes-like object of DER-encoded ++ certificates. Like with *capath* extra lines around PEM-encoded ++ certificates are ignored but at least one certificate must be present. ++ ++.. method:: SSLContext.get_ca_certs(binary_form=False) ++ ++ Get a list of loaded "certification authority" (CA) certificates. If the ++ ``binary_form`` parameter is :const:`False` each list ++ entry is a dict like the output of :meth:`SSLSocket.getpeercert`. Otherwise ++ the method returns a list of DER-encoded certificates. The returned list ++ does not contain certificates from *capath* unless a certificate was ++ requested and loaded by a SSL connection. ++ ++.. method:: SSLContext.set_default_verify_paths() ++ ++ Load a set of default "certification authority" (CA) certificates from ++ a filesystem path defined when building the OpenSSL library. Unfortunately, ++ there's no easy way to know whether this method succeeds: no error is ++ returned if no certificates are to be found. When the OpenSSL library is ++ provided as part of the operating system, though, it is likely to be ++ configured properly. ++ ++.. method:: SSLContext.set_ciphers(ciphers) ++ ++ Set the available ciphers for sockets created with this context. ++ It should be a string in the `OpenSSL cipher list format ++ `_. ++ If no cipher can be selected (because compile-time options or other ++ configuration forbids use of all the specified ciphers), an ++ :class:`SSLError` will be raised. ++ ++ .. note:: ++ when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will ++ give the currently selected cipher. ++ ++.. method:: SSLContext.set_npn_protocols(protocols) ++ ++ Specify which protocols the socket should advertise during the SSL/TLS ++ handshake. It should be a list of strings, like ``['http/1.1', 'spdy/2']``, ++ ordered by preference. The selection of a protocol will happen during the ++ handshake, and will play out according to the `NPN draft specification ++ `_. After a ++ successful handshake, the :meth:`SSLSocket.selected_npn_protocol` method will ++ return the agreed-upon protocol. ++ ++ This method will raise :exc:`NotImplementedError` if :data:`HAS_NPN` is ++ False. ++ ++.. method:: SSLContext.set_servername_callback(server_name_callback) ++ ++ Register a callback function that will be called after the TLS Client Hello ++ handshake message has been received by the SSL/TLS server when the TLS client ++ specifies a server name indication. The server name indication mechanism ++ is specified in :rfc:`6066` section 3 - Server Name Indication. ++ ++ Only one callback can be set per ``SSLContext``. If *server_name_callback* ++ is ``None`` then the callback is disabled. Calling this function a ++ subsequent time will disable the previously registered callback. ++ ++ The callback function, *server_name_callback*, will be called with three ++ arguments; the first being the :class:`ssl.SSLSocket`, the second is a string ++ that represents the server name that the client is intending to communicate ++ (or :const:`None` if the TLS Client Hello does not contain a server name) ++ and the third argument is the original :class:`SSLContext`. The server name ++ argument is the IDNA decoded server name. ++ ++ A typical use of this callback is to change the :class:`ssl.SSLSocket`'s ++ :attr:`SSLSocket.context` attribute to a new object of type ++ :class:`SSLContext` representing a certificate chain that matches the server ++ name. ++ ++ Due to the early negotiation phase of the TLS connection, only limited ++ methods and attributes are usable like ++ :meth:`SSLSocket.selected_npn_protocol` and :attr:`SSLSocket.context`. ++ :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.getpeercert`, ++ :meth:`SSLSocket.cipher` and :meth:`SSLSocket.compress` methods require that ++ the TLS connection has progressed beyond the TLS Client Hello and therefore ++ will not contain return meaningful values nor can they be called safely. ++ ++ The *server_name_callback* function must return ``None`` to allow the ++ TLS negotiation to continue. If a TLS failure is required, a constant ++ :const:`ALERT_DESCRIPTION_* ` can be ++ returned. Other return values will result in a TLS fatal error with ++ :const:`ALERT_DESCRIPTION_INTERNAL_ERROR`. ++ ++ If there is an IDNA decoding error on the server name, the TLS connection ++ will terminate with an :const:`ALERT_DESCRIPTION_INTERNAL_ERROR` fatal TLS ++ alert message to the client. ++ ++ If an exception is raised from the *server_name_callback* function the TLS ++ connection will terminate with a fatal TLS alert message ++ :const:`ALERT_DESCRIPTION_HANDSHAKE_FAILURE`. ++ ++ This method will raise :exc:`NotImplementedError` if the OpenSSL library ++ had OPENSSL_NO_TLSEXT defined when it was built. ++ ++.. method:: SSLContext.load_dh_params(dhfile) ++ ++ Load the key generation parameters for Diffie-Helman (DH) key exchange. ++ Using DH key exchange improves forward secrecy at the expense of ++ computational resources (both on the server and on the client). ++ The *dhfile* parameter should be the path to a file containing DH ++ parameters in PEM format. ++ ++ This setting doesn't apply to client sockets. You can also use the ++ :data:`OP_SINGLE_DH_USE` option to further improve security. ++ ++.. method:: SSLContext.set_ecdh_curve(curve_name) ++ ++ Set the curve name for Elliptic Curve-based Diffie-Hellman (ECDH) key ++ exchange. ECDH is significantly faster than regular DH while arguably ++ as secure. The *curve_name* parameter should be a string describing ++ a well-known elliptic curve, for example ``prime256v1`` for a widely ++ supported curve. ++ ++ This setting doesn't apply to client sockets. You can also use the ++ :data:`OP_SINGLE_ECDH_USE` option to further improve security. ++ ++ This method is not available if :data:`HAS_ECDH` is False. ++ ++ .. seealso:: ++ `SSL/TLS & Perfect Forward Secrecy `_ ++ Vincent Bernat. ++ ++.. method:: SSLContext.wrap_socket(sock, server_side=False, \ ++ do_handshake_on_connect=True, suppress_ragged_eofs=True, \ ++ server_hostname=None) ++ ++ Wrap an existing Python socket *sock* and return an :class:`SSLSocket` ++ object. *sock* must be a :data:`~socket.SOCK_STREAM` socket; other socket ++ types are unsupported. ++ ++ The returned SSL socket is tied to the context, its settings and ++ certificates. The parameters *server_side*, *do_handshake_on_connect* ++ and *suppress_ragged_eofs* have the same meaning as in the top-level ++ :func:`wrap_socket` function. ++ ++ On client connections, the optional parameter *server_hostname* specifies ++ the hostname of the service which we are connecting to. This allows a ++ single server to host multiple SSL-based services with distinct certificates, ++ quite similarly to HTTP virtual hosts. Specifying *server_hostname* ++ will raise a :exc:`ValueError` if the OpenSSL library doesn't have support ++ for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying ++ *server_hostname* will also raise a :exc:`ValueError` if *server_side* ++ is true. ++ ++.. method:: SSLContext.session_stats() ++ ++ Get statistics about the SSL sessions created or managed by this context. ++ A dictionary is returned which maps the names of each `piece of information ++ `_ to their ++ numeric values. For example, here is the total number of hits and misses ++ in the session cache since the context was created:: ++ ++ >>> stats = context.session_stats() ++ >>> stats['hits'], stats['misses'] ++ (0, 0) ++ ++.. method:: SSLContext.get_ca_certs(binary_form=False) ++ ++ Returns a list of dicts with information of loaded CA certs. If the ++ optional argument is true, returns a DER-encoded copy of the CA ++ certificate. ++ ++ .. note:: ++ Certificates in a capath directory aren't loaded unless they have ++ been used at least once. ++ ++.. attribute:: SSLContext.check_hostname ++ ++ Wether to match the peer cert's hostname with :func:`match_hostname` in ++ :meth:`SSLSocket.do_handshake`. The context's ++ :attr:`~SSLContext.verify_mode` must be set to :data:`CERT_OPTIONAL` or ++ :data:`CERT_REQUIRED`, and you must pass *server_hostname* to ++ :meth:`~SSLContext.wrap_socket` in order to match the hostname. ++ ++ Example:: ++ ++ import socket, ssl ++ ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.check_hostname = True ++ context.load_default_certs() ++ ++ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com') ++ ssl_sock.connect(('www.verisign.com', 443)) ++ ++ .. note:: ++ ++ This features requires OpenSSL 0.9.8f or newer. ++ ++.. attribute:: SSLContext.options ++ ++ An integer representing the set of SSL options enabled on this context. ++ The default value is :data:`OP_ALL`, but you can specify other options ++ such as :data:`OP_NO_SSLv2` by ORing them together. ++ ++ .. note:: ++ With versions of OpenSSL older than 0.9.8m, it is only possible ++ to set options, not to clear them. Attempting to clear an option ++ (by resetting the corresponding bits) will raise a ``ValueError``. ++ ++.. attribute:: SSLContext.protocol ++ ++ The protocol version chosen when constructing the context. This attribute ++ is read-only. ++ ++.. attribute:: SSLContext.verify_flags ++ ++ The flags for certificate verification operations. You can set flags like ++ :data:`VERIFY_CRL_CHECK_LEAF` by ORing them together. By default OpenSSL ++ does neither require nor verify certificate revocation lists (CRLs). ++ Available only with openssl version 0.9.8+. ++ ++.. attribute:: SSLContext.verify_mode ++ ++ Whether to try to verify other peers' certificates and how to behave ++ if verification fails. This attribute must be one of ++ :data:`CERT_NONE`, :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`. ++ + + .. index:: single: certificates + +@@ -445,6 +1249,9 @@ and a footer line:: + ... (certificate in base64 PEM encoding) ... + -----END CERTIFICATE----- + ++Certificate chains ++^^^^^^^^^^^^^^^^^^ ++ + The Python files which contain certificates can contain a sequence of + certificates, sometimes called a *certificate chain*. This chain should start + with the specific certificate for the principal who "is" the client or server, +@@ -468,25 +1275,35 @@ certification authority's certificate:: + ... (the root certificate for the CA's issuer)... + -----END CERTIFICATE----- + ++CA certificates ++^^^^^^^^^^^^^^^ ++ + If you are going to require validation of the other side of the connection's + certificate, you need to provide a "CA certs" file, filled with the certificate + chains for each issuer you are willing to trust. Again, this file just contains + these chains concatenated together. For validation, Python will use the first +-chain it finds in the file which matches. ++chain it finds in the file which matches. The platform's certificates file can ++be used by calling :meth:`SSLContext.load_default_certs`, this is done ++automatically with :func:`.create_default_context`. ++ ++Combined key and certificate ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Often the private key is stored in the same file as the certificate; in this ++case, only the ``certfile`` parameter to :meth:`SSLContext.load_cert_chain` ++and :func:`wrap_socket` needs to be passed. If the private key is stored ++with the certificate, it should come before the first certificate in ++the certificate chain:: ++ ++ -----BEGIN RSA PRIVATE KEY----- ++ ... (private key in base64 encoding) ... ++ -----END RSA PRIVATE KEY----- ++ -----BEGIN CERTIFICATE----- ++ ... (certificate in base64 PEM encoding) ... ++ -----END CERTIFICATE----- + +-Some "standard" root certificates are available from various certification +-authorities: `CACert.org `_, `Thawte +-`_, `Verisign +-`_, `Positive SSL +-`_ +-(used by python.org), `Equifax and GeoTrust +-`_. +- +-In general, if you are using SSL3 or TLS1, you don't need to put the full chain +-in your "CA certs" file; you only need the root certificates, and the remote +-peer is supposed to furnish the other certificates necessary to chain from its +-certificate to a root certificate. See :rfc:`4158` for more discussion of the +-way in which certification chains can be built. ++Self-signed certificates ++^^^^^^^^^^^^^^^^^^^^^^^^ + + If you are going to create a server that provides SSL-encrypted connection + services, you will need to acquire a certificate for that service. There are +@@ -541,87 +1358,156 @@ should use the following idiom:: + Client-side operation + ^^^^^^^^^^^^^^^^^^^^^ + +-This example connects to an SSL server, prints the server's address and +-certificate, sends some bytes, and reads part of the response:: ++This example connects to an SSL server and prints the server's certificate:: + + import socket, ssl, pprint + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +- + # require a certificate from the server + ssl_sock = ssl.wrap_socket(s, + ca_certs="/etc/ca_certs_file", + cert_reqs=ssl.CERT_REQUIRED) +- + ssl_sock.connect(('www.verisign.com', 443)) + +- print repr(ssl_sock.getpeername()) +- print ssl_sock.cipher() +- print pprint.pformat(ssl_sock.getpeercert()) +- +- # Set a simple HTTP request -- use httplib in actual code. +- ssl_sock.write("""GET / HTTP/1.0\r +- Host: www.verisign.com\r\n\r\n""") +- +- # Read a chunk of data. Will not necessarily +- # read all the data returned by the server. +- data = ssl_sock.read() +- ++ pprint.pprint(ssl_sock.getpeercert()) + # note that closing the SSLSocket will also close the underlying socket + ssl_sock.close() + +-As of September 6, 2007, the certificate printed by this program looked like ++As of January 6, 2012, the certificate printed by this program looks like + this:: + +- {'notAfter': 'May 8 23:59:59 2009 GMT', +- 'subject': ((('serialNumber', u'2497886'),), +- (('1.3.6.1.4.1.311.60.2.1.3', u'US'),), +- (('1.3.6.1.4.1.311.60.2.1.2', u'Delaware'),), +- (('countryName', u'US'),), +- (('postalCode', u'94043'),), +- (('stateOrProvinceName', u'California'),), +- (('localityName', u'Mountain View'),), +- (('streetAddress', u'487 East Middlefield Road'),), +- (('organizationName', u'VeriSign, Inc.'),), +- (('organizationalUnitName', +- u'Production Security Services'),), +- (('organizationalUnitName', +- u'Terms of use at www.verisign.com/rpa (c)06'),), +- (('commonName', u'www.verisign.com'),))} ++ {'issuer': ((('countryName', 'US'),), ++ (('organizationName', 'VeriSign, Inc.'),), ++ (('organizationalUnitName', 'VeriSign Trust Network'),), ++ (('organizationalUnitName', ++ 'Terms of use at https://www.verisign.com/rpa (c)06'),), ++ (('commonName', ++ 'VeriSign Class 3 Extended Validation SSL SGC CA'),)), ++ 'notAfter': 'May 25 23:59:59 2012 GMT', ++ 'notBefore': 'May 26 00:00:00 2010 GMT', ++ 'serialNumber': '53D2BEF924A7245E83CA01E46CAA2477', ++ 'subject': ((('1.3.6.1.4.1.311.60.2.1.3', 'US'),), ++ (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), ++ (('businessCategory', 'V1.0, Clause 5.(b)'),), ++ (('serialNumber', '2497886'),), ++ (('countryName', 'US'),), ++ (('postalCode', '94043'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'Mountain View'),), ++ (('streetAddress', '487 East Middlefield Road'),), ++ (('organizationName', 'VeriSign, Inc.'),), ++ (('organizationalUnitName', ' Production Security Services'),), ++ (('commonName', 'www.verisign.com'),)), ++ 'subjectAltName': (('DNS', 'www.verisign.com'), ++ ('DNS', 'verisign.com'), ++ ('DNS', 'www.verisign.net'), ++ ('DNS', 'verisign.net'), ++ ('DNS', 'www.verisign.mobi'), ++ ('DNS', 'verisign.mobi'), ++ ('DNS', 'www.verisign.eu'), ++ ('DNS', 'verisign.eu')), ++ 'version': 3} ++ ++This other example first creates an SSL context, instructs it to verify ++certificates sent by peers, and feeds it a set of recognized certificate ++authorities (CA):: ++ ++ >>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ >>> context.verify_mode = ssl.CERT_REQUIRED ++ >>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt") ++ ++(it is assumed your operating system places a bundle of all CA certificates ++in ``/etc/ssl/certs/ca-bundle.crt``; if not, you'll get an error and have ++to adjust the location) ++ ++When you use the context to connect to a server, :const:`CERT_REQUIRED` ++validates the server certificate: it ensures that the server certificate ++was signed with one of the CA certificates, and checks the signature for ++correctness:: ++ ++ >>> conn = context.wrap_socket(socket.socket(socket.AF_INET)) ++ >>> conn.connect(("linuxfr.org", 443)) ++ ++You should then fetch the certificate and check its fields for conformity:: ++ ++ >>> cert = conn.getpeercert() ++ >>> ssl.match_hostname(cert, "linuxfr.org") ++ ++Visual inspection shows that the certificate does identify the desired service ++(that is, the HTTPS host ``linuxfr.org``):: ++ ++ >>> pprint.pprint(cert) ++ {'issuer': ((('organizationName', 'CAcert Inc.'),), ++ (('organizationalUnitName', 'http://www.CAcert.org'),), ++ (('commonName', 'CAcert Class 3 Root'),)), ++ 'notAfter': 'Jun 7 21:02:24 2013 GMT', ++ 'notBefore': 'Jun 8 21:02:24 2011 GMT', ++ 'serialNumber': 'D3E9', ++ 'subject': ((('commonName', 'linuxfr.org'),),), ++ 'subjectAltName': (('DNS', 'linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'dev.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'prod.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'alpha.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', '*.linuxfr.org'), ++ ('othername', '')), ++ 'version': 3} ++ ++Now that you are assured of its authenticity, you can proceed to talk with ++the server:: ++ ++ >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n") ++ >>> pprint.pprint(conn.recv(1024).split(b"\r\n")) ++ [b'HTTP/1.1 302 Found', ++ b'Date: Sun, 16 May 2010 13:43:28 GMT', ++ b'Server: Apache/2.2', ++ b'Location: https://linuxfr.org/pub/', ++ b'Vary: Accept-Encoding', ++ b'Connection: close', ++ b'Content-Type: text/html; charset=iso-8859-1', ++ b'', ++ b''] ++ ++See the discussion of :ref:`ssl-security` below. + +-which is a fairly poorly-formed ``subject`` field. + + Server-side operation + ^^^^^^^^^^^^^^^^^^^^^ + +-For server operation, typically you'd need to have a server certificate, and +-private key, each in a file. You'd open a socket, bind it to a port, call +-:meth:`listen` on it, then start waiting for clients to connect:: ++For server operation, typically you'll need to have a server certificate, and ++private key, each in a file. You'll first create a context holding the key ++and the certificate, so that clients can check your authenticity. Then ++you'll open a socket, bind it to a port, call :meth:`listen` on it, and start ++waiting for clients to connect:: + + import socket, ssl + ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile") ++ + bindsocket = socket.socket() + bindsocket.bind(('myaddr.mydomain.com', 10023)) + bindsocket.listen(5) + +-When one did, you'd call :meth:`accept` on the socket to get the new socket from +-the other end, and use :func:`wrap_socket` to create a server-side SSL context +-for it:: ++When a client connects, you'll call :meth:`accept` on the socket to get the ++new socket from the other end, and use the context's :meth:`SSLContext.wrap_socket` ++method to create a server-side SSL socket for the connection:: + + while True: + newsocket, fromaddr = bindsocket.accept() +- connstream = ssl.wrap_socket(newsocket, +- server_side=True, +- certfile="mycertfile", +- keyfile="mykeyfile", +- ssl_version=ssl.PROTOCOL_TLSv1) ++ connstream = context.wrap_socket(newsocket, server_side=True) + try: + deal_with_client(connstream) + finally: + connstream.shutdown(socket.SHUT_RDWR) + connstream.close() + +-Then you'd read data from the ``connstream`` and do something with it till you ++Then you'll read data from the ``connstream`` and do something with it till you + are finished with the client (or the client is finished with you):: + + def deal_with_client(connstream): +@@ -635,7 +1521,138 @@ are finished with the client (or the cli + data = connstream.read() + # finished with client + +-And go back to listening for new client connections. ++And go back to listening for new client connections (of course, a real server ++would probably handle each client connection in a separate thread, or put ++the sockets in non-blocking mode and use an event loop). ++ ++ ++.. _ssl-nonblocking: ++ ++Notes on non-blocking sockets ++----------------------------- ++ ++When working with non-blocking sockets, there are several things you need ++to be aware of: ++ ++- Calling :func:`~select.select` tells you that the OS-level socket can be ++ read from (or written to), but it does not imply that there is sufficient ++ data at the upper SSL layer. For example, only part of an SSL frame might ++ have arrived. Therefore, you must be ready to handle :meth:`SSLSocket.recv` ++ and :meth:`SSLSocket.send` failures, and retry after another call to ++ :func:`~select.select`. ++ ++- Conversely, since the SSL layer has its own framing, a SSL socket may ++ still have data available for reading without :func:`~select.select` ++ being aware of it. Therefore, you should first call ++ :meth:`SSLSocket.recv` to drain any potentially available data, and then ++ only block on a :func:`~select.select` call if still necessary. ++ ++ (of course, similar provisions apply when using other primitives such as ++ :func:`~select.poll`, or those in the :mod:`selectors` module) ++ ++- The SSL handshake itself will be non-blocking: the ++ :meth:`SSLSocket.do_handshake` method has to be retried until it returns ++ successfully. Here is a synopsis using :func:`~select.select` to wait for ++ the socket's readiness:: ++ ++ while True: ++ try: ++ sock.do_handshake() ++ break ++ except ssl.SSLWantReadError: ++ select.select([sock], [], []) ++ except ssl.SSLWantWriteError: ++ select.select([], [sock], []) ++ ++ ++.. _ssl-security: ++ ++Security considerations ++----------------------- ++ ++Best defaults ++^^^^^^^^^^^^^ ++ ++For **client use**, if you don't have any special requirements for your ++security policy, it is highly recommended that you use the ++:func:`create_default_context` function to create your SSL context. ++It will load the system's trusted CA certificates, enable certificate ++validation and hostname checking, and try to choose reasonably secure ++protocol and cipher settings. ++ ++If a client certificate is needed for the connection, it can be added with ++:meth:`SSLContext.load_cert_chain`. ++ ++By contrast, if you create the SSL context by calling the :class:`SSLContext` ++constructor yourself, it will not have certificate validation nor hostname ++checking enabled by default. If you do so, please read the paragraphs below ++to achieve a good security level. ++ ++Manual settings ++^^^^^^^^^^^^^^^ ++ ++Verifying certificates ++'''''''''''''''''''''' ++ ++When calling the :class:`SSLContext` constructor directly, ++:const:`CERT_NONE` is the default. Since it does not authenticate the other ++peer, it can be insecure, especially in client mode where most of time you ++would like to ensure the authenticity of the server you're talking to. ++Therefore, when in client mode, it is highly recommended to use ++:const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also ++have to check that the server certificate, which can be obtained by calling ++:meth:`SSLSocket.getpeercert`, matches the desired service. For many ++protocols and applications, the service can be identified by the hostname; ++in this case, the :func:`match_hostname` function can be used. This common ++check is automatically performed when :attr:`SSLContext.check_hostname` is ++enabled. ++ ++In server mode, if you want to authenticate your clients using the SSL layer ++(rather than using a higher-level authentication mechanism), you'll also have ++to specify :const:`CERT_REQUIRED` and similarly check the client certificate. ++ ++ .. note:: ++ ++ In client mode, :const:`CERT_OPTIONAL` and :const:`CERT_REQUIRED` are ++ equivalent unless anonymous ciphers are enabled (they are disabled ++ by default). ++ ++Protocol versions ++''''''''''''''''' ++ ++SSL version 2 is considered insecure and is therefore dangerous to use. If ++you want maximum compatibility between clients and servers, it is recommended ++to use :const:`PROTOCOL_SSLv23` as the protocol version and then disable ++SSLv2 explicitly using the :data:`SSLContext.options` attribute:: ++ ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.options |= ssl.OP_NO_SSLv2 ++ ++The SSL context created above will allow SSLv3 and TLSv1 (and later, if ++supported by your system) connections, but not SSLv2. ++ ++Cipher selection ++'''''''''''''''' ++ ++If you have advanced security requirements, fine-tuning of the ciphers ++enabled when negotiating a SSL session is possible through the ++:meth:`SSLContext.set_ciphers` method. Starting from Python 2.7.9, the ++ssl module disables certain weak ciphers by default, but you may want ++to further restrict the cipher choice. Be sure to read OpenSSL's documentation ++about the `cipher list format `_. ++If you want to check which ciphers are enabled by a given cipher list, use the ++``openssl ciphers`` command on your system. ++ ++Multi-processing ++^^^^^^^^^^^^^^^^ ++ ++If using this module as part of a multi-processed application (using, ++for example the :mod:`multiprocessing` or :mod:`concurrent.futures` modules), ++be aware that OpenSSL's internal random number generator does not properly ++handle forked processes. Applications must change the PRNG state of the ++parent process if they use any SSL feature with :func:`os.fork`. Any ++successful call of :func:`~ssl.RAND_add`, :func:`~ssl.RAND_bytes` or ++:func:`~ssl.RAND_pseudo_bytes` is sufficient. + + + .. seealso:: +@@ -654,3 +1671,15 @@ And go back to listening for new client + + `RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile `_ + Housley et. al. ++ ++ `RFC 4366: Transport Layer Security (TLS) Extensions `_ ++ Blake-Wilson et. al. ++ ++ `RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 `_ ++ T. Dierks et. al. ++ ++ `RFC 6066: Transport Layer Security (TLS) Extensions `_ ++ D. Eastlake ++ ++ `IANA TLS: Transport Layer Security (TLS) Parameters `_ ++ IANA +diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl Python-2.7.5/Lib/test/test_ssl.py +--- Python-2.7.5/Lib/test/test_ssl.py.ssl 2015-02-24 11:37:12.270937480 +0100 ++++ Python-2.7.5/Lib/test/test_ssl.py 2015-02-24 10:17:44.084768602 +0100 +@@ -1,35 +1,78 @@ ++# -*- coding: utf-8 -*- + # Test the support for SSL and sockets + + import sys + import unittest +-from test import test_support ++from test import test_support as support + import asyncore + import socket + import select + import time ++import datetime + import gc + import os + import errno + import pprint +-import urllib, urlparse ++import tempfile ++import urllib + import traceback + import weakref +-import functools + import platform ++import functools ++from contextlib import closing ++ ++ssl = support.import_module("ssl") + +-from BaseHTTPServer import HTTPServer +-from SimpleHTTPServer import SimpleHTTPRequestHandler ++PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) ++HOST = support.HOST + +-ssl = test_support.import_module("ssl") ++def data_file(*name): ++ return os.path.join(os.path.dirname(__file__), *name) ++ ++# The custom key and certificate files used in test_ssl are generated ++# using Lib/test/make_ssl_certs.py. ++# Other certificates are simply fetched from the Internet servers they ++# are meant to authenticate. ++ ++CERTFILE = data_file("keycert.pem") ++BYTES_CERTFILE = CERTFILE.encode(sys.getfilesystemencoding()) ++ONLYCERT = data_file("ssl_cert.pem") ++ONLYKEY = data_file("ssl_key.pem") ++BYTES_ONLYCERT = ONLYCERT.encode(sys.getfilesystemencoding()) ++BYTES_ONLYKEY = ONLYKEY.encode(sys.getfilesystemencoding()) ++CERTFILE_PROTECTED = data_file("keycert.passwd.pem") ++ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem") ++KEY_PASSWORD = "somepass" ++CAPATH = data_file("capath") ++BYTES_CAPATH = CAPATH.encode(sys.getfilesystemencoding()) ++CAFILE_NEURONIO = data_file("capath", "4e1295a3.0") ++CAFILE_CACERT = data_file("capath", "5ed36f99.0") ++ ++ ++# empty CRL ++CRLFILE = data_file("revocation.crl") ++ ++# Two keys and certs signed by the same CA (for SNI tests) ++SIGNED_CERTFILE = data_file("keycert3.pem") ++SIGNED_CERTFILE2 = data_file("keycert4.pem") ++SIGNING_CA = data_file("pycacert.pem") ++ ++SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem") ++ ++EMPTYCERT = data_file("nullcert.pem") ++BADCERT = data_file("badcert.pem") ++WRONGCERT = data_file("XXXnonexisting.pem") ++BADKEY = data_file("badkey.pem") ++NOKIACERT = data_file("nokia.pem") ++NULLBYTECERT = data_file("nullbytecert.pem") ++ ++DHFILE = data_file("dh512.pem") ++BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) + +-HOST = test_support.HOST +-CERTFILE = None +-SVN_PYTHON_ORG_ROOT_CERT = None +-NULLBYTECERT = None + + def handle_error(prefix): + exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(prefix + exc_format) + + +@@ -51,48 +94,76 @@ class BasicTests(unittest.TestCase): + pass + else: + raise ++def can_clear_options(): ++ # 0.9.8m or higher ++ return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) ++ ++def no_sslv2_implies_sslv3_hello(): ++ # 0.9.7h or higher ++ return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15) ++ ++def have_verify_flags(): ++ # 0.9.8 or higher ++ return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15) ++ ++def utc_offset(): #NOTE: ignore issues like #1647654 ++ # local time = utc time + utc offset ++ if time.daylight and time.localtime().tm_isdst > 0: ++ return -time.altzone # seconds ++ return -time.timezone ++ ++def asn1time(cert_time): ++ # Some versions of OpenSSL ignore seconds, see #18207 ++ # 0.9.8.i ++ if ssl._OPENSSL_API_VERSION == (0, 9, 8, 9, 15): ++ fmt = "%b %d %H:%M:%S %Y GMT" ++ dt = datetime.datetime.strptime(cert_time, fmt) ++ dt = dt.replace(second=0) ++ cert_time = dt.strftime(fmt) ++ # %d adds leading zero but ASN1_TIME_print() uses leading space ++ if cert_time[4] == "0": ++ cert_time = cert_time[:4] + " " + cert_time[5:] ++ ++ return cert_time + + # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 + def skip_if_broken_ubuntu_ssl(func): + if hasattr(ssl, 'PROTOCOL_SSLv2'): +- # We need to access the lower-level wrapper in order to create an +- # implicit SSL context without trying to connect or listen. +- try: +- import _ssl +- except ImportError: +- # The returned function won't get executed, just ignore the error +- pass + @functools.wraps(func) + def f(*args, **kwargs): + try: +- s = socket.socket(socket.AF_INET) +- _ssl.sslwrap(s._sock, 0, None, None, +- ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None) +- except ssl.SSLError as e: ++ ssl.SSLContext(ssl.PROTOCOL_SSLv2) ++ except ssl.SSLError: + if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and +- platform.linux_distribution() == ('debian', 'squeeze/sid', '') +- and 'Invalid SSL protocol variant specified' in str(e)): ++ platform.linux_distribution() == ('debian', 'squeeze/sid', '')): + raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") + return func(*args, **kwargs) + return f + else: + return func + ++needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") ++ + + class BasicSocketTests(unittest.TestCase): + + def test_constants(self): +- #ssl.PROTOCOL_SSLv2 +- ssl.PROTOCOL_SSLv23 +- ssl.PROTOCOL_SSLv3 +- ssl.PROTOCOL_TLSv1 + ssl.CERT_NONE + ssl.CERT_OPTIONAL + ssl.CERT_REQUIRED ++ ssl.OP_CIPHER_SERVER_PREFERENCE ++ ssl.OP_SINGLE_DH_USE ++ if ssl.HAS_ECDH: ++ ssl.OP_SINGLE_ECDH_USE ++ if ssl.OPENSSL_VERSION_INFO >= (1, 0): ++ ssl.OP_NO_COMPRESSION ++ self.assertIn(ssl.HAS_SNI, {True, False}) ++ self.assertIn(ssl.HAS_ECDH, {True, False}) ++ + + def test_random(self): + v = ssl.RAND_status() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n RAND_status is %d (%s)\n" + % (v, (v and "sufficient randomness") or + "insufficient randomness")) +@@ -104,9 +175,19 @@ class BasicSocketTests(unittest.TestCase + # note that this uses an 'unofficial' function in _ssl.c, + # provided solely for this test, to exercise the certificate + # parsing code +- p = ssl._ssl._test_decode_cert(CERTFILE, False) +- if test_support.verbose: ++ p = ssl._ssl._test_decode_cert(CERTFILE) ++ if support.verbose: + sys.stdout.write("\n" + pprint.pformat(p) + "\n") ++ self.assertEqual(p['issuer'], ++ ((('countryName', 'XY'),), ++ (('localityName', 'Castle Anthrax'),), ++ (('organizationName', 'Python Software Foundation'),), ++ (('commonName', 'localhost'),)) ++ ) ++ # Note the next three asserts will fail if the keys are regenerated ++ self.assertEqual(p['notAfter'], asn1time('Oct 5 23:01:56 2020 GMT')) ++ self.assertEqual(p['notBefore'], asn1time('Oct 8 23:01:56 2010 GMT')) ++ self.assertEqual(p['serialNumber'], 'D7C7381919AFC24E') + self.assertEqual(p['subject'], + ((('countryName', 'XY'),), + (('localityName', 'Castle Anthrax'),), +@@ -117,16 +198,23 @@ class BasicSocketTests(unittest.TestCase + # Issue #13034: the subjectAltName in some certificates + # (notably projects.developer.nokia.com:443) wasn't parsed + p = ssl._ssl._test_decode_cert(NOKIACERT) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n" + pprint.pformat(p) + "\n") + self.assertEqual(p['subjectAltName'], + (('DNS', 'projects.developer.nokia.com'), + ('DNS', 'projects.forum.nokia.com')) + ) ++ # extra OCSP and AIA fields ++ self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',)) ++ self.assertEqual(p['caIssuers'], ++ ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',)) ++ self.assertEqual(p['crlDistributionPoints'], ++ ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) ++ + + def test_parse_cert_CVE_2013_4073(self): + p = ssl._ssl._test_decode_cert(NULLBYTECERT) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n" + pprint.pformat(p) + "\n") + subject = ((('countryName', 'US'),), + (('stateOrProvinceName', 'Oregon'),), +@@ -184,25 +272,7 @@ class BasicSocketTests(unittest.TestCase + self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), + (s, t)) + +- def test_ciphers(self): +- if not test_support.is_resource_enabled('network'): +- return +- remote = ("svn.python.org", 443) +- with test_support.transient_internet(remote[0]): +- s = ssl.wrap_socket(socket.socket(socket.AF_INET), +- cert_reqs=ssl.CERT_NONE, ciphers="ALL") +- s.connect(remote) +- s = ssl.wrap_socket(socket.socket(socket.AF_INET), +- cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") +- s.connect(remote) +- # Error checking occurs when connecting, because the SSL context +- # isn't created before. +- s = ssl.wrap_socket(socket.socket(socket.AF_INET), +- cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") +- with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): +- s.connect(remote) +- +- @test_support.cpython_only ++ @support.cpython_only + def test_refcycle(self): + # Issue #7943: an SSL object doesn't create reference cycles with + # itself. +@@ -213,53 +283,917 @@ class BasicSocketTests(unittest.TestCase + self.assertEqual(wr(), None) + + def test_wrapped_unconnected(self): +- # The _delegate_methods in socket.py are correctly delegated to by an +- # unconnected SSLSocket, so they will raise a socket.error rather than +- # something unexpected like TypeError. ++ # Methods on an unconnected SSLSocket propagate the original ++ # socket.error raise by the underlying socket object. + s = socket.socket(socket.AF_INET) +- ss = ssl.wrap_socket(s) +- self.assertRaises(socket.error, ss.recv, 1) +- self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) +- self.assertRaises(socket.error, ss.recvfrom, 1) +- self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) +- self.assertRaises(socket.error, ss.send, b'x') +- self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) ++ with closing(ssl.wrap_socket(s)) as ss: ++ self.assertRaises(socket.error, ss.recv, 1) ++ self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) ++ self.assertRaises(socket.error, ss.recvfrom, 1) ++ self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) ++ self.assertRaises(socket.error, ss.send, b'x') ++ self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) ++ ++ def test_timeout(self): ++ # Issue #8524: when creating an SSL socket, the timeout of the ++ # original socket should be retained. ++ for timeout in (None, 0.0, 5.0): ++ s = socket.socket(socket.AF_INET) ++ s.settimeout(timeout) ++ with closing(ssl.wrap_socket(s)) as ss: ++ self.assertEqual(timeout, ss.gettimeout()) ++ ++ def test_errors(self): ++ sock = socket.socket() ++ self.assertRaisesRegexp(ValueError, ++ "certfile must be specified", ++ ssl.wrap_socket, sock, keyfile=CERTFILE) ++ self.assertRaisesRegexp(ValueError, ++ "certfile must be specified for server-side operations", ++ ssl.wrap_socket, sock, server_side=True) ++ self.assertRaisesRegexp(ValueError, ++ "certfile must be specified for server-side operations", ++ ssl.wrap_socket, sock, server_side=True, certfile="") ++ with closing(ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE)) as s: ++ self.assertRaisesRegexp(ValueError, "can't connect in server-side mode", ++ s.connect, (HOST, 8080)) ++ with self.assertRaises(IOError) as cm: ++ with closing(socket.socket()) as sock: ++ ssl.wrap_socket(sock, certfile=WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaises(IOError) as cm: ++ with closing(socket.socket()) as sock: ++ ssl.wrap_socket(sock, certfile=CERTFILE, keyfile=WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaises(IOError) as cm: ++ with closing(socket.socket()) as sock: ++ ssl.wrap_socket(sock, certfile=WRONGCERT, keyfile=WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ ++ def test_match_hostname(self): ++ def ok(cert, hostname): ++ ssl.match_hostname(cert, hostname) ++ def fail(cert, hostname): ++ self.assertRaises(ssl.CertificateError, ++ ssl.match_hostname, cert, hostname) ++ ++ cert = {'subject': ((('commonName', 'example.com'),),)} ++ ok(cert, 'example.com') ++ ok(cert, 'ExAmple.cOm') ++ fail(cert, 'www.example.com') ++ fail(cert, '.example.com') ++ fail(cert, 'example.org') ++ fail(cert, 'exampleXcom') ++ ++ cert = {'subject': ((('commonName', '*.a.com'),),)} ++ ok(cert, 'foo.a.com') ++ fail(cert, 'bar.foo.a.com') ++ fail(cert, 'a.com') ++ fail(cert, 'Xa.com') ++ fail(cert, '.a.com') ++ ++ # only match one left-most wildcard ++ cert = {'subject': ((('commonName', 'f*.com'),),)} ++ ok(cert, 'foo.com') ++ ok(cert, 'f.com') ++ fail(cert, 'bar.com') ++ fail(cert, 'foo.a.com') ++ fail(cert, 'bar.foo.com') ++ ++ # NULL bytes are bad, CVE-2013-4073 ++ cert = {'subject': ((('commonName', ++ 'null.python.org\x00example.org'),),)} ++ ok(cert, 'null.python.org\x00example.org') # or raise an error? ++ fail(cert, 'example.org') ++ fail(cert, 'null.python.org') ++ ++ # error cases with wildcards ++ cert = {'subject': ((('commonName', '*.*.a.com'),),)} ++ fail(cert, 'bar.foo.a.com') ++ fail(cert, 'a.com') ++ fail(cert, 'Xa.com') ++ fail(cert, '.a.com') ++ ++ cert = {'subject': ((('commonName', 'a.*.com'),),)} ++ fail(cert, 'a.foo.com') ++ fail(cert, 'a..com') ++ fail(cert, 'a.com') ++ ++ # wildcard doesn't match IDNA prefix 'xn--' ++ idna = u'püthon.python.org'.encode("idna").decode("ascii") ++ cert = {'subject': ((('commonName', idna),),)} ++ ok(cert, idna) ++ cert = {'subject': ((('commonName', 'x*.python.org'),),)} ++ fail(cert, idna) ++ cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)} ++ fail(cert, idna) ++ ++ # wildcard in first fragment and IDNA A-labels in sequent fragments ++ # are supported. ++ idna = u'www*.pythön.org'.encode("idna").decode("ascii") ++ cert = {'subject': ((('commonName', idna),),)} ++ ok(cert, u'www.pythön.org'.encode("idna").decode("ascii")) ++ ok(cert, u'www1.pythön.org'.encode("idna").decode("ascii")) ++ fail(cert, u'ftp.pythön.org'.encode("idna").decode("ascii")) ++ fail(cert, u'pythön.org'.encode("idna").decode("ascii")) ++ ++ # Slightly fake real-world example ++ cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT', ++ 'subject': ((('commonName', 'linuxfrz.org'),),), ++ 'subjectAltName': (('DNS', 'linuxfr.org'), ++ ('DNS', 'linuxfr.com'), ++ ('othername', ''))} ++ ok(cert, 'linuxfr.org') ++ ok(cert, 'linuxfr.com') ++ # Not a "DNS" entry ++ fail(cert, '') ++ # When there is a subjectAltName, commonName isn't used ++ fail(cert, 'linuxfrz.org') ++ ++ # A pristine real-world example ++ cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT', ++ 'subject': ((('countryName', 'US'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'Mountain View'),), ++ (('organizationName', 'Google Inc'),), ++ (('commonName', 'mail.google.com'),))} ++ ok(cert, 'mail.google.com') ++ fail(cert, 'gmail.com') ++ # Only commonName is considered ++ fail(cert, 'California') ++ ++ # Neither commonName nor subjectAltName ++ cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT', ++ 'subject': ((('countryName', 'US'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'Mountain View'),), ++ (('organizationName', 'Google Inc'),))} ++ fail(cert, 'mail.google.com') ++ ++ # No DNS entry in subjectAltName but a commonName ++ cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', ++ 'subject': ((('countryName', 'US'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'Mountain View'),), ++ (('commonName', 'mail.google.com'),)), ++ 'subjectAltName': (('othername', 'blabla'), )} ++ ok(cert, 'mail.google.com') ++ ++ # No DNS entry subjectAltName and no commonName ++ cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', ++ 'subject': ((('countryName', 'US'),), ++ (('stateOrProvinceName', 'California'),), ++ (('localityName', 'Mountain View'),), ++ (('organizationName', 'Google Inc'),)), ++ 'subjectAltName': (('othername', 'blabla'),)} ++ fail(cert, 'google.com') ++ ++ # Empty cert / no cert ++ self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') ++ self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') ++ ++ # Issue #17980: avoid denials of service by refusing more than one ++ # wildcard per fragment. ++ cert = {'subject': ((('commonName', 'a*b.com'),),)} ++ ok(cert, 'axxb.com') ++ cert = {'subject': ((('commonName', 'a*b.co*'),),)} ++ fail(cert, 'axxb.com') ++ cert = {'subject': ((('commonName', 'a*b*.com'),),)} ++ with self.assertRaises(ssl.CertificateError) as cm: ++ ssl.match_hostname(cert, 'axxbxxc.com') ++ self.assertIn("too many wildcards", str(cm.exception)) ++ ++ def test_server_side(self): ++ # server_hostname doesn't work for server sockets ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ with closing(socket.socket()) as sock: ++ self.assertRaises(ValueError, ctx.wrap_socket, sock, True, ++ server_hostname="some.hostname") ++ ++ def test_unknown_channel_binding(self): ++ # should raise ValueError for unknown type ++ s = socket.socket(socket.AF_INET) ++ with closing(ssl.wrap_socket(s)) as ss: ++ with self.assertRaises(ValueError): ++ ss.get_channel_binding("unknown-type") ++ ++ @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES, ++ "'tls-unique' channel binding not available") ++ def test_tls_unique_channel_binding(self): ++ # unconnected should return None for known type ++ s = socket.socket(socket.AF_INET) ++ with closing(ssl.wrap_socket(s)) as ss: ++ self.assertIsNone(ss.get_channel_binding("tls-unique")) ++ # the same for server-side ++ s = socket.socket(socket.AF_INET) ++ with closing(ssl.wrap_socket(s, server_side=True, certfile=CERTFILE)) as ss: ++ self.assertIsNone(ss.get_channel_binding("tls-unique")) ++ ++ def test_get_default_verify_paths(self): ++ paths = ssl.get_default_verify_paths() ++ self.assertEqual(len(paths), 6) ++ self.assertIsInstance(paths, ssl.DefaultVerifyPaths) ++ ++ with support.EnvironmentVarGuard() as env: ++ env["SSL_CERT_DIR"] = CAPATH ++ env["SSL_CERT_FILE"] = CERTFILE ++ paths = ssl.get_default_verify_paths() ++ self.assertEqual(paths.cafile, CERTFILE) ++ self.assertEqual(paths.capath, CAPATH) ++ ++ @unittest.skipUnless(sys.platform == "win32", "Windows specific") ++ def test_enum_certificates(self): ++ self.assertTrue(ssl.enum_certificates("CA")) ++ self.assertTrue(ssl.enum_certificates("ROOT")) ++ ++ self.assertRaises(TypeError, ssl.enum_certificates) ++ self.assertRaises(WindowsError, ssl.enum_certificates, "") ++ ++ trust_oids = set() ++ for storename in ("CA", "ROOT"): ++ store = ssl.enum_certificates(storename) ++ self.assertIsInstance(store, list) ++ for element in store: ++ self.assertIsInstance(element, tuple) ++ self.assertEqual(len(element), 3) ++ cert, enc, trust = element ++ self.assertIsInstance(cert, bytes) ++ self.assertIn(enc, {"x509_asn", "pkcs_7_asn"}) ++ self.assertIsInstance(trust, (set, bool)) ++ if isinstance(trust, set): ++ trust_oids.update(trust) ++ ++ serverAuth = "1.3.6.1.5.5.7.3.1" ++ self.assertIn(serverAuth, trust_oids) ++ ++ @unittest.skipUnless(sys.platform == "win32", "Windows specific") ++ def test_enum_crls(self): ++ self.assertTrue(ssl.enum_crls("CA")) ++ self.assertRaises(TypeError, ssl.enum_crls) ++ self.assertRaises(WindowsError, ssl.enum_crls, "") ++ ++ crls = ssl.enum_crls("CA") ++ self.assertIsInstance(crls, list) ++ for element in crls: ++ self.assertIsInstance(element, tuple) ++ self.assertEqual(len(element), 2) ++ self.assertIsInstance(element[0], bytes) ++ self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"}) ++ ++ ++ def test_asn1object(self): ++ expected = (129, 'serverAuth', 'TLS Web Server Authentication', ++ '1.3.6.1.5.5.7.3.1') ++ ++ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') ++ self.assertEqual(val, expected) ++ self.assertEqual(val.nid, 129) ++ self.assertEqual(val.shortname, 'serverAuth') ++ self.assertEqual(val.longname, 'TLS Web Server Authentication') ++ self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1') ++ self.assertIsInstance(val, ssl._ASN1Object) ++ self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth') ++ ++ val = ssl._ASN1Object.fromnid(129) ++ self.assertEqual(val, expected) ++ self.assertIsInstance(val, ssl._ASN1Object) ++ self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1) ++ with self.assertRaisesRegexp(ValueError, "unknown NID 100000"): ++ ssl._ASN1Object.fromnid(100000) ++ for i in range(1000): ++ try: ++ obj = ssl._ASN1Object.fromnid(i) ++ except ValueError: ++ pass ++ else: ++ self.assertIsInstance(obj.nid, int) ++ self.assertIsInstance(obj.shortname, str) ++ self.assertIsInstance(obj.longname, str) ++ self.assertIsInstance(obj.oid, (str, type(None))) ++ ++ val = ssl._ASN1Object.fromname('TLS Web Server Authentication') ++ self.assertEqual(val, expected) ++ self.assertIsInstance(val, ssl._ASN1Object) ++ self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected) ++ self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'), ++ expected) ++ with self.assertRaisesRegexp(ValueError, "unknown object 'serverauth'"): ++ ssl._ASN1Object.fromname('serverauth') ++ ++ def test_purpose_enum(self): ++ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') ++ self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object) ++ self.assertEqual(ssl.Purpose.SERVER_AUTH, val) ++ self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129) ++ self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth') ++ self.assertEqual(ssl.Purpose.SERVER_AUTH.oid, ++ '1.3.6.1.5.5.7.3.1') ++ ++ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2') ++ self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object) ++ self.assertEqual(ssl.Purpose.CLIENT_AUTH, val) ++ self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130) ++ self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth') ++ self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid, ++ '1.3.6.1.5.5.7.3.2') ++ ++ def cert_time_ok(self, timestring, timestamp): ++ self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp) ++ ++ def cert_time_fail(self, timestring): ++ with self.assertRaises(ValueError): ++ ssl.cert_time_to_seconds(timestring) ++ ++ @unittest.skipUnless(utc_offset(), ++ 'local time needs to be different from UTC') ++ def test_cert_time_to_seconds_timezone(self): ++ # Issue #19940: ssl.cert_time_to_seconds() returns wrong ++ # results if local timezone is not UTC ++ self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0) ++ self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0) ++ ++ def test_cert_time_to_seconds(self): ++ timestring = "Jan 5 09:34:43 2018 GMT" ++ ts = 1515144883.0 ++ self.cert_time_ok(timestring, ts) ++ # accept keyword parameter, assert its name ++ self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts) ++ # accept both %e and %d (space or zero generated by strftime) ++ self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts) ++ # case-insensitive ++ self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts) ++ self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds ++ self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT ++ self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone ++ self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day ++ self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month ++ self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour ++ self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute ++ ++ newyear_ts = 1230768000.0 ++ # leap seconds ++ self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts) ++ # same timestamp ++ self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts) ++ ++ self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899) ++ # allow 60th second (even if it is not a leap second) ++ self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900) ++ # allow 2nd leap second for compatibility with time.strptime() ++ self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901) ++ self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds ++ ++ # no special treatement for the special value: ++ # 99991231235959Z (rfc 5280) ++ self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0) ++ ++ @support.run_with_locale('LC_ALL', '') ++ def test_cert_time_to_seconds_locale(self): ++ # `cert_time_to_seconds()` should be locale independent ++ ++ def local_february_name(): ++ return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0)) ++ ++ if local_february_name().lower() == 'feb': ++ self.skipTest("locale-specific month name needs to be " ++ "different from C locale") ++ ++ # locale-independent ++ self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0) ++ self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT") ++ ++ ++class ContextTests(unittest.TestCase): ++ ++ @skip_if_broken_ubuntu_ssl ++ def test_constructor(self): ++ for protocol in PROTOCOLS: ++ ssl.SSLContext(protocol) ++ self.assertRaises(TypeError, ssl.SSLContext) ++ self.assertRaises(ValueError, ssl.SSLContext, -1) ++ self.assertRaises(ValueError, ssl.SSLContext, 42) ++ ++ @skip_if_broken_ubuntu_ssl ++ def test_protocol(self): ++ for proto in PROTOCOLS: ++ ctx = ssl.SSLContext(proto) ++ self.assertEqual(ctx.protocol, proto) ++ ++ def test_ciphers(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.set_ciphers("ALL") ++ ctx.set_ciphers("DEFAULT") ++ with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): ++ ctx.set_ciphers("^$:,;?*'dorothyx") ++ ++ @skip_if_broken_ubuntu_ssl ++ def test_options(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ # OP_ALL | OP_NO_SSLv2 is the default value ++ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ++ ctx.options) ++ ctx.options |= ssl.OP_NO_SSLv3 ++ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, ++ ctx.options) ++ if can_clear_options(): ++ ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 ++ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, ++ ctx.options) ++ ctx.options = 0 ++ self.assertEqual(0, ctx.options) ++ else: ++ with self.assertRaises(ValueError): ++ ctx.options = 0 ++ ++ def test_verify_mode(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ # Default value ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ ctx.verify_mode = ssl.CERT_OPTIONAL ++ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) ++ ctx.verify_mode = ssl.CERT_NONE ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ with self.assertRaises(TypeError): ++ ctx.verify_mode = None ++ with self.assertRaises(ValueError): ++ ctx.verify_mode = 42 ++ ++ @unittest.skipUnless(have_verify_flags(), ++ "verify_flags need OpenSSL > 0.9.8") ++ def test_verify_flags(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ # default value by OpenSSL ++ self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT) ++ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF ++ self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF) ++ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN ++ self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN) ++ ctx.verify_flags = ssl.VERIFY_DEFAULT ++ self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT) ++ # supports any value ++ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT ++ self.assertEqual(ctx.verify_flags, ++ ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT) ++ with self.assertRaises(TypeError): ++ ctx.verify_flags = None ++ ++ def test_load_cert_chain(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ # Combined key and cert in a single file ++ ctx.load_cert_chain(CERTFILE) ++ ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) ++ self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) ++ with self.assertRaises(IOError) as cm: ++ ctx.load_cert_chain(WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_cert_chain(BADCERT) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_cert_chain(EMPTYCERT) ++ # Separate key and cert ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_cert_chain(ONLYCERT, ONLYKEY) ++ ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY) ++ ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_cert_chain(ONLYCERT) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_cert_chain(ONLYKEY) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT) ++ # Mismatching key and cert ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ with self.assertRaisesRegexp(ssl.SSLError, "key values mismatch"): ++ ctx.load_cert_chain(SVN_PYTHON_ORG_ROOT_CERT, ONLYKEY) ++ # Password protected key and cert ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode()) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, ++ password=bytearray(KEY_PASSWORD.encode())) ++ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD) ++ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode()) ++ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, ++ bytearray(KEY_PASSWORD.encode())) ++ with self.assertRaisesRegexp(TypeError, "should be a string"): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=True) ++ with self.assertRaises(ssl.SSLError): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass") ++ with self.assertRaisesRegexp(ValueError, "cannot be longer"): ++ # openssl has a fixed limit on the password buffer. ++ # PEM_BUFSIZE is generally set to 1kb. ++ # Return a string larger than this. ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400) ++ # Password callback ++ def getpass_unicode(): ++ return KEY_PASSWORD ++ def getpass_bytes(): ++ return KEY_PASSWORD.encode() ++ def getpass_bytearray(): ++ return bytearray(KEY_PASSWORD.encode()) ++ def getpass_badpass(): ++ return "badpass" ++ def getpass_huge(): ++ return b'a' * (1024 * 1024) ++ def getpass_bad_type(): ++ return 9 ++ def getpass_exception(): ++ raise Exception('getpass error') ++ class GetPassCallable: ++ def __call__(self): ++ return KEY_PASSWORD ++ def getpass(self): ++ return KEY_PASSWORD ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable()) ++ ctx.load_cert_chain(CERTFILE_PROTECTED, ++ password=GetPassCallable().getpass) ++ with self.assertRaises(ssl.SSLError): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass) ++ with self.assertRaisesRegexp(ValueError, "cannot be longer"): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge) ++ with self.assertRaisesRegexp(TypeError, "must return a string"): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type) ++ with self.assertRaisesRegexp(Exception, "getpass error"): ++ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception) ++ # Make sure the password function isn't called if it isn't needed ++ ctx.load_cert_chain(CERTFILE, password=getpass_exception) ++ ++ def test_load_verify_locations(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_verify_locations(CERTFILE) ++ ctx.load_verify_locations(cafile=CERTFILE, capath=None) ++ ctx.load_verify_locations(BYTES_CERTFILE) ++ ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None) ++ self.assertRaises(TypeError, ctx.load_verify_locations) ++ self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None) ++ with self.assertRaises(IOError) as cm: ++ ctx.load_verify_locations(WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ++ ctx.load_verify_locations(BADCERT) ++ ctx.load_verify_locations(CERTFILE, CAPATH) ++ ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH) ++ ++ # Issue #10989: crash if the second argument type is invalid ++ self.assertRaises(TypeError, ctx.load_verify_locations, None, True) ++ ++ def test_load_verify_cadata(self): ++ # test cadata ++ with open(CAFILE_CACERT) as f: ++ cacert_pem = f.read().decode("ascii") ++ cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem) ++ with open(CAFILE_NEURONIO) as f: ++ neuronio_pem = f.read().decode("ascii") ++ neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem) ++ ++ # test PEM ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0) ++ ctx.load_verify_locations(cadata=cacert_pem) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1) ++ ctx.load_verify_locations(cadata=neuronio_pem) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ # cert already in hash table ++ ctx.load_verify_locations(cadata=neuronio_pem) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ ++ # combined ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ combined = "\n".join((cacert_pem, neuronio_pem)) ++ ctx.load_verify_locations(cadata=combined) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ ++ # with junk around the certs ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ combined = ["head", cacert_pem, "other", neuronio_pem, "again", ++ neuronio_pem, "tail"] ++ ctx.load_verify_locations(cadata="\n".join(combined)) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ ++ # test DER ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_verify_locations(cadata=cacert_der) ++ ctx.load_verify_locations(cadata=neuronio_der) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ # cert already in hash table ++ ctx.load_verify_locations(cadata=cacert_der) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ ++ # combined ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ combined = b"".join((cacert_der, neuronio_der)) ++ ctx.load_verify_locations(cadata=combined) ++ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) ++ ++ # error cases ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object) ++ ++ with self.assertRaisesRegexp(ssl.SSLError, "no start line"): ++ ctx.load_verify_locations(cadata=u"broken") ++ with self.assertRaisesRegexp(ssl.SSLError, "not enough data"): ++ ctx.load_verify_locations(cadata=b"broken") ++ ++ ++ def test_load_dh_params(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_dh_params(DHFILE) ++ if os.name != 'nt': ++ ctx.load_dh_params(BYTES_DHFILE) ++ self.assertRaises(TypeError, ctx.load_dh_params) ++ self.assertRaises(TypeError, ctx.load_dh_params, None) ++ with self.assertRaises(IOError) as cm: ++ ctx.load_dh_params(WRONGCERT) ++ self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaises(ssl.SSLError) as cm: ++ ctx.load_dh_params(CERTFILE) ++ ++ @skip_if_broken_ubuntu_ssl ++ def test_session_stats(self): ++ for proto in PROTOCOLS: ++ ctx = ssl.SSLContext(proto) ++ self.assertEqual(ctx.session_stats(), { ++ 'number': 0, ++ 'connect': 0, ++ 'connect_good': 0, ++ 'connect_renegotiate': 0, ++ 'accept': 0, ++ 'accept_good': 0, ++ 'accept_renegotiate': 0, ++ 'hits': 0, ++ 'misses': 0, ++ 'timeouts': 0, ++ 'cache_full': 0, ++ }) ++ ++ def test_set_default_verify_paths(self): ++ # There's not much we can do to test that it acts as expected, ++ # so just check it doesn't crash or raise an exception. ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.set_default_verify_paths() ++ ++ @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build") ++ def test_set_ecdh_curve(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.set_ecdh_curve("prime256v1") ++ ctx.set_ecdh_curve(b"prime256v1") ++ self.assertRaises(TypeError, ctx.set_ecdh_curve) ++ self.assertRaises(TypeError, ctx.set_ecdh_curve, None) ++ self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo") ++ self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo") ++ ++ @needs_sni ++ def test_sni_callback(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ++ # set_servername_callback expects a callable, or None ++ self.assertRaises(TypeError, ctx.set_servername_callback) ++ self.assertRaises(TypeError, ctx.set_servername_callback, 4) ++ self.assertRaises(TypeError, ctx.set_servername_callback, "") ++ self.assertRaises(TypeError, ctx.set_servername_callback, ctx) ++ ++ def dummycallback(sock, servername, ctx): ++ pass ++ ctx.set_servername_callback(None) ++ ctx.set_servername_callback(dummycallback) ++ ++ @needs_sni ++ def test_sni_callback_refcycle(self): ++ # Reference cycles through the servername callback are detected ++ # and cleared. ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ def dummycallback(sock, servername, ctx, cycle=ctx): ++ pass ++ ctx.set_servername_callback(dummycallback) ++ wr = weakref.ref(ctx) ++ del ctx, dummycallback ++ gc.collect() ++ self.assertIs(wr(), None) ++ ++ def test_cert_store_stats(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.cert_store_stats(), ++ {'x509_ca': 0, 'crl': 0, 'x509': 0}) ++ ctx.load_cert_chain(CERTFILE) ++ self.assertEqual(ctx.cert_store_stats(), ++ {'x509_ca': 0, 'crl': 0, 'x509': 0}) ++ ctx.load_verify_locations(CERTFILE) ++ self.assertEqual(ctx.cert_store_stats(), ++ {'x509_ca': 0, 'crl': 0, 'x509': 1}) ++ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) ++ self.assertEqual(ctx.cert_store_stats(), ++ {'x509_ca': 1, 'crl': 0, 'x509': 2}) ++ ++ def test_get_ca_certs(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.get_ca_certs(), []) ++ # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE ++ ctx.load_verify_locations(CERTFILE) ++ self.assertEqual(ctx.get_ca_certs(), []) ++ # but SVN_PYTHON_ORG_ROOT_CERT is a CA cert ++ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) ++ self.assertEqual(ctx.get_ca_certs(), ++ [{'issuer': ((('organizationName', 'Root CA'),), ++ (('organizationalUnitName', 'http://www.cacert.org'),), ++ (('commonName', 'CA Cert Signing Authority'),), ++ (('emailAddress', 'support@cacert.org'),)), ++ 'notAfter': asn1time('Mar 29 12:29:49 2033 GMT'), ++ 'notBefore': asn1time('Mar 30 12:29:49 2003 GMT'), ++ 'serialNumber': '00', ++ 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',), ++ 'subject': ((('organizationName', 'Root CA'),), ++ (('organizationalUnitName', 'http://www.cacert.org'),), ++ (('commonName', 'CA Cert Signing Authority'),), ++ (('emailAddress', 'support@cacert.org'),)), ++ 'version': 3}]) ++ ++ with open(SVN_PYTHON_ORG_ROOT_CERT) as f: ++ pem = f.read() ++ der = ssl.PEM_cert_to_DER_cert(pem) ++ self.assertEqual(ctx.get_ca_certs(True), [der]) + ++ def test_load_default_certs(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_default_certs() ++ ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_default_certs(ssl.Purpose.SERVER_AUTH) ++ ctx.load_default_certs() ++ ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH) ++ ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertRaises(TypeError, ctx.load_default_certs, None) ++ self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH') ++ ++ def test_create_default_context(self): ++ ctx = ssl.create_default_context() ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) ++ self.assertTrue(ctx.check_hostname) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ self.assertEqual( ++ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), ++ getattr(ssl, "OP_NO_COMPRESSION", 0), ++ ) ++ ++ with open(SIGNING_CA) as f: ++ cadata = f.read().decode("ascii") ++ ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH, ++ cadata=cadata) ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ self.assertEqual( ++ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), ++ getattr(ssl, "OP_NO_COMPRESSION", 0), ++ ) ++ ++ ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ self.assertEqual( ++ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), ++ getattr(ssl, "OP_NO_COMPRESSION", 0), ++ ) ++ self.assertEqual( ++ ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0), ++ getattr(ssl, "OP_SINGLE_DH_USE", 0), ++ ) ++ self.assertEqual( ++ ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0), ++ getattr(ssl, "OP_SINGLE_ECDH_USE", 0), ++ ) ++ ++ def test__create_stdlib_context(self): ++ ctx = ssl._create_stdlib_context() ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ self.assertFalse(ctx.check_hostname) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ ++ ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ ++ ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, ++ cert_reqs=ssl.CERT_REQUIRED, ++ check_hostname=True) ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) ++ self.assertTrue(ctx.check_hostname) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ ++ ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) ++ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) ++ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) ++ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) ++ ++ def test_check_hostname(self): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ self.assertFalse(ctx.check_hostname) ++ ++ # Requires CERT_REQUIRED or CERT_OPTIONAL ++ with self.assertRaises(ValueError): ++ ctx.check_hostname = True ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ self.assertFalse(ctx.check_hostname) ++ ctx.check_hostname = True ++ self.assertTrue(ctx.check_hostname) ++ ++ ctx.verify_mode = ssl.CERT_OPTIONAL ++ ctx.check_hostname = True ++ self.assertTrue(ctx.check_hostname) ++ ++ # Cannot set CERT_NONE with check_hostname enabled ++ with self.assertRaises(ValueError): ++ ctx.verify_mode = ssl.CERT_NONE ++ ctx.check_hostname = False ++ self.assertFalse(ctx.check_hostname) ++ ++ ++class SSLErrorTests(unittest.TestCase): ++ ++ def test_str(self): ++ # The str() of a SSLError doesn't include the errno ++ e = ssl.SSLError(1, "foo") ++ self.assertEqual(str(e), "foo") ++ self.assertEqual(e.errno, 1) ++ # Same for a subclass ++ e = ssl.SSLZeroReturnError(1, "foo") ++ self.assertEqual(str(e), "foo") ++ self.assertEqual(e.errno, 1) ++ ++ def test_lib_reason(self): ++ # Test the library and reason attributes ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ with self.assertRaises(ssl.SSLError) as cm: ++ ctx.load_dh_params(CERTFILE) ++ self.assertEqual(cm.exception.library, 'PEM') ++ self.assertEqual(cm.exception.reason, 'NO_START_LINE') ++ s = str(cm.exception) ++ self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s) ++ ++ def test_subclass(self): ++ # Check that the appropriate SSLError subclass is raised ++ # (this only tests one of them) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ with closing(socket.socket()) as s: ++ s.bind(("127.0.0.1", 0)) ++ s.listen(5) ++ c = socket.socket() ++ c.connect(s.getsockname()) ++ c.setblocking(False) ++ with closing(ctx.wrap_socket(c, False, do_handshake_on_connect=False)) as c: ++ with self.assertRaises(ssl.SSLWantReadError) as cm: ++ c.do_handshake() ++ s = str(cm.exception) ++ self.assertTrue(s.startswith("The operation did not complete (read)"), s) ++ # For compatibility ++ self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ) ++ ++ ++ + + class NetworkedTests(unittest.TestCase): + + def test_connect(self): +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_NONE) +- s.connect(("svn.python.org", 443)) +- c = s.getpeercert() +- if c: +- self.fail("Peer cert %s shouldn't be here!") +- s.close() +- +- # this should fail because we have no verification certs +- s = ssl.wrap_socket(socket.socket(socket.AF_INET), +- cert_reqs=ssl.CERT_REQUIRED) + try: + s.connect(("svn.python.org", 443)) +- except ssl.SSLError: +- pass ++ self.assertEqual({}, s.getpeercert()) + finally: + s.close() + ++ # this should fail because we have no verification certs ++ s = ssl.wrap_socket(socket.socket(socket.AF_INET), ++ cert_reqs=ssl.CERT_REQUIRED) ++ self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", ++ s.connect, ("svn.python.org", 443)) ++ s.close() ++ + # this should succeed because we specify the root cert + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT) + try: + s.connect(("svn.python.org", 443)) ++ self.assertTrue(s.getpeercert()) + finally: + s.close() + + def test_connect_ex(self): + # Issue #11326: check connect_ex() implementation +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT) +@@ -272,7 +1206,7 @@ class NetworkedTests(unittest.TestCase): + def test_non_blocking_connect_ex(self): + # Issue #11326: non-blocking connect_ex() should allow handshake + # to proceed after the socket gets ready. +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT, +@@ -289,13 +1223,10 @@ class NetworkedTests(unittest.TestCase): + try: + s.do_handshake() + break +- except ssl.SSLError as err: +- if err.args[0] == ssl.SSL_ERROR_WANT_READ: +- select.select([s], [], [], 5.0) +- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: +- select.select([], [s], [], 5.0) +- else: +- raise ++ except ssl.SSLWantReadError: ++ select.select([s], [], [], 5.0) ++ except ssl.SSLWantWriteError: ++ select.select([], [s], [], 5.0) + # SSL established + self.assertTrue(s.getpeercert()) + finally: +@@ -304,7 +1235,7 @@ class NetworkedTests(unittest.TestCase): + def test_timeout_connect_ex(self): + # Issue #12065: on a timeout, connect_ex() should return the original + # errno (mimicking the behaviour of non-SSL sockets). +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT, +@@ -319,22 +1250,109 @@ class NetworkedTests(unittest.TestCase): + s.close() + + def test_connect_ex_error(self): +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT) + try: +- self.assertEqual(errno.ECONNREFUSED, +- s.connect_ex(("svn.python.org", 444))) ++ rc = s.connect_ex(("svn.python.org", 444)) ++ # Issue #19919: Windows machines or VMs hosted on Windows ++ # machines sometimes return EWOULDBLOCK. ++ self.assertIn(rc, (errno.ECONNREFUSED, errno.EWOULDBLOCK)) ++ finally: ++ s.close() ++ ++ def test_connect_with_context(self): ++ with support.transient_internet("svn.python.org"): ++ # Same as test_connect, but with a separately created context ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ s.connect(("svn.python.org", 443)) ++ try: ++ self.assertEqual({}, s.getpeercert()) + finally: + s.close() ++ # Same with a server hostname ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET), ++ server_hostname="svn.python.org") ++ if ssl.HAS_SNI: ++ s.connect(("svn.python.org", 443)) ++ s.close() ++ else: ++ self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) ++ # This should fail because we have no verification certs ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", ++ s.connect, ("svn.python.org", 443)) ++ s.close() ++ # This should succeed because we specify the root cert ++ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ s.connect(("svn.python.org", 443)) ++ try: ++ cert = s.getpeercert() ++ self.assertTrue(cert) ++ finally: ++ s.close() ++ ++ def test_connect_capath(self): ++ # Verify server certificates using the `capath` argument ++ # NOTE: the subject hashing algorithm has been changed between ++ # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must ++ # contain both versions of each certificate (same content, different ++ # filename) for this test to be portable across OpenSSL releases. ++ with support.transient_internet("svn.python.org"): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(capath=CAPATH) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ s.connect(("svn.python.org", 443)) ++ try: ++ cert = s.getpeercert() ++ self.assertTrue(cert) ++ finally: ++ s.close() ++ # Same with a bytes `capath` argument ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(capath=BYTES_CAPATH) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ s.connect(("svn.python.org", 443)) ++ try: ++ cert = s.getpeercert() ++ self.assertTrue(cert) ++ finally: ++ s.close() ++ ++ def test_connect_cadata(self): ++ with open(CAFILE_CACERT) as f: ++ pem = f.read().decode('ascii') ++ der = ssl.PEM_cert_to_DER_cert(pem) ++ with support.transient_internet("svn.python.org"): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(cadata=pem) ++ with closing(ctx.wrap_socket(socket.socket(socket.AF_INET))) as s: ++ s.connect(("svn.python.org", 443)) ++ cert = s.getpeercert() ++ self.assertTrue(cert) ++ ++ # same with DER ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(cadata=der) ++ with closing(ctx.wrap_socket(socket.socket(socket.AF_INET))) as s: ++ s.connect(("svn.python.org", 443)) ++ cert = s.getpeercert() ++ self.assertTrue(cert) + + @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows") + def test_makefile_close(self): + # Issue #5238: creating a file-like object with makefile() shouldn't + # delay closing the underlying "real socket" (here tested with its + # file descriptor, hence skipping the test under Windows). +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + ss = ssl.wrap_socket(socket.socket(socket.AF_INET)) + ss.connect(("svn.python.org", 443)) + fd = ss.fileno() +@@ -350,7 +1368,7 @@ class NetworkedTests(unittest.TestCase): + self.assertEqual(e.exception.errno, errno.EBADF) + + def test_non_blocking_handshake(self): +- with test_support.transient_internet("svn.python.org"): ++ with support.transient_internet("svn.python.org"): + s = socket.socket(socket.AF_INET) + s.connect(("svn.python.org", 443)) + s.setblocking(False) +@@ -363,36 +1381,57 @@ class NetworkedTests(unittest.TestCase): + count += 1 + s.do_handshake() + break +- except ssl.SSLError, err: +- if err.args[0] == ssl.SSL_ERROR_WANT_READ: +- select.select([s], [], []) +- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: +- select.select([], [s], []) +- else: +- raise ++ except ssl.SSLWantReadError: ++ select.select([s], [], []) ++ except ssl.SSLWantWriteError: ++ select.select([], [s], []) + s.close() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count) + + def test_get_server_certificate(self): +- with test_support.transient_internet("svn.python.org"): +- pem = ssl.get_server_certificate(("svn.python.org", 443)) +- if not pem: +- self.fail("No server certificate on svn.python.org:443!") ++ def _test_get_server_certificate(host, port, cert=None): ++ with support.transient_internet(host): ++ pem = ssl.get_server_certificate((host, port)) ++ if not pem: ++ self.fail("No server certificate on %s:%s!" % (host, port)) + +- try: +- pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE) +- except ssl.SSLError: +- #should fail +- pass +- else: +- self.fail("Got server certificate %s for svn.python.org!" % pem) ++ try: ++ pem = ssl.get_server_certificate((host, port), ++ ca_certs=CERTFILE) ++ except ssl.SSLError as x: ++ #should fail ++ if support.verbose: ++ sys.stdout.write("%s\n" % x) ++ else: ++ self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) ++ pem = ssl.get_server_certificate((host, port), ++ ca_certs=cert) ++ if not pem: ++ self.fail("No server certificate on %s:%s!" % (host, port)) ++ if support.verbose: ++ sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) ++ ++ _test_get_server_certificate('svn.python.org', 443, SVN_PYTHON_ORG_ROOT_CERT) ++ if support.IPV6_ENABLED: ++ _test_get_server_certificate('ipv6.google.com', 443) ++ ++ def test_ciphers(self): ++ remote = ("svn.python.org", 443) ++ with support.transient_internet(remote[0]): ++ with closing(ssl.wrap_socket(socket.socket(socket.AF_INET), ++ cert_reqs=ssl.CERT_NONE, ciphers="ALL")) as s: ++ s.connect(remote) ++ with closing(ssl.wrap_socket(socket.socket(socket.AF_INET), ++ cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")) as s: ++ s.connect(remote) ++ # Error checking can happen at instantiation or when connecting ++ with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): ++ with closing(socket.socket(socket.AF_INET)) as sock: ++ s = ssl.wrap_socket(sock, ++ cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") ++ s.connect(remote) + +- pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT) +- if not pem: +- self.fail("No server certificate on svn.python.org:443!") +- if test_support.verbose: +- sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem) + + def test_algorithms(self): + # Issue #8484: all algorithms should be available when verifying a +@@ -400,17 +1439,21 @@ class NetworkedTests(unittest.TestCase): + # SHA256 was added in OpenSSL 0.9.8 + if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): + self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) +- self.skipTest("remote host needs SNI, only available on Python 3.2+") +- # NOTE: https://sha2.hboeck.de is another possible test host ++ # sha256.tbs-internet.com needs SNI to use the correct certificate ++ if not ssl.HAS_SNI: ++ self.skipTest("SNI needed for this test") ++ # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) + remote = ("sha256.tbs-internet.com", 443) + sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") +- with test_support.transient_internet("sha256.tbs-internet.com"): +- s = ssl.wrap_socket(socket.socket(socket.AF_INET), +- cert_reqs=ssl.CERT_REQUIRED, +- ca_certs=sha256_cert,) ++ with support.transient_internet("sha256.tbs-internet.com"): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(sha256_cert) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET), ++ server_hostname="sha256.tbs-internet.com") + try: + s.connect(remote) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\nCipher with %r is %r\n" % + (remote, s.cipher())) + sys.stdout.write("Certificate is:\n%s\n" % +@@ -418,6 +1461,36 @@ class NetworkedTests(unittest.TestCase): + finally: + s.close() + ++ def test_get_ca_certs_capath(self): ++ # capath certs are loaded on request ++ with support.transient_internet("svn.python.org"): ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx.verify_mode = ssl.CERT_REQUIRED ++ ctx.load_verify_locations(capath=CAPATH) ++ self.assertEqual(ctx.get_ca_certs(), []) ++ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) ++ s.connect(("svn.python.org", 443)) ++ try: ++ cert = s.getpeercert() ++ self.assertTrue(cert) ++ finally: ++ s.close() ++ self.assertEqual(len(ctx.get_ca_certs()), 1) ++ ++ @needs_sni ++ def test_context_setget(self): ++ # Check that the context of a connected socket can be replaced. ++ with support.transient_internet("svn.python.org"): ++ ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ s = socket.socket(socket.AF_INET) ++ with closing(ctx1.wrap_socket(s)) as ss: ++ ss.connect(("svn.python.org", 443)) ++ self.assertIs(ss.context, ctx1) ++ self.assertIs(ss._sslobj.context, ctx1) ++ ss.context = ctx2 ++ self.assertIs(ss.context, ctx2) ++ self.assertIs(ss._sslobj.context, ctx2) + + try: + import threading +@@ -426,6 +1499,8 @@ except ImportError: + else: + _have_threads = True + ++ from test.ssl_servers import make_https_server ++ + class ThreadedEchoServer(threading.Thread): + + class ConnectionHandler(threading.Thread): +@@ -434,48 +1509,51 @@ else: + with and without the SSL wrapper around the socket connection, so + that we can test the STARTTLS functionality.""" + +- def __init__(self, server, connsock): ++ def __init__(self, server, connsock, addr): + self.server = server + self.running = False + self.sock = connsock ++ self.addr = addr + self.sock.setblocking(1) + self.sslconn = None + threading.Thread.__init__(self) + self.daemon = True + +- def show_conn_details(self): +- if self.server.certreqs == ssl.CERT_REQUIRED: +- cert = self.sslconn.getpeercert() +- if test_support.verbose and self.server.chatty: +- sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n") +- cert_binary = self.sslconn.getpeercert(True) +- if test_support.verbose and self.server.chatty: +- sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n") +- cipher = self.sslconn.cipher() +- if test_support.verbose and self.server.chatty: +- sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n") +- + def wrap_conn(self): + try: +- self.sslconn = ssl.wrap_socket(self.sock, server_side=True, +- certfile=self.server.certificate, +- ssl_version=self.server.protocol, +- ca_certs=self.server.cacerts, +- cert_reqs=self.server.certreqs, +- ciphers=self.server.ciphers) +- except ssl.SSLError as e: ++ self.sslconn = self.server.context.wrap_socket( ++ self.sock, server_side=True) ++ self.server.selected_protocols.append(self.sslconn.selected_npn_protocol()) ++ except socket.error as e: ++ # We treat ConnectionResetError as though it were an ++ # SSLError - OpenSSL on Ubuntu abruptly closes the ++ # connection when asked to use an unsupported protocol. ++ # + # XXX Various errors can have happened here, for example + # a mismatching protocol version, an invalid certificate, + # or a low-level bug. This should be made more discriminating. ++ if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET: ++ raise + self.server.conn_errors.append(e) + if self.server.chatty: +- handle_error("\n server: bad connection attempt from " + +- str(self.sock.getpeername()) + ":\n") +- self.close() ++ handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") + self.running = False + self.server.stop() ++ self.close() + return False + else: ++ if self.server.context.verify_mode == ssl.CERT_REQUIRED: ++ cert = self.sslconn.getpeercert() ++ if support.verbose and self.server.chatty: ++ sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n") ++ cert_binary = self.sslconn.getpeercert(True) ++ if support.verbose and self.server.chatty: ++ sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n") ++ cipher = self.sslconn.cipher() ++ if support.verbose and self.server.chatty: ++ sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n") ++ sys.stdout.write(" server: selected protocol is now " ++ + str(self.sslconn.selected_npn_protocol()) + "\n") + return True + + def read(self): +@@ -494,48 +1572,53 @@ else: + if self.sslconn: + self.sslconn.close() + else: +- self.sock._sock.close() ++ self.sock.close() + + def run(self): + self.running = True + if not self.server.starttls_server: +- if isinstance(self.sock, ssl.SSLSocket): +- self.sslconn = self.sock +- elif not self.wrap_conn(): ++ if not self.wrap_conn(): + return +- self.show_conn_details() + while self.running: + try: + msg = self.read() +- if not msg: ++ stripped = msg.strip() ++ if not stripped: + # eof, so quit this handler + self.running = False + self.close() +- elif msg.strip() == 'over': +- if test_support.verbose and self.server.connectionchatty: ++ elif stripped == b'over': ++ if support.verbose and self.server.connectionchatty: + sys.stdout.write(" server: client closed connection\n") + self.close() + return +- elif self.server.starttls_server and msg.strip() == 'STARTTLS': +- if test_support.verbose and self.server.connectionchatty: ++ elif (self.server.starttls_server and ++ stripped == b'STARTTLS'): ++ if support.verbose and self.server.connectionchatty: + sys.stdout.write(" server: read STARTTLS from client, sending OK...\n") +- self.write("OK\n") ++ self.write(b"OK\n") + if not self.wrap_conn(): + return +- elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS': +- if test_support.verbose and self.server.connectionchatty: ++ elif (self.server.starttls_server and self.sslconn ++ and stripped == b'ENDTLS'): ++ if support.verbose and self.server.connectionchatty: + sys.stdout.write(" server: read ENDTLS from client, sending OK...\n") +- self.write("OK\n") +- self.sslconn.unwrap() ++ self.write(b"OK\n") ++ self.sock = self.sslconn.unwrap() + self.sslconn = None +- if test_support.verbose and self.server.connectionchatty: ++ if support.verbose and self.server.connectionchatty: + sys.stdout.write(" server: connection is now unencrypted...\n") ++ elif stripped == b'CB tls-unique': ++ if support.verbose and self.server.connectionchatty: ++ sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n") ++ data = self.sslconn.get_channel_binding("tls-unique") ++ self.write(repr(data).encode("us-ascii") + b"\n") + else: +- if (test_support.verbose and ++ if (support.verbose and + self.server.connectionchatty): + ctype = (self.sslconn and "encrypted") or "unencrypted" +- sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n" +- % (repr(msg), ctype, repr(msg.lower()), ctype)) ++ sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n" ++ % (msg, ctype, msg.lower(), ctype)) + self.write(msg.lower()) + except ssl.SSLError: + if self.server.chatty: +@@ -546,36 +1629,34 @@ else: + # harness, we want to stop the server + self.server.stop() + +- def __init__(self, certificate, ssl_version=None, ++ def __init__(self, certificate=None, ssl_version=None, + certreqs=None, cacerts=None, + chatty=True, connectionchatty=False, starttls_server=False, +- wrap_accepting_socket=False, ciphers=None): +- +- if ssl_version is None: +- ssl_version = ssl.PROTOCOL_TLSv1 +- if certreqs is None: +- certreqs = ssl.CERT_NONE +- self.certificate = certificate +- self.protocol = ssl_version +- self.certreqs = certreqs +- self.cacerts = cacerts +- self.ciphers = ciphers ++ npn_protocols=None, ciphers=None, context=None): ++ if context: ++ self.context = context ++ else: ++ self.context = ssl.SSLContext(ssl_version ++ if ssl_version is not None ++ else ssl.PROTOCOL_TLSv1) ++ self.context.verify_mode = (certreqs if certreqs is not None ++ else ssl.CERT_NONE) ++ if cacerts: ++ self.context.load_verify_locations(cacerts) ++ if certificate: ++ self.context.load_cert_chain(certificate) ++ if npn_protocols: ++ self.context.set_npn_protocols(npn_protocols) ++ if ciphers: ++ self.context.set_ciphers(ciphers) + self.chatty = chatty + self.connectionchatty = connectionchatty + self.starttls_server = starttls_server + self.sock = socket.socket() ++ self.port = support.bind_port(self.sock) + self.flag = None +- if wrap_accepting_socket: +- self.sock = ssl.wrap_socket(self.sock, server_side=True, +- certfile=self.certificate, +- cert_reqs = self.certreqs, +- ca_certs = self.cacerts, +- ssl_version = self.protocol, +- ciphers = self.ciphers) +- if test_support.verbose and self.chatty: +- sys.stdout.write(' server: wrapped server socket as %s\n' % str(self.sock)) +- self.port = test_support.bind_port(self.sock) + self.active = False ++ self.selected_protocols = [] + self.conn_errors = [] + threading.Thread.__init__(self) + self.daemon = True +@@ -603,10 +1684,10 @@ else: + while self.active: + try: + newconn, connaddr = self.sock.accept() +- if test_support.verbose and self.chatty: ++ if support.verbose and self.chatty: + sys.stdout.write(' server: new connection from ' +- + str(connaddr) + '\n') +- handler = self.ConnectionHandler(self, newconn) ++ + repr(connaddr) + '\n') ++ handler = self.ConnectionHandler(self, newconn, connaddr) + handler.start() + handler.join() + except socket.timeout: +@@ -625,11 +1706,12 @@ else: + class ConnectionHandler(asyncore.dispatcher_with_send): + + def __init__(self, conn, certfile): +- asyncore.dispatcher_with_send.__init__(self, conn) + self.socket = ssl.wrap_socket(conn, server_side=True, + certfile=certfile, + do_handshake_on_connect=False) ++ asyncore.dispatcher_with_send.__init__(self, self.socket) + self._ssl_accepting = True ++ self._do_ssl_handshake() + + def readable(self): + if isinstance(self.socket, ssl.SSLSocket): +@@ -640,12 +1722,11 @@ else: + def _do_ssl_handshake(self): + try: + self.socket.do_handshake() +- except ssl.SSLError, err: +- if err.args[0] in (ssl.SSL_ERROR_WANT_READ, +- ssl.SSL_ERROR_WANT_WRITE): +- return +- elif err.args[0] == ssl.SSL_ERROR_EOF: +- return self.handle_close() ++ except (ssl.SSLWantReadError, ssl.SSLWantWriteError): ++ return ++ except ssl.SSLEOFError: ++ return self.handle_close() ++ except ssl.SSLError: + raise + except socket.error, err: + if err.args[0] == errno.ECONNABORTED: +@@ -658,12 +1739,16 @@ else: + self._do_ssl_handshake() + else: + data = self.recv(1024) +- if data and data.strip() != 'over': ++ if support.verbose: ++ sys.stdout.write(" server: read %s from client\n" % repr(data)) ++ if not data: ++ self.close() ++ else: + self.send(data.lower()) + + def handle_close(self): + self.close() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(" server: closed connection %s\n" % self.socket) + + def handle_error(self): +@@ -671,14 +1756,14 @@ else: + + def __init__(self, certfile): + self.certfile = certfile +- asyncore.dispatcher.__init__(self) +- self.create_socket(socket.AF_INET, socket.SOCK_STREAM) +- self.port = test_support.bind_port(self.socket) ++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ self.port = support.bind_port(sock, '') ++ asyncore.dispatcher.__init__(self, sock) + self.listen(5) + + def handle_accept(self): + sock_obj, addr = self.accept() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(" server: new connection from %s:%s\n" %addr) + self.ConnectionHandler(sock_obj, self.certfile) + +@@ -702,13 +1787,13 @@ else: + return self + + def __exit__(self, *args): +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(" cleanup: stopping server.\n") + self.stop() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(" cleanup: joining server thread.\n") + self.join() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(" cleanup: successfully joined.\n") + + def start(self, flag=None): +@@ -720,103 +1805,15 @@ else: + if self.flag: + self.flag.set() + while self.active: +- asyncore.loop(0.05) ++ try: ++ asyncore.loop(1) ++ except: ++ pass + + def stop(self): + self.active = False + self.server.close() + +- class SocketServerHTTPSServer(threading.Thread): +- +- class HTTPSServer(HTTPServer): +- +- def __init__(self, server_address, RequestHandlerClass, certfile): +- HTTPServer.__init__(self, server_address, RequestHandlerClass) +- # we assume the certfile contains both private key and certificate +- self.certfile = certfile +- self.allow_reuse_address = True +- +- def __str__(self): +- return ('<%s %s:%s>' % +- (self.__class__.__name__, +- self.server_name, +- self.server_port)) +- +- def get_request(self): +- # override this to wrap socket with SSL +- sock, addr = self.socket.accept() +- sslconn = ssl.wrap_socket(sock, server_side=True, +- certfile=self.certfile) +- return sslconn, addr +- +- class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): +- # need to override translate_path to get a known root, +- # instead of using os.curdir, since the test could be +- # run from anywhere +- +- server_version = "TestHTTPS/1.0" +- +- root = None +- +- def translate_path(self, path): +- """Translate a /-separated PATH to the local filename syntax. +- +- Components that mean special things to the local file system +- (e.g. drive or directory names) are ignored. (XXX They should +- probably be diagnosed.) +- +- """ +- # abandon query parameters +- path = urlparse.urlparse(path)[2] +- path = os.path.normpath(urllib.unquote(path)) +- words = path.split('/') +- words = filter(None, words) +- path = self.root +- for word in words: +- drive, word = os.path.splitdrive(word) +- head, word = os.path.split(word) +- if word in self.root: continue +- path = os.path.join(path, word) +- return path +- +- def log_message(self, format, *args): +- +- # we override this to suppress logging unless "verbose" +- +- if test_support.verbose: +- sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" % +- (self.server.server_address, +- self.server.server_port, +- self.request.cipher(), +- self.log_date_time_string(), +- format%args)) +- +- +- def __init__(self, certfile): +- self.flag = None +- self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0] +- self.server = self.HTTPSServer( +- (HOST, 0), self.RootedHTTPRequestHandler, certfile) +- self.port = self.server.server_port +- threading.Thread.__init__(self) +- self.daemon = True +- +- def __str__(self): +- return "<%s %s>" % (self.__class__.__name__, self.server) +- +- def start(self, flag=None): +- self.flag = flag +- threading.Thread.start(self) +- +- def run(self): +- if self.flag: +- self.flag.set() +- self.server.serve_forever(0.05) +- +- def stop(self): +- self.server.shutdown() +- +- + def bad_cert_test(certfile): + """ + Launch a server with CERT_REQUIRED, and check that trying to +@@ -824,74 +1821,74 @@ else: + """ + server = ThreadedEchoServer(CERTFILE, + certreqs=ssl.CERT_REQUIRED, +- cacerts=CERTFILE, chatty=False) ++ cacerts=CERTFILE, chatty=False, ++ connectionchatty=False) + with server: + try: +- s = ssl.wrap_socket(socket.socket(), +- certfile=certfile, +- ssl_version=ssl.PROTOCOL_TLSv1) +- s.connect((HOST, server.port)) +- except ssl.SSLError, x: +- if test_support.verbose: +- sys.stdout.write("\nSSLError is %s\n" % x[1]) +- except socket.error, x: +- if test_support.verbose: +- sys.stdout.write("\nsocket.error is %s\n" % x[1]) ++ with closing(socket.socket()) as sock: ++ s = ssl.wrap_socket(sock, ++ certfile=certfile, ++ ssl_version=ssl.PROTOCOL_TLSv1) ++ s.connect((HOST, server.port)) ++ except ssl.SSLError as x: ++ if support.verbose: ++ sys.stdout.write("\nSSLError is %s\n" % x.args[1]) ++ except OSError as x: ++ if support.verbose: ++ sys.stdout.write("\nOSError is %s\n" % x.args[1]) ++ except OSError as x: ++ if x.errno != errno.ENOENT: ++ raise ++ if support.verbose: ++ sys.stdout.write("\OSError is %s\n" % str(x)) + else: + raise AssertionError("Use of invalid cert should have failed!") + +- def server_params_test(certfile, protocol, certreqs, cacertsfile, +- client_certfile, client_protocol=None, indata="FOO\n", +- ciphers=None, chatty=True, connectionchatty=False, +- wrap_accepting_socket=False): ++ def server_params_test(client_context, server_context, indata=b"FOO\n", ++ chatty=True, connectionchatty=False, sni_name=None): + """ + Launch a server, connect a client to it and try various reads + and writes. + """ +- server = ThreadedEchoServer(certfile, +- certreqs=certreqs, +- ssl_version=protocol, +- cacerts=cacertsfile, +- ciphers=ciphers, ++ stats = {} ++ server = ThreadedEchoServer(context=server_context, + chatty=chatty, +- connectionchatty=connectionchatty, +- wrap_accepting_socket=wrap_accepting_socket) ++ connectionchatty=False) + with server: +- # try to connect +- if client_protocol is None: +- client_protocol = protocol +- s = ssl.wrap_socket(socket.socket(), +- certfile=client_certfile, +- ca_certs=cacertsfile, +- ciphers=ciphers, +- cert_reqs=certreqs, +- ssl_version=client_protocol) +- s.connect((HOST, server.port)) +- for arg in [indata, bytearray(indata), memoryview(indata)]: +- if connectionchatty: +- if test_support.verbose: +- sys.stdout.write( +- " client: sending %s...\n" % (repr(arg))) +- s.write(arg) +- outdata = s.read() ++ with closing(client_context.wrap_socket(socket.socket(), ++ server_hostname=sni_name)) as s: ++ s.connect((HOST, server.port)) ++ for arg in [indata, bytearray(indata), memoryview(indata)]: ++ if connectionchatty: ++ if support.verbose: ++ sys.stdout.write( ++ " client: sending %r...\n" % indata) ++ s.write(arg) ++ outdata = s.read() ++ if connectionchatty: ++ if support.verbose: ++ sys.stdout.write(" client: read %r\n" % outdata) ++ if outdata != indata.lower(): ++ raise AssertionError( ++ "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n" ++ % (outdata[:20], len(outdata), ++ indata[:20].lower(), len(indata))) ++ s.write(b"over\n") + if connectionchatty: +- if test_support.verbose: +- sys.stdout.write(" client: read %s\n" % repr(outdata)) +- if outdata != indata.lower(): +- raise AssertionError( +- "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n" +- % (outdata[:min(len(outdata),20)], len(outdata), +- indata[:min(len(indata),20)].lower(), len(indata))) +- s.write("over\n") +- if connectionchatty: +- if test_support.verbose: +- sys.stdout.write(" client: closing connection.\n") +- s.close() ++ if support.verbose: ++ sys.stdout.write(" client: closing connection.\n") ++ stats.update({ ++ 'compression': s.compression(), ++ 'cipher': s.cipher(), ++ 'peercert': s.getpeercert(), ++ 'client_npn_protocol': s.selected_npn_protocol() ++ }) ++ s.close() ++ stats['server_npn_protocols'] = server.selected_protocols ++ return stats + +- def try_protocol_combo(server_protocol, +- client_protocol, +- expect_success, +- certsreqs=None): ++ def try_protocol_combo(server_protocol, client_protocol, expect_success, ++ certsreqs=None, server_options=0, client_options=0): + if certsreqs is None: + certsreqs = ssl.CERT_NONE + certtype = { +@@ -899,19 +1896,30 @@ else: + ssl.CERT_OPTIONAL: "CERT_OPTIONAL", + ssl.CERT_REQUIRED: "CERT_REQUIRED", + }[certsreqs] +- if test_support.verbose: ++ if support.verbose: + formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n" + sys.stdout.write(formatstr % + (ssl.get_protocol_name(client_protocol), + ssl.get_protocol_name(server_protocol), + certtype)) ++ client_context = ssl.SSLContext(client_protocol) ++ client_context.options |= client_options ++ server_context = ssl.SSLContext(server_protocol) ++ server_context.options |= server_options ++ ++ # NOTE: we must enable "ALL" ciphers on the client, otherwise an ++ # SSLv23 client will send an SSLv3 hello (rather than SSLv2) ++ # starting from OpenSSL 1.0.0 (see issue #8322). ++ if client_context.protocol == ssl.PROTOCOL_SSLv23: ++ client_context.set_ciphers("ALL") ++ ++ for ctx in (client_context, server_context): ++ ctx.verify_mode = certsreqs ++ ctx.load_cert_chain(CERTFILE) ++ ctx.load_verify_locations(CERTFILE) + try: +- # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client +- # will send an SSLv3 hello (rather than SSLv2) starting from +- # OpenSSL 1.0.0 (see issue #8322). +- server_params_test(CERTFILE, server_protocol, certsreqs, +- CERTFILE, CERTFILE, client_protocol, +- ciphers="ALL", chatty=False) ++ server_params_test(client_context, server_context, ++ chatty=False, connectionchatty=False) + # Protocol mismatch can result in either an SSLError, or a + # "Connection reset by peer" error. + except ssl.SSLError: +@@ -930,75 +1938,38 @@ else: + + class ThreadedTests(unittest.TestCase): + +- def test_rude_shutdown(self): +- """A brutal shutdown of an SSL server should raise an IOError +- in the client when attempting handshake. +- """ +- listener_ready = threading.Event() +- listener_gone = threading.Event() +- +- s = socket.socket() +- port = test_support.bind_port(s, HOST) +- +- # `listener` runs in a thread. It sits in an accept() until +- # the main thread connects. Then it rudely closes the socket, +- # and sets Event `listener_gone` to let the main thread know +- # the socket is gone. +- def listener(): +- s.listen(5) +- listener_ready.set() +- s.accept() +- s.close() +- listener_gone.set() +- +- def connector(): +- listener_ready.wait() +- c = socket.socket() +- c.connect((HOST, port)) +- listener_gone.wait() +- try: +- ssl_sock = ssl.wrap_socket(c) +- except IOError: +- pass +- else: +- self.fail('connecting to closed SSL socket should have failed') +- +- t = threading.Thread(target=listener) +- t.start() +- try: +- connector() +- finally: +- t.join() +- + @skip_if_broken_ubuntu_ssl + def test_echo(self): + """Basic test of an SSL client connecting to a server""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") +- server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE, +- CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1, +- chatty=True, connectionchatty=True) ++ for protocol in PROTOCOLS: ++ context = ssl.SSLContext(protocol) ++ context.load_cert_chain(CERTFILE) ++ server_params_test(context, context, ++ chatty=True, connectionchatty=True) + + def test_getpeercert(self): +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") +- s2 = socket.socket() +- server = ThreadedEchoServer(CERTFILE, +- certreqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_SSLv23, +- cacerts=CERTFILE, +- chatty=False) ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERTFILE) ++ context.load_cert_chain(CERTFILE) ++ server = ThreadedEchoServer(context=context, chatty=False) + with server: +- s = ssl.wrap_socket(socket.socket(), +- certfile=CERTFILE, +- ca_certs=CERTFILE, +- cert_reqs=ssl.CERT_REQUIRED, +- ssl_version=ssl.PROTOCOL_SSLv23) ++ s = context.wrap_socket(socket.socket(), ++ do_handshake_on_connect=False) + s.connect((HOST, server.port)) ++ # getpeercert() raise ValueError while the handshake isn't ++ # done. ++ with self.assertRaises(ValueError): ++ s.getpeercert() ++ s.do_handshake() + cert = s.getpeercert() + self.assertTrue(cert, "Can't get peer certificate.") + cipher = s.cipher() +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write(pprint.pformat(cert) + '\n') + sys.stdout.write("Connection cipher is " + str(cipher) + '.\n') + if 'subject' not in cert: +@@ -1009,8 +1980,94 @@ else: + self.fail( + "Missing or invalid 'organizationName' field in certificate subject; " + "should be 'Python Software Foundation'.") ++ self.assertIn('notBefore', cert) ++ self.assertIn('notAfter', cert) ++ before = ssl.cert_time_to_seconds(cert['notBefore']) ++ after = ssl.cert_time_to_seconds(cert['notAfter']) ++ self.assertLess(before, after) + s.close() + ++ @unittest.skipUnless(have_verify_flags(), ++ "verify_flags need OpenSSL > 0.9.8") ++ def test_crl_check(self): ++ if support.verbose: ++ sys.stdout.write("\n") ++ ++ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ server_context.load_cert_chain(SIGNED_CERTFILE) ++ ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(SIGNING_CA) ++ self.assertEqual(context.verify_flags, ssl.VERIFY_DEFAULT) ++ ++ # VERIFY_DEFAULT should pass ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ s.connect((HOST, server.port)) ++ cert = s.getpeercert() ++ self.assertTrue(cert, "Can't get peer certificate.") ++ ++ # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails ++ context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF ++ ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ with self.assertRaisesRegexp(ssl.SSLError, ++ "certificate verify failed"): ++ s.connect((HOST, server.port)) ++ ++ # now load a CRL file. The CRL file is signed by the CA. ++ context.load_verify_locations(CRLFILE) ++ ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ s.connect((HOST, server.port)) ++ cert = s.getpeercert() ++ self.assertTrue(cert, "Can't get peer certificate.") ++ ++ @needs_sni ++ def test_check_hostname(self): ++ if support.verbose: ++ sys.stdout.write("\n") ++ ++ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ server_context.load_cert_chain(SIGNED_CERTFILE) ++ ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.check_hostname = True ++ context.load_verify_locations(SIGNING_CA) ++ ++ # correct hostname should verify ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(context.wrap_socket(socket.socket(), ++ server_hostname="localhost")) as s: ++ s.connect((HOST, server.port)) ++ cert = s.getpeercert() ++ self.assertTrue(cert, "Can't get peer certificate.") ++ ++ # incorrect hostname should raise an exception ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(context.wrap_socket(socket.socket(), ++ server_hostname="invalid")) as s: ++ with self.assertRaisesRegexp(ssl.CertificateError, ++ "hostname 'invalid' doesn't match u?'localhost'"): ++ s.connect((HOST, server.port)) ++ ++ # missing server_hostname arg should cause an exception, too ++ server = ThreadedEchoServer(context=server_context, chatty=True) ++ with server: ++ with closing(socket.socket()) as s: ++ with self.assertRaisesRegexp(ValueError, ++ "check_hostname requires server_hostname"): ++ context.wrap_socket(s) ++ + def test_empty_cert(self): + """Connecting with an empty cert file""" + bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, +@@ -1027,26 +2084,83 @@ else: + """Connecting with a badly formatted key (syntax error)""" + bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, + "badkey.pem")) ++ def test_rude_shutdown(self): ++ """A brutal shutdown of an SSL server should raise an OSError ++ in the client when attempting handshake. ++ """ ++ listener_ready = threading.Event() ++ listener_gone = threading.Event() + +- @skip_if_broken_ubuntu_ssl ++ s = socket.socket() ++ port = support.bind_port(s, HOST) ++ ++ # `listener` runs in a thread. It sits in an accept() until ++ # the main thread connects. Then it rudely closes the socket, ++ # and sets Event `listener_gone` to let the main thread know ++ # the socket is gone. ++ def listener(): ++ s.listen(5) ++ listener_ready.set() ++ newsock, addr = s.accept() ++ newsock.close() ++ s.close() ++ listener_gone.set() ++ ++ def connector(): ++ listener_ready.wait() ++ with closing(socket.socket()) as c: ++ c.connect((HOST, port)) ++ listener_gone.wait() ++ try: ++ ssl_sock = ssl.wrap_socket(c) ++ except ssl.SSLError: ++ pass ++ else: ++ self.fail('connecting to closed SSL socket should have failed') ++ ++ t = threading.Thread(target=listener) ++ t.start() ++ try: ++ connector() ++ finally: ++ t.join() ++ ++ @unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), ++ "OpenSSL is compiled without SSLv2 support") + def test_protocol_sslv2(self): + """Connecting to an SSLv2 server with various client options""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") +- if not hasattr(ssl, 'PROTOCOL_SSLv2'): +- self.skipTest("PROTOCOL_SSLv2 needed") + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) ++ # SSLv23 client with specific SSL options ++ if no_sslv2_implies_sslv3_hello(): ++ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_SSLv2) ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_SSLv3) ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_TLSv1) + + @skip_if_broken_ubuntu_ssl + def test_protocol_sslv23(self): + """Connecting to an SSLv23 server with various client options""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") ++ if hasattr(ssl, 'PROTOCOL_SSLv2'): ++ try: ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) ++ except socket.error as x: ++ # this fails on some older versions of OpenSSL (0.9.7l, for instance) ++ if support.verbose: ++ sys.stdout.write( ++ " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" ++ % str(x)) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) +@@ -1059,22 +2173,38 @@ else: + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) + ++ # Server with specific SSL options ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, ++ server_options=ssl.OP_NO_SSLv3) ++ # Will choose TLSv1 ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ++ server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, False, ++ server_options=ssl.OP_NO_TLSv1) ++ ++ + @skip_if_broken_ubuntu_ssl + def test_protocol_sslv3(self): + """Connecting to an SSLv3 server with various client options""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_SSLv3) + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) ++ if no_sslv2_implies_sslv3_hello(): ++ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True, ++ client_options=ssl.OP_NO_SSLv2) + + @skip_if_broken_ubuntu_ssl + def test_protocol_tlsv1(self): + """Connecting to a TLSv1 server with various client options""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) +@@ -1082,10 +2212,55 @@ else: + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_TLSv1) ++ ++ @skip_if_broken_ubuntu_ssl ++ @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_1"), ++ "TLS version 1.1 not supported.") ++ def test_protocol_tlsv1_1(self): ++ """Connecting to a TLSv1.1 server with various client options. ++ Testing against older TLS versions.""" ++ if support.verbose: ++ sys.stdout.write("\n") ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True) ++ if hasattr(ssl, 'PROTOCOL_SSLv2'): ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_TLSv1_1) ++ ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, True) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) ++ ++ ++ @skip_if_broken_ubuntu_ssl ++ @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_2"), ++ "TLS version 1.2 not supported.") ++ def test_protocol_tlsv1_2(self): ++ """Connecting to a TLSv1.2 server with various client options. ++ Testing against older TLS versions.""" ++ if support.verbose: ++ sys.stdout.write("\n") ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True, ++ server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2, ++ client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,) ++ if hasattr(ssl, 'PROTOCOL_SSLv2'): ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv23, False, ++ client_options=ssl.OP_NO_TLSv1_2) ++ ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, True) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False) + + def test_starttls(self): + """Switching from clear text to encrypted and back again.""" +- msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6") ++ msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6") + + server = ThreadedEchoServer(CERTFILE, + ssl_version=ssl.PROTOCOL_TLSv1, +@@ -1097,119 +2272,109 @@ else: + s = socket.socket() + s.setblocking(1) + s.connect((HOST, server.port)) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") + for indata in msgs: +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( +- " client: sending %s...\n" % repr(indata)) ++ " client: sending %r...\n" % indata) + if wrapped: + conn.write(indata) + outdata = conn.read() + else: + s.send(indata) + outdata = s.recv(1024) +- if (indata == "STARTTLS" and +- outdata.strip().lower().startswith("ok")): ++ msg = outdata.strip().lower() ++ if indata == b"STARTTLS" and msg.startswith(b"ok"): + # STARTTLS ok, switch to secure mode +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( +- " client: read %s from server, starting TLS...\n" +- % repr(outdata)) ++ " client: read %r from server, starting TLS...\n" ++ % msg) + conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1) + wrapped = True +- elif (indata == "ENDTLS" and +- outdata.strip().lower().startswith("ok")): ++ elif indata == b"ENDTLS" and msg.startswith(b"ok"): + # ENDTLS ok, switch back to clear text +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( +- " client: read %s from server, ending TLS...\n" +- % repr(outdata)) ++ " client: read %r from server, ending TLS...\n" ++ % msg) + s = conn.unwrap() + wrapped = False + else: +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( +- " client: read %s from server\n" % repr(outdata)) +- if test_support.verbose: ++ " client: read %r from server\n" % msg) ++ if support.verbose: + sys.stdout.write(" client: closing connection.\n") + if wrapped: +- conn.write("over\n") ++ conn.write(b"over\n") + else: +- s.send("over\n") +- s.close() ++ s.send(b"over\n") ++ if wrapped: ++ conn.close() ++ else: ++ s.close() + + def test_socketserver(self): + """Using a SocketServer to create and manage SSL connections.""" +- server = SocketServerHTTPSServer(CERTFILE) +- flag = threading.Event() +- server.start(flag) +- # wait for it to start +- flag.wait() ++ server = make_https_server(self, certfile=CERTFILE) + # try to connect ++ if support.verbose: ++ sys.stdout.write('\n') ++ with open(CERTFILE, 'rb') as f: ++ d1 = f.read() ++ d2 = '' ++ # now fetch the same data from the HTTPS server ++ url = 'https://%s:%d/%s' % ( ++ HOST, server.port, os.path.split(CERTFILE)[1]) ++ f = urllib.urlopen(url) + try: +- if test_support.verbose: +- sys.stdout.write('\n') +- with open(CERTFILE, 'rb') as f: +- d1 = f.read() +- d2 = '' +- # now fetch the same data from the HTTPS server +- url = 'https://127.0.0.1:%d/%s' % ( +- server.port, os.path.split(CERTFILE)[1]) +- with test_support.check_py3k_warnings(): +- f = urllib.urlopen(url) + dlen = f.info().getheader("content-length") + if dlen and (int(dlen) > 0): + d2 = f.read(int(dlen)) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( + " client: read %d bytes from remote server '%s'\n" + % (len(d2), server)) +- f.close() +- self.assertEqual(d1, d2) + finally: +- server.stop() +- server.join() +- +- def test_wrapped_accept(self): +- """Check the accept() method on SSL sockets.""" +- if test_support.verbose: +- sys.stdout.write("\n") +- server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED, +- CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23, +- chatty=True, connectionchatty=True, +- wrap_accepting_socket=True) ++ f.close() ++ self.assertEqual(d1, d2) + + def test_asyncore_server(self): + """Check the example asyncore integration.""" + indata = "TEST MESSAGE of mixed case\n" + +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") ++ ++ indata = b"FOO\n" + server = AsyncoreEchoServer(CERTFILE) + with server: + s = ssl.wrap_socket(socket.socket()) + s.connect(('127.0.0.1', server.port)) +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write( +- " client: sending %s...\n" % (repr(indata))) ++ " client: sending %r...\n" % indata) + s.write(indata) + outdata = s.read() +- if test_support.verbose: +- sys.stdout.write(" client: read %s\n" % repr(outdata)) ++ if support.verbose: ++ sys.stdout.write(" client: read %r\n" % outdata) + if outdata != indata.lower(): + self.fail( +- "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n" +- % (outdata[:min(len(outdata),20)], len(outdata), +- indata[:min(len(indata),20)].lower(), len(indata))) +- s.write("over\n") +- if test_support.verbose: ++ "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n" ++ % (outdata[:20], len(outdata), ++ indata[:20].lower(), len(indata))) ++ s.write(b"over\n") ++ if support.verbose: + sys.stdout.write(" client: closing connection.\n") + s.close() ++ if support.verbose: ++ sys.stdout.write(" client: connection closed.\n") + + def test_recv_send(self): + """Test recv(), send() and friends.""" +- if test_support.verbose: ++ if support.verbose: + sys.stdout.write("\n") + + server = ThreadedEchoServer(CERTFILE, +@@ -1228,12 +2393,12 @@ else: + s.connect((HOST, server.port)) + # helper methods for standardising recv* method signatures + def _recv_into(): +- b = bytearray("\0"*100) ++ b = bytearray(b"\0"*100) + count = s.recv_into(b) + return b[:count] + + def _recvfrom_into(): +- b = bytearray("\0"*100) ++ b = bytearray(b"\0"*100) + count, addr = s.recvfrom_into(b) + return b[:count] + +@@ -1252,73 +2417,73 @@ else: + data_prefix = u"PREFIX_" + + for meth_name, send_meth, expect_success, args in send_methods: +- indata = data_prefix + meth_name ++ indata = (data_prefix + meth_name).encode('ascii') + try: +- send_meth(indata.encode('ASCII', 'strict'), *args) ++ send_meth(indata, *args) + outdata = s.read() +- outdata = outdata.decode('ASCII', 'strict') + if outdata != indata.lower(): + self.fail( +- "While sending with <<%s>> bad data " +- "<<%r>> (%d) received; " +- "expected <<%r>> (%d)\n" % ( +- meth_name, outdata[:20], len(outdata), +- indata[:20], len(indata) ++ "While sending with <<{name:s}>> bad data " ++ "<<{outdata:r}>> ({nout:d}) received; " ++ "expected <<{indata:r}>> ({nin:d})\n".format( ++ name=meth_name, outdata=outdata[:20], ++ nout=len(outdata), ++ indata=indata[:20], nin=len(indata) + ) + ) + except ValueError as e: + if expect_success: + self.fail( +- "Failed to send with method <<%s>>; " +- "expected to succeed.\n" % (meth_name,) ++ "Failed to send with method <<{name:s}>>; " ++ "expected to succeed.\n".format(name=meth_name) + ) + if not str(e).startswith(meth_name): + self.fail( +- "Method <<%s>> failed with unexpected " +- "exception message: %s\n" % ( +- meth_name, e ++ "Method <<{name:s}>> failed with unexpected " ++ "exception message: {exp:s}\n".format( ++ name=meth_name, exp=e + ) + ) + + for meth_name, recv_meth, expect_success, args in recv_methods: +- indata = data_prefix + meth_name ++ indata = (data_prefix + meth_name).encode('ascii') + try: +- s.send(indata.encode('ASCII', 'strict')) ++ s.send(indata) + outdata = recv_meth(*args) +- outdata = outdata.decode('ASCII', 'strict') + if outdata != indata.lower(): + self.fail( +- "While receiving with <<%s>> bad data " +- "<<%r>> (%d) received; " +- "expected <<%r>> (%d)\n" % ( +- meth_name, outdata[:20], len(outdata), +- indata[:20], len(indata) ++ "While receiving with <<{name:s}>> bad data " ++ "<<{outdata:r}>> ({nout:d}) received; " ++ "expected <<{indata:r}>> ({nin:d})\n".format( ++ name=meth_name, outdata=outdata[:20], ++ nout=len(outdata), ++ indata=indata[:20], nin=len(indata) + ) + ) + except ValueError as e: + if expect_success: + self.fail( +- "Failed to receive with method <<%s>>; " +- "expected to succeed.\n" % (meth_name,) ++ "Failed to receive with method <<{name:s}>>; " ++ "expected to succeed.\n".format(name=meth_name) + ) + if not str(e).startswith(meth_name): + self.fail( +- "Method <<%s>> failed with unexpected " +- "exception message: %s\n" % ( +- meth_name, e ++ "Method <<{name:s}>> failed with unexpected " ++ "exception message: {exp:s}\n".format( ++ name=meth_name, exp=e + ) + ) + # consume data + s.read() + +- s.write("over\n".encode("ASCII", "strict")) ++ s.write(b"over\n") + s.close() + + def test_handshake_timeout(self): + # Issue #5103: SSL handshake must respect the socket timeout + server = socket.socket(socket.AF_INET) + host = "127.0.0.1" +- port = test_support.bind_port(server) ++ port = support.bind_port(server) + started = threading.Event() + finish = False + +@@ -1332,6 +2497,8 @@ else: + # Let the socket hang around rather than having + # it closed by garbage collection. + conns.append(server.accept()[0]) ++ for sock in conns: ++ sock.close() + + t = threading.Thread(target=serve) + t.start() +@@ -1349,8 +2516,8 @@ else: + c.close() + try: + c = socket.socket(socket.AF_INET) +- c.settimeout(0.2) + c = ssl.wrap_socket(c) ++ c.settimeout(0.2) + # Will attempt handshake and time out + self.assertRaisesRegexp(ssl.SSLError, "timed out", + c.connect, (host, port)) +@@ -1361,59 +2528,384 @@ else: + t.join() + server.close() + ++ def test_server_accept(self): ++ # Issue #16357: accept() on a SSLSocket created through ++ # SSLContext.wrap_socket(). ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERTFILE) ++ context.load_cert_chain(CERTFILE) ++ server = socket.socket(socket.AF_INET) ++ host = "127.0.0.1" ++ port = support.bind_port(server) ++ server = context.wrap_socket(server, server_side=True) ++ ++ evt = threading.Event() ++ remote = [None] ++ peer = [None] ++ def serve(): ++ server.listen(5) ++ # Block on the accept and wait on the connection to close. ++ evt.set() ++ remote[0], peer[0] = server.accept() ++ remote[0].recv(1) ++ ++ t = threading.Thread(target=serve) ++ t.start() ++ # Client wait until server setup and perform a connect. ++ evt.wait() ++ client = context.wrap_socket(socket.socket()) ++ client.connect((host, port)) ++ client_addr = client.getsockname() ++ client.close() ++ t.join() ++ remote[0].close() ++ server.close() ++ # Sanity checks. ++ self.assertIsInstance(remote[0], ssl.SSLSocket) ++ self.assertEqual(peer[0], client_addr) ++ ++ def test_getpeercert_enotconn(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ with closing(context.wrap_socket(socket.socket())) as sock: ++ with self.assertRaises(socket.error) as cm: ++ sock.getpeercert() ++ self.assertEqual(cm.exception.errno, errno.ENOTCONN) ++ ++ def test_do_handshake_enotconn(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ with closing(context.wrap_socket(socket.socket())) as sock: ++ with self.assertRaises(socket.error) as cm: ++ sock.do_handshake() ++ self.assertEqual(cm.exception.errno, errno.ENOTCONN) ++ + def test_default_ciphers(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ try: ++ # Force a set of weak ciphers on our client context ++ context.set_ciphers("DES") ++ except ssl.SSLError: ++ self.skipTest("no DES cipher available") + with ThreadedEchoServer(CERTFILE, + ssl_version=ssl.PROTOCOL_SSLv23, + chatty=False) as server: +- sock = socket.socket() +- try: +- # Force a set of weak ciphers on our client socket +- try: +- s = ssl.wrap_socket(sock, +- ssl_version=ssl.PROTOCOL_SSLv23, +- ciphers="DES") +- except ssl.SSLError: +- self.skipTest("no DES cipher available") +- with self.assertRaises((OSError, ssl.SSLError)): ++ with closing(context.wrap_socket(socket.socket())) as s: ++ with self.assertRaises(ssl.SSLError): + s.connect((HOST, server.port)) +- finally: +- sock.close() + self.assertIn("no shared cipher", str(server.conn_errors[0])) + ++ @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") ++ def test_default_ecdh_curve(self): ++ # Issue #21015: elliptic curve-based Diffie Hellman key exchange ++ # should be enabled by default on SSL contexts. ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.load_cert_chain(CERTFILE) ++ # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled ++ # explicitly using the 'ECCdraft' cipher alias. Otherwise, ++ # our default cipher list should prefer ECDH-based ciphers ++ # automatically. ++ if ssl.OPENSSL_VERSION_INFO < (1, 0, 0): ++ context.set_ciphers("ECCdraft:ECDH") ++ with ThreadedEchoServer(context=context) as server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ s.connect((HOST, server.port)) ++ self.assertIn("ECDH", s.cipher()[0]) ++ ++ @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES, ++ "'tls-unique' channel binding not available") ++ def test_tls_unique_channel_binding(self): ++ """Test tls-unique channel binding.""" ++ if support.verbose: ++ sys.stdout.write("\n") ++ ++ server = ThreadedEchoServer(CERTFILE, ++ certreqs=ssl.CERT_NONE, ++ ssl_version=ssl.PROTOCOL_TLSv1, ++ cacerts=CERTFILE, ++ chatty=True, ++ connectionchatty=False) ++ with server: ++ s = ssl.wrap_socket(socket.socket(), ++ server_side=False, ++ certfile=CERTFILE, ++ ca_certs=CERTFILE, ++ cert_reqs=ssl.CERT_NONE, ++ ssl_version=ssl.PROTOCOL_TLSv1) ++ s.connect((HOST, server.port)) ++ # get the data ++ cb_data = s.get_channel_binding("tls-unique") ++ if support.verbose: ++ sys.stdout.write(" got channel binding data: {0!r}\n" ++ .format(cb_data)) ++ ++ # check if it is sane ++ self.assertIsNotNone(cb_data) ++ self.assertEqual(len(cb_data), 12) # True for TLSv1 ++ ++ # and compare with the peers version ++ s.write(b"CB tls-unique\n") ++ peer_data_repr = s.read().strip() ++ self.assertEqual(peer_data_repr, ++ repr(cb_data).encode("us-ascii")) ++ s.close() ++ ++ # now, again ++ s = ssl.wrap_socket(socket.socket(), ++ server_side=False, ++ certfile=CERTFILE, ++ ca_certs=CERTFILE, ++ cert_reqs=ssl.CERT_NONE, ++ ssl_version=ssl.PROTOCOL_TLSv1) ++ s.connect((HOST, server.port)) ++ new_cb_data = s.get_channel_binding("tls-unique") ++ if support.verbose: ++ sys.stdout.write(" got another channel binding data: {0!r}\n" ++ .format(new_cb_data)) ++ # is it really unique ++ self.assertNotEqual(cb_data, new_cb_data) ++ self.assertIsNotNone(cb_data) ++ self.assertEqual(len(cb_data), 12) # True for TLSv1 ++ s.write(b"CB tls-unique\n") ++ peer_data_repr = s.read().strip() ++ self.assertEqual(peer_data_repr, ++ repr(new_cb_data).encode("us-ascii")) ++ s.close() ++ ++ def test_compression(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.load_cert_chain(CERTFILE) ++ stats = server_params_test(context, context, ++ chatty=True, connectionchatty=True) ++ if support.verbose: ++ sys.stdout.write(" got compression: {!r}\n".format(stats['compression'])) ++ self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' }) ++ ++ @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'), ++ "ssl.OP_NO_COMPRESSION needed for this test") ++ def test_compression_disabled(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.load_cert_chain(CERTFILE) ++ context.options |= ssl.OP_NO_COMPRESSION ++ stats = server_params_test(context, context, ++ chatty=True, connectionchatty=True) ++ self.assertIs(stats['compression'], None) ++ ++ def test_dh_params(self): ++ # Check we can get a connection with ephemeral Diffie-Hellman ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.load_cert_chain(CERTFILE) ++ context.load_dh_params(DHFILE) ++ context.set_ciphers("kEDH") ++ stats = server_params_test(context, context, ++ chatty=True, connectionchatty=True) ++ cipher = stats["cipher"][0] ++ parts = cipher.split("-") ++ if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: ++ self.fail("Non-DH cipher: " + cipher[0]) ++ ++ def test_selected_npn_protocol(self): ++ # selected_npn_protocol() is None unless NPN is used ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.load_cert_chain(CERTFILE) ++ stats = server_params_test(context, context, ++ chatty=True, connectionchatty=True) ++ self.assertIs(stats['client_npn_protocol'], None) ++ ++ @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test") ++ def test_npn_protocols(self): ++ server_protocols = ['http/1.1', 'spdy/2'] ++ protocol_tests = [ ++ (['http/1.1', 'spdy/2'], 'http/1.1'), ++ (['spdy/2', 'http/1.1'], 'http/1.1'), ++ (['spdy/2', 'test'], 'spdy/2'), ++ (['abc', 'def'], 'abc') ++ ] ++ for client_protocols, expected in protocol_tests: ++ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ server_context.load_cert_chain(CERTFILE) ++ server_context.set_npn_protocols(server_protocols) ++ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ client_context.load_cert_chain(CERTFILE) ++ client_context.set_npn_protocols(client_protocols) ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True) ++ ++ msg = "failed trying %s (s) and %s (c).\n" \ ++ "was expecting %s, but got %%s from the %%s" \ ++ % (str(server_protocols), str(client_protocols), ++ str(expected)) ++ client_result = stats['client_npn_protocol'] ++ self.assertEqual(client_result, expected, msg % (client_result, "client")) ++ server_result = stats['server_npn_protocols'][-1] \ ++ if len(stats['server_npn_protocols']) else 'nothing' ++ self.assertEqual(server_result, expected, msg % (server_result, "server")) ++ ++ def sni_contexts(self): ++ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ server_context.load_cert_chain(SIGNED_CERTFILE) ++ other_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ other_context.load_cert_chain(SIGNED_CERTFILE2) ++ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ client_context.verify_mode = ssl.CERT_REQUIRED ++ client_context.load_verify_locations(SIGNING_CA) ++ return server_context, other_context, client_context ++ ++ def check_common_name(self, stats, name): ++ cert = stats['peercert'] ++ self.assertIn((('commonName', name),), cert['subject']) ++ ++ @needs_sni ++ def test_sni_callback(self): ++ calls = [] ++ server_context, other_context, client_context = self.sni_contexts() ++ ++ def servername_cb(ssl_sock, server_name, initial_context): ++ calls.append((server_name, initial_context)) ++ if server_name is not None: ++ ssl_sock.context = other_context ++ server_context.set_servername_callback(servername_cb) ++ ++ stats = server_params_test(client_context, server_context, ++ chatty=True, ++ sni_name='supermessage') ++ # The hostname was fetched properly, and the certificate was ++ # changed for the connection. ++ self.assertEqual(calls, [("supermessage", server_context)]) ++ # CERTFILE4 was selected ++ self.check_common_name(stats, 'fakehostname') ++ ++ calls = [] ++ # The callback is called with server_name=None ++ stats = server_params_test(client_context, server_context, ++ chatty=True, ++ sni_name=None) ++ self.assertEqual(calls, [(None, server_context)]) ++ self.check_common_name(stats, 'localhost') ++ ++ # Check disabling the callback ++ calls = [] ++ server_context.set_servername_callback(None) ++ ++ stats = server_params_test(client_context, server_context, ++ chatty=True, ++ sni_name='notfunny') ++ # Certificate didn't change ++ self.check_common_name(stats, 'localhost') ++ self.assertEqual(calls, []) ++ ++ @needs_sni ++ def test_sni_callback_alert(self): ++ # Returning a TLS alert is reflected to the connecting client ++ server_context, other_context, client_context = self.sni_contexts() ++ ++ def cb_returning_alert(ssl_sock, server_name, initial_context): ++ return ssl.ALERT_DESCRIPTION_ACCESS_DENIED ++ server_context.set_servername_callback(cb_returning_alert) ++ ++ with self.assertRaises(ssl.SSLError) as cm: ++ stats = server_params_test(client_context, server_context, ++ chatty=False, ++ sni_name='supermessage') ++ self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED') ++ ++ @needs_sni ++ def test_sni_callback_raising(self): ++ # Raising fails the connection with a TLS handshake failure alert. ++ server_context, other_context, client_context = self.sni_contexts() ++ ++ def cb_raising(ssl_sock, server_name, initial_context): ++ 1/0 ++ server_context.set_servername_callback(cb_raising) ++ ++ with self.assertRaises(ssl.SSLError) as cm, \ ++ support.captured_stderr() as stderr: ++ stats = server_params_test(client_context, server_context, ++ chatty=False, ++ sni_name='supermessage') ++ self.assertEqual(cm.exception.reason, 'SSLV3_ALERT_HANDSHAKE_FAILURE') ++ self.assertIn("ZeroDivisionError", stderr.getvalue()) ++ ++ @needs_sni ++ def test_sni_callback_wrong_return_type(self): ++ # Returning the wrong return type terminates the TLS connection ++ # with an internal error alert. ++ server_context, other_context, client_context = self.sni_contexts() ++ ++ def cb_wrong_return_type(ssl_sock, server_name, initial_context): ++ return "foo" ++ server_context.set_servername_callback(cb_wrong_return_type) ++ ++ with self.assertRaises(ssl.SSLError) as cm, \ ++ support.captured_stderr() as stderr: ++ stats = server_params_test(client_context, server_context, ++ chatty=False, ++ sni_name='supermessage') ++ self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR') ++ self.assertIn("TypeError", stderr.getvalue()) ++ ++ def test_read_write_after_close_raises_valuerror(self): ++ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERTFILE) ++ context.load_cert_chain(CERTFILE) ++ server = ThreadedEchoServer(context=context, chatty=False) ++ ++ with server: ++ s = context.wrap_socket(socket.socket()) ++ s.connect((HOST, server.port)) ++ s.close() ++ ++ self.assertRaises(ValueError, s.read, 1024) ++ self.assertRaises(ValueError, s.write, b'hello') ++ + + def test_main(verbose=False): +- global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, NOKIACERT, NULLBYTECERT +- CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, +- "keycert.pem") +- SVN_PYTHON_ORG_ROOT_CERT = os.path.join( +- os.path.dirname(__file__) or os.curdir, +- "https_svn_python_org_root.pem") +- NOKIACERT = os.path.join(os.path.dirname(__file__) or os.curdir, +- "nokia.pem") +- NULLBYTECERT = os.path.join(os.path.dirname(__file__) or os.curdir, +- "nullbytecert.pem") +- +- if (not os.path.exists(CERTFILE) or +- not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT) or +- not os.path.exists(NOKIACERT) or +- not os.path.exists(NULLBYTECERT)): +- raise test_support.TestFailed("Can't read certificate files!") ++ if support.verbose: ++ plats = { ++ 'Linux': platform.linux_distribution, ++ 'Mac': platform.mac_ver, ++ 'Windows': platform.win32_ver, ++ } ++ for name, func in plats.items(): ++ plat = func() ++ if plat and plat[0]: ++ plat = '%s %r' % (name, plat) ++ break ++ else: ++ plat = repr(platform.platform()) ++ print("test_ssl: testing with %r %r" % ++ (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO)) ++ print(" under %s" % plat) ++ print(" HAS_SNI = %r" % ssl.HAS_SNI) ++ print(" OP_ALL = 0x%8x" % ssl.OP_ALL) ++ try: ++ print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1) ++ except AttributeError: ++ pass ++ ++ for filename in [ ++ CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, BYTES_CERTFILE, ++ ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY, ++ SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA, ++ BADCERT, BADKEY, EMPTYCERT]: ++ if not os.path.exists(filename): ++ raise support.TestFailed("Can't read certificate file %r" % filename) + +- tests = [BasicTests, BasicSocketTests] ++ tests = [ContextTests, BasicSocketTests, SSLErrorTests] + +- if test_support.is_resource_enabled('network'): ++ if support.is_resource_enabled('network'): + tests.append(NetworkedTests) + + if _have_threads: +- thread_info = test_support.threading_setup() +- if thread_info and test_support.is_resource_enabled('network'): ++ thread_info = support.threading_setup() ++ if thread_info: + tests.append(ThreadedTests) + + try: +- test_support.run_unittest(*tests) ++ support.run_unittest(*tests) + finally: + if _have_threads: +- test_support.threading_cleanup(*thread_info) ++ support.threading_cleanup(*thread_info) + + if __name__ == "__main__": + test_main() +diff -up Python-2.7.5/Makefile.pre.in.ssl Python-2.7.5/Makefile.pre.in +--- Python-2.7.5/Makefile.pre.in.ssl 2015-02-24 11:37:01.544850801 +0100 ++++ Python-2.7.5/Makefile.pre.in 2015-02-24 10:19:57.491864267 +0100 +@@ -931,7 +931,7 @@ PLATMACDIRS= plat-mac plat-mac/Carbon pl + plat-mac/lib-scriptpackages/Terminal + PLATMACPATH=:plat-mac:plat-mac/lib-scriptpackages + LIBSUBDIRS= lib-tk lib-tk/test lib-tk/test/test_tkinter \ +- lib-tk/test/test_ttk site-packages test test/data \ ++ lib-tk/test/test_ttk site-packages test test/data test/capath \ + test/cjkencodings test/decimaltestdata test/xmltestdata test/subprocessdata \ + test/tracedmodules \ + encodings compiler hotshot \ +diff --git a/Modules/_ssl_data.h b/Modules/_ssl_data.h +new file mode 100644 +--- /dev/null ++++ b/Modules/_ssl_data.h +@@ -0,0 +1,1653 @@ ++/* File generated by Tools/ssl/make_ssl_data.py */ ++/* Generated on 2012-05-16T23:56:40.981382 */ ++ ++static struct py_ssl_library_code library_codes[] = { ++ {"PEM", ERR_LIB_PEM}, ++ {"SSL", ERR_LIB_SSL}, ++ {"X509", ERR_LIB_X509}, ++ { NULL } ++}; ++ ++static struct py_ssl_error_code error_codes[] = { ++ #ifdef PEM_R_BAD_BASE64_DECODE ++ {"BAD_BASE64_DECODE", ERR_LIB_PEM, PEM_R_BAD_BASE64_DECODE}, ++ #else ++ {"BAD_BASE64_DECODE", ERR_LIB_PEM, 100}, ++ #endif ++ #ifdef PEM_R_BAD_DECRYPT ++ {"BAD_DECRYPT", ERR_LIB_PEM, PEM_R_BAD_DECRYPT}, ++ #else ++ {"BAD_DECRYPT", ERR_LIB_PEM, 101}, ++ #endif ++ #ifdef PEM_R_BAD_END_LINE ++ {"BAD_END_LINE", ERR_LIB_PEM, PEM_R_BAD_END_LINE}, ++ #else ++ {"BAD_END_LINE", ERR_LIB_PEM, 102}, ++ #endif ++ #ifdef PEM_R_BAD_IV_CHARS ++ {"BAD_IV_CHARS", ERR_LIB_PEM, PEM_R_BAD_IV_CHARS}, ++ #else ++ {"BAD_IV_CHARS", ERR_LIB_PEM, 103}, ++ #endif ++ #ifdef PEM_R_BAD_MAGIC_NUMBER ++ {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER}, ++ #else ++ {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, 116}, ++ #endif ++ #ifdef PEM_R_BAD_PASSWORD_READ ++ {"BAD_PASSWORD_READ", ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ}, ++ #else ++ {"BAD_PASSWORD_READ", ERR_LIB_PEM, 104}, ++ #endif ++ #ifdef PEM_R_BAD_VERSION_NUMBER ++ {"BAD_VERSION_NUMBER", ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER}, ++ #else ++ {"BAD_VERSION_NUMBER", ERR_LIB_PEM, 117}, ++ #endif ++ #ifdef PEM_R_BIO_WRITE_FAILURE ++ {"BIO_WRITE_FAILURE", ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE}, ++ #else ++ {"BIO_WRITE_FAILURE", ERR_LIB_PEM, 118}, ++ #endif ++ #ifdef PEM_R_CIPHER_IS_NULL ++ {"CIPHER_IS_NULL", ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL}, ++ #else ++ {"CIPHER_IS_NULL", ERR_LIB_PEM, 127}, ++ #endif ++ #ifdef PEM_R_ERROR_CONVERTING_PRIVATE_KEY ++ {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY}, ++ #else ++ {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, 115}, ++ #endif ++ #ifdef PEM_R_EXPECTING_PRIVATE_KEY_BLOB ++ {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB}, ++ #else ++ {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, 119}, ++ #endif ++ #ifdef PEM_R_EXPECTING_PUBLIC_KEY_BLOB ++ {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB}, ++ #else ++ {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, 120}, ++ #endif ++ #ifdef PEM_R_INCONSISTENT_HEADER ++ {"INCONSISTENT_HEADER", ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER}, ++ #else ++ {"INCONSISTENT_HEADER", ERR_LIB_PEM, 121}, ++ #endif ++ #ifdef PEM_R_KEYBLOB_HEADER_PARSE_ERROR ++ {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR}, ++ #else ++ {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, 122}, ++ #endif ++ #ifdef PEM_R_KEYBLOB_TOO_SHORT ++ {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT}, ++ #else ++ {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, 123}, ++ #endif ++ #ifdef PEM_R_NOT_DEK_INFO ++ {"NOT_DEK_INFO", ERR_LIB_PEM, PEM_R_NOT_DEK_INFO}, ++ #else ++ {"NOT_DEK_INFO", ERR_LIB_PEM, 105}, ++ #endif ++ #ifdef PEM_R_NOT_ENCRYPTED ++ {"NOT_ENCRYPTED", ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED}, ++ #else ++ {"NOT_ENCRYPTED", ERR_LIB_PEM, 106}, ++ #endif ++ #ifdef PEM_R_NOT_PROC_TYPE ++ {"NOT_PROC_TYPE", ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE}, ++ #else ++ {"NOT_PROC_TYPE", ERR_LIB_PEM, 107}, ++ #endif ++ #ifdef PEM_R_NO_START_LINE ++ {"NO_START_LINE", ERR_LIB_PEM, PEM_R_NO_START_LINE}, ++ #else ++ {"NO_START_LINE", ERR_LIB_PEM, 108}, ++ #endif ++ #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD ++ {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD}, ++ #else ++ {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, 109}, ++ #endif ++ #ifdef PEM_R_PUBLIC_KEY_NO_RSA ++ {"PUBLIC_KEY_NO_RSA", ERR_LIB_PEM, PEM_R_PUBLIC_KEY_NO_RSA}, ++ #else ++ {"PUBLIC_KEY_NO_RSA", ERR_LIB_PEM, 110}, ++ #endif ++ #ifdef PEM_R_PVK_DATA_TOO_SHORT ++ {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT}, ++ #else ++ {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, 124}, ++ #endif ++ #ifdef PEM_R_PVK_TOO_SHORT ++ {"PVK_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT}, ++ #else ++ {"PVK_TOO_SHORT", ERR_LIB_PEM, 125}, ++ #endif ++ #ifdef PEM_R_READ_KEY ++ {"READ_KEY", ERR_LIB_PEM, PEM_R_READ_KEY}, ++ #else ++ {"READ_KEY", ERR_LIB_PEM, 111}, ++ #endif ++ #ifdef PEM_R_SHORT_HEADER ++ {"SHORT_HEADER", ERR_LIB_PEM, PEM_R_SHORT_HEADER}, ++ #else ++ {"SHORT_HEADER", ERR_LIB_PEM, 112}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, 113}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_ENCRYPTION ++ {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION}, ++ #else ++ {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, 114}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_KEY_COMPONENTS ++ {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS}, ++ #else ++ {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, 126}, ++ #endif ++ #ifdef SSL_R_APP_DATA_IN_HANDSHAKE ++ {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, SSL_R_APP_DATA_IN_HANDSHAKE}, ++ #else ++ {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, 100}, ++ #endif ++ #ifdef SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT ++ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT}, ++ #else ++ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, 272}, ++ #endif ++ #ifdef SSL_R_BAD_ALERT_RECORD ++ {"BAD_ALERT_RECORD", ERR_LIB_SSL, SSL_R_BAD_ALERT_RECORD}, ++ #else ++ {"BAD_ALERT_RECORD", ERR_LIB_SSL, 101}, ++ #endif ++ #ifdef SSL_R_BAD_AUTHENTICATION_TYPE ++ {"BAD_AUTHENTICATION_TYPE", ERR_LIB_SSL, SSL_R_BAD_AUTHENTICATION_TYPE}, ++ #else ++ {"BAD_AUTHENTICATION_TYPE", ERR_LIB_SSL, 102}, ++ #endif ++ #ifdef SSL_R_BAD_CHANGE_CIPHER_SPEC ++ {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC}, ++ #else ++ {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, 103}, ++ #endif ++ #ifdef SSL_R_BAD_CHECKSUM ++ {"BAD_CHECKSUM", ERR_LIB_SSL, SSL_R_BAD_CHECKSUM}, ++ #else ++ {"BAD_CHECKSUM", ERR_LIB_SSL, 104}, ++ #endif ++ #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK ++ {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, ++ #else ++ {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, 106}, ++ #endif ++ #ifdef SSL_R_BAD_DECOMPRESSION ++ {"BAD_DECOMPRESSION", ERR_LIB_SSL, SSL_R_BAD_DECOMPRESSION}, ++ #else ++ {"BAD_DECOMPRESSION", ERR_LIB_SSL, 107}, ++ #endif ++ #ifdef SSL_R_BAD_DH_G_LENGTH ++ {"BAD_DH_G_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_G_LENGTH}, ++ #else ++ {"BAD_DH_G_LENGTH", ERR_LIB_SSL, 108}, ++ #endif ++ #ifdef SSL_R_BAD_DH_PUB_KEY_LENGTH ++ {"BAD_DH_PUB_KEY_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_PUB_KEY_LENGTH}, ++ #else ++ {"BAD_DH_PUB_KEY_LENGTH", ERR_LIB_SSL, 109}, ++ #endif ++ #ifdef SSL_R_BAD_DH_P_LENGTH ++ {"BAD_DH_P_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_P_LENGTH}, ++ #else ++ {"BAD_DH_P_LENGTH", ERR_LIB_SSL, 110}, ++ #endif ++ #ifdef SSL_R_BAD_DIGEST_LENGTH ++ {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DIGEST_LENGTH}, ++ #else ++ {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, 111}, ++ #endif ++ #ifdef SSL_R_BAD_DSA_SIGNATURE ++ {"BAD_DSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_DSA_SIGNATURE}, ++ #else ++ {"BAD_DSA_SIGNATURE", ERR_LIB_SSL, 112}, ++ #endif ++ #ifdef SSL_R_BAD_ECC_CERT ++ {"BAD_ECC_CERT", ERR_LIB_SSL, SSL_R_BAD_ECC_CERT}, ++ #else ++ {"BAD_ECC_CERT", ERR_LIB_SSL, 304}, ++ #endif ++ #ifdef SSL_R_BAD_ECDSA_SIGNATURE ++ {"BAD_ECDSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_ECDSA_SIGNATURE}, ++ #else ++ {"BAD_ECDSA_SIGNATURE", ERR_LIB_SSL, 305}, ++ #endif ++ #ifdef SSL_R_BAD_ECPOINT ++ {"BAD_ECPOINT", ERR_LIB_SSL, SSL_R_BAD_ECPOINT}, ++ #else ++ {"BAD_ECPOINT", ERR_LIB_SSL, 306}, ++ #endif ++ #ifdef SSL_R_BAD_HANDSHAKE_LENGTH ++ {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_LENGTH}, ++ #else ++ {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, 332}, ++ #endif ++ #ifdef SSL_R_BAD_HELLO_REQUEST ++ {"BAD_HELLO_REQUEST", ERR_LIB_SSL, SSL_R_BAD_HELLO_REQUEST}, ++ #else ++ {"BAD_HELLO_REQUEST", ERR_LIB_SSL, 105}, ++ #endif ++ #ifdef SSL_R_BAD_LENGTH ++ {"BAD_LENGTH", ERR_LIB_SSL, SSL_R_BAD_LENGTH}, ++ #else ++ {"BAD_LENGTH", ERR_LIB_SSL, 271}, ++ #endif ++ #ifdef SSL_R_BAD_MAC_DECODE ++ {"BAD_MAC_DECODE", ERR_LIB_SSL, SSL_R_BAD_MAC_DECODE}, ++ #else ++ {"BAD_MAC_DECODE", ERR_LIB_SSL, 113}, ++ #endif ++ #ifdef SSL_R_BAD_MAC_LENGTH ++ {"BAD_MAC_LENGTH", ERR_LIB_SSL, SSL_R_BAD_MAC_LENGTH}, ++ #else ++ {"BAD_MAC_LENGTH", ERR_LIB_SSL, 333}, ++ #endif ++ #ifdef SSL_R_BAD_MESSAGE_TYPE ++ {"BAD_MESSAGE_TYPE", ERR_LIB_SSL, SSL_R_BAD_MESSAGE_TYPE}, ++ #else ++ {"BAD_MESSAGE_TYPE", ERR_LIB_SSL, 114}, ++ #endif ++ #ifdef SSL_R_BAD_PACKET_LENGTH ++ {"BAD_PACKET_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PACKET_LENGTH}, ++ #else ++ {"BAD_PACKET_LENGTH", ERR_LIB_SSL, 115}, ++ #endif ++ #ifdef SSL_R_BAD_PROTOCOL_VERSION_NUMBER ++ {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER}, ++ #else ++ {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, 116}, ++ #endif ++ #ifdef SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH ++ {"BAD_PSK_IDENTITY_HINT_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH}, ++ #else ++ {"BAD_PSK_IDENTITY_HINT_LENGTH", ERR_LIB_SSL, 316}, ++ #endif ++ #ifdef SSL_R_BAD_RESPONSE_ARGUMENT ++ {"BAD_RESPONSE_ARGUMENT", ERR_LIB_SSL, SSL_R_BAD_RESPONSE_ARGUMENT}, ++ #else ++ {"BAD_RESPONSE_ARGUMENT", ERR_LIB_SSL, 117}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_DECRYPT ++ {"BAD_RSA_DECRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_DECRYPT}, ++ #else ++ {"BAD_RSA_DECRYPT", ERR_LIB_SSL, 118}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_ENCRYPT ++ {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_ENCRYPT}, ++ #else ++ {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, 119}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_E_LENGTH ++ {"BAD_RSA_E_LENGTH", ERR_LIB_SSL, SSL_R_BAD_RSA_E_LENGTH}, ++ #else ++ {"BAD_RSA_E_LENGTH", ERR_LIB_SSL, 120}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_MODULUS_LENGTH ++ {"BAD_RSA_MODULUS_LENGTH", ERR_LIB_SSL, SSL_R_BAD_RSA_MODULUS_LENGTH}, ++ #else ++ {"BAD_RSA_MODULUS_LENGTH", ERR_LIB_SSL, 121}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_SIGNATURE ++ {"BAD_RSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_RSA_SIGNATURE}, ++ #else ++ {"BAD_RSA_SIGNATURE", ERR_LIB_SSL, 122}, ++ #endif ++ #ifdef SSL_R_BAD_SIGNATURE ++ {"BAD_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_SIGNATURE}, ++ #else ++ {"BAD_SIGNATURE", ERR_LIB_SSL, 123}, ++ #endif ++ #ifdef SSL_R_BAD_SSL_FILETYPE ++ {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, ++ #else ++ {"BAD_SSL_FILETYPE", ERR_LIB_SSL, 124}, ++ #endif ++ #ifdef SSL_R_BAD_SSL_SESSION_ID_LENGTH ++ {"BAD_SSL_SESSION_ID_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SSL_SESSION_ID_LENGTH}, ++ #else ++ {"BAD_SSL_SESSION_ID_LENGTH", ERR_LIB_SSL, 125}, ++ #endif ++ #ifdef SSL_R_BAD_STATE ++ {"BAD_STATE", ERR_LIB_SSL, SSL_R_BAD_STATE}, ++ #else ++ {"BAD_STATE", ERR_LIB_SSL, 126}, ++ #endif ++ #ifdef SSL_R_BAD_WRITE_RETRY ++ {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, ++ #else ++ {"BAD_WRITE_RETRY", ERR_LIB_SSL, 127}, ++ #endif ++ #ifdef SSL_R_BIO_NOT_SET ++ {"BIO_NOT_SET", ERR_LIB_SSL, SSL_R_BIO_NOT_SET}, ++ #else ++ {"BIO_NOT_SET", ERR_LIB_SSL, 128}, ++ #endif ++ #ifdef SSL_R_BLOCK_CIPHER_PAD_IS_WRONG ++ {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG}, ++ #else ++ {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, 129}, ++ #endif ++ #ifdef SSL_R_BN_LIB ++ {"BN_LIB", ERR_LIB_SSL, SSL_R_BN_LIB}, ++ #else ++ {"BN_LIB", ERR_LIB_SSL, 130}, ++ #endif ++ #ifdef SSL_R_CA_DN_LENGTH_MISMATCH ++ {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CA_DN_LENGTH_MISMATCH}, ++ #else ++ {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, 131}, ++ #endif ++ #ifdef SSL_R_CA_DN_TOO_LONG ++ {"CA_DN_TOO_LONG", ERR_LIB_SSL, SSL_R_CA_DN_TOO_LONG}, ++ #else ++ {"CA_DN_TOO_LONG", ERR_LIB_SSL, 132}, ++ #endif ++ #ifdef SSL_R_CCS_RECEIVED_EARLY ++ {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, ++ #else ++ {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, 133}, ++ #endif ++ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED ++ {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED}, ++ #else ++ {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, 134}, ++ #endif ++ #ifdef SSL_R_CERT_LENGTH_MISMATCH ++ {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, ++ #else ++ {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, 135}, ++ #endif ++ #ifdef SSL_R_CHALLENGE_IS_DIFFERENT ++ {"CHALLENGE_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_CHALLENGE_IS_DIFFERENT}, ++ #else ++ {"CHALLENGE_IS_DIFFERENT", ERR_LIB_SSL, 136}, ++ #endif ++ #ifdef SSL_R_CIPHER_CODE_WRONG_LENGTH ++ {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH}, ++ #else ++ {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, 137}, ++ #endif ++ #ifdef SSL_R_CIPHER_OR_HASH_UNAVAILABLE ++ {"CIPHER_OR_HASH_UNAVAILABLE", ERR_LIB_SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE}, ++ #else ++ {"CIPHER_OR_HASH_UNAVAILABLE", ERR_LIB_SSL, 138}, ++ #endif ++ #ifdef SSL_R_CIPHER_TABLE_SRC_ERROR ++ {"CIPHER_TABLE_SRC_ERROR", ERR_LIB_SSL, SSL_R_CIPHER_TABLE_SRC_ERROR}, ++ #else ++ {"CIPHER_TABLE_SRC_ERROR", ERR_LIB_SSL, 139}, ++ #endif ++ #ifdef SSL_R_CLIENTHELLO_TLSEXT ++ {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_CLIENTHELLO_TLSEXT}, ++ #else ++ {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, 226}, ++ #endif ++ #ifdef SSL_R_COMPRESSED_LENGTH_TOO_LONG ++ {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_COMPRESSED_LENGTH_TOO_LONG}, ++ #else ++ {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, 140}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_DISABLED ++ {"COMPRESSION_DISABLED", ERR_LIB_SSL, SSL_R_COMPRESSION_DISABLED}, ++ #else ++ {"COMPRESSION_DISABLED", ERR_LIB_SSL, 343}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_FAILURE ++ {"COMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_COMPRESSION_FAILURE}, ++ #else ++ {"COMPRESSION_FAILURE", ERR_LIB_SSL, 141}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE ++ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE}, ++ #else ++ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, 307}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_LIBRARY_ERROR ++ {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR}, ++ #else ++ {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, 142}, ++ #endif ++ #ifdef SSL_R_CONNECTION_ID_IS_DIFFERENT ++ {"CONNECTION_ID_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_CONNECTION_ID_IS_DIFFERENT}, ++ #else ++ {"CONNECTION_ID_IS_DIFFERENT", ERR_LIB_SSL, 143}, ++ #endif ++ #ifdef SSL_R_CONNECTION_TYPE_NOT_SET ++ {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET}, ++ #else ++ {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, 144}, ++ #endif ++ #ifdef SSL_R_COOKIE_MISMATCH ++ {"COOKIE_MISMATCH", ERR_LIB_SSL, SSL_R_COOKIE_MISMATCH}, ++ #else ++ {"COOKIE_MISMATCH", ERR_LIB_SSL, 308}, ++ #endif ++ #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED ++ {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED}, ++ #else ++ {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, 145}, ++ #endif ++ #ifdef SSL_R_DATA_LENGTH_TOO_LONG ++ {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG}, ++ #else ++ {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, 146}, ++ #endif ++ #ifdef SSL_R_DECRYPTION_FAILED ++ {"DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED}, ++ #else ++ {"DECRYPTION_FAILED", ERR_LIB_SSL, 147}, ++ #endif ++ #ifdef SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC ++ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC}, ++ #else ++ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, 281}, ++ #endif ++ #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG ++ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, ++ #else ++ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, 148}, ++ #endif ++ #ifdef SSL_R_DIGEST_CHECK_FAILED ++ {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, SSL_R_DIGEST_CHECK_FAILED}, ++ #else ++ {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, 149}, ++ #endif ++ #ifdef SSL_R_DTLS_MESSAGE_TOO_BIG ++ {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, SSL_R_DTLS_MESSAGE_TOO_BIG}, ++ #else ++ {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, 334}, ++ #endif ++ #ifdef SSL_R_DUPLICATE_COMPRESSION_ID ++ {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, SSL_R_DUPLICATE_COMPRESSION_ID}, ++ #else ++ {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, 309}, ++ #endif ++ #ifdef SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT ++ {"ECC_CERT_NOT_FOR_KEY_AGREEMENT", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT}, ++ #else ++ {"ECC_CERT_NOT_FOR_KEY_AGREEMENT", ERR_LIB_SSL, 317}, ++ #endif ++ #ifdef SSL_R_ECC_CERT_NOT_FOR_SIGNING ++ {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING}, ++ #else ++ {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, 318}, ++ #endif ++ #ifdef SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE ++ {"ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE", ERR_LIB_SSL, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE}, ++ #else ++ {"ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE", ERR_LIB_SSL, 322}, ++ #endif ++ #ifdef SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE ++ {"ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE", ERR_LIB_SSL, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE}, ++ #else ++ {"ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE", ERR_LIB_SSL, 323}, ++ #endif ++ #ifdef SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER ++ {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER}, ++ #else ++ {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, 310}, ++ #endif ++ #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG ++ {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, ++ #else ++ {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, 150}, ++ #endif ++ #ifdef SSL_R_ERROR_GENERATING_TMP_RSA_KEY ++ {"ERROR_GENERATING_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_ERROR_GENERATING_TMP_RSA_KEY}, ++ #else ++ {"ERROR_GENERATING_TMP_RSA_KEY", ERR_LIB_SSL, 282}, ++ #endif ++ #ifdef SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST ++ {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST}, ++ #else ++ {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, 151}, ++ #endif ++ #ifdef SSL_R_EXCESSIVE_MESSAGE_SIZE ++ {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE}, ++ #else ++ {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, 152}, ++ #endif ++ #ifdef SSL_R_EXTRA_DATA_IN_MESSAGE ++ {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, SSL_R_EXTRA_DATA_IN_MESSAGE}, ++ #else ++ {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, 153}, ++ #endif ++ #ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS ++ {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS}, ++ #else ++ {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, 154}, ++ #endif ++ #ifdef SSL_R_HTTPS_PROXY_REQUEST ++ {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, ++ #else ++ {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, 155}, ++ #endif ++ #ifdef SSL_R_HTTP_REQUEST ++ {"HTTP_REQUEST", ERR_LIB_SSL, SSL_R_HTTP_REQUEST}, ++ #else ++ {"HTTP_REQUEST", ERR_LIB_SSL, 156}, ++ #endif ++ #ifdef SSL_R_ILLEGAL_PADDING ++ {"ILLEGAL_PADDING", ERR_LIB_SSL, SSL_R_ILLEGAL_PADDING}, ++ #else ++ {"ILLEGAL_PADDING", ERR_LIB_SSL, 283}, ++ #endif ++ #ifdef SSL_R_INCONSISTENT_COMPRESSION ++ {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, ++ #else ++ {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, 340}, ++ #endif ++ #ifdef SSL_R_INVALID_CHALLENGE_LENGTH ++ {"INVALID_CHALLENGE_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_CHALLENGE_LENGTH}, ++ #else ++ {"INVALID_CHALLENGE_LENGTH", ERR_LIB_SSL, 158}, ++ #endif ++ #ifdef SSL_R_INVALID_COMMAND ++ {"INVALID_COMMAND", ERR_LIB_SSL, SSL_R_INVALID_COMMAND}, ++ #else ++ {"INVALID_COMMAND", ERR_LIB_SSL, 280}, ++ #endif ++ #ifdef SSL_R_INVALID_COMPRESSION_ALGORITHM ++ {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_INVALID_COMPRESSION_ALGORITHM}, ++ #else ++ {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, 341}, ++ #endif ++ #ifdef SSL_R_INVALID_PURPOSE ++ {"INVALID_PURPOSE", ERR_LIB_SSL, SSL_R_INVALID_PURPOSE}, ++ #else ++ {"INVALID_PURPOSE", ERR_LIB_SSL, 278}, ++ #endif ++ #ifdef SSL_R_INVALID_STATUS_RESPONSE ++ {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, ++ #else ++ {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, 328}, ++ #endif ++ #ifdef SSL_R_INVALID_TICKET_KEYS_LENGTH ++ {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH}, ++ #else ++ {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, 325}, ++ #endif ++ #ifdef SSL_R_INVALID_TRUST ++ {"INVALID_TRUST", ERR_LIB_SSL, SSL_R_INVALID_TRUST}, ++ #else ++ {"INVALID_TRUST", ERR_LIB_SSL, 279}, ++ #endif ++ #ifdef SSL_R_KEY_ARG_TOO_LONG ++ {"KEY_ARG_TOO_LONG", ERR_LIB_SSL, SSL_R_KEY_ARG_TOO_LONG}, ++ #else ++ {"KEY_ARG_TOO_LONG", ERR_LIB_SSL, 284}, ++ #endif ++ #ifdef SSL_R_KRB5 ++ {"KRB5", ERR_LIB_SSL, SSL_R_KRB5}, ++ #else ++ {"KRB5", ERR_LIB_SSL, 285}, ++ #endif ++ #ifdef SSL_R_KRB5_C_CC_PRINC ++ {"KRB5_C_CC_PRINC", ERR_LIB_SSL, SSL_R_KRB5_C_CC_PRINC}, ++ #else ++ {"KRB5_C_CC_PRINC", ERR_LIB_SSL, 286}, ++ #endif ++ #ifdef SSL_R_KRB5_C_GET_CRED ++ {"KRB5_C_GET_CRED", ERR_LIB_SSL, SSL_R_KRB5_C_GET_CRED}, ++ #else ++ {"KRB5_C_GET_CRED", ERR_LIB_SSL, 287}, ++ #endif ++ #ifdef SSL_R_KRB5_C_INIT ++ {"KRB5_C_INIT", ERR_LIB_SSL, SSL_R_KRB5_C_INIT}, ++ #else ++ {"KRB5_C_INIT", ERR_LIB_SSL, 288}, ++ #endif ++ #ifdef SSL_R_KRB5_C_MK_REQ ++ {"KRB5_C_MK_REQ", ERR_LIB_SSL, SSL_R_KRB5_C_MK_REQ}, ++ #else ++ {"KRB5_C_MK_REQ", ERR_LIB_SSL, 289}, ++ #endif ++ #ifdef SSL_R_KRB5_S_BAD_TICKET ++ {"KRB5_S_BAD_TICKET", ERR_LIB_SSL, SSL_R_KRB5_S_BAD_TICKET}, ++ #else ++ {"KRB5_S_BAD_TICKET", ERR_LIB_SSL, 290}, ++ #endif ++ #ifdef SSL_R_KRB5_S_INIT ++ {"KRB5_S_INIT", ERR_LIB_SSL, SSL_R_KRB5_S_INIT}, ++ #else ++ {"KRB5_S_INIT", ERR_LIB_SSL, 291}, ++ #endif ++ #ifdef SSL_R_KRB5_S_RD_REQ ++ {"KRB5_S_RD_REQ", ERR_LIB_SSL, SSL_R_KRB5_S_RD_REQ}, ++ #else ++ {"KRB5_S_RD_REQ", ERR_LIB_SSL, 292}, ++ #endif ++ #ifdef SSL_R_KRB5_S_TKT_EXPIRED ++ {"KRB5_S_TKT_EXPIRED", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_EXPIRED}, ++ #else ++ {"KRB5_S_TKT_EXPIRED", ERR_LIB_SSL, 293}, ++ #endif ++ #ifdef SSL_R_KRB5_S_TKT_NYV ++ {"KRB5_S_TKT_NYV", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_NYV}, ++ #else ++ {"KRB5_S_TKT_NYV", ERR_LIB_SSL, 294}, ++ #endif ++ #ifdef SSL_R_KRB5_S_TKT_SKEW ++ {"KRB5_S_TKT_SKEW", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_SKEW}, ++ #else ++ {"KRB5_S_TKT_SKEW", ERR_LIB_SSL, 295}, ++ #endif ++ #ifdef SSL_R_LENGTH_MISMATCH ++ {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, ++ #else ++ {"LENGTH_MISMATCH", ERR_LIB_SSL, 159}, ++ #endif ++ #ifdef SSL_R_LENGTH_TOO_SHORT ++ {"LENGTH_TOO_SHORT", ERR_LIB_SSL, SSL_R_LENGTH_TOO_SHORT}, ++ #else ++ {"LENGTH_TOO_SHORT", ERR_LIB_SSL, 160}, ++ #endif ++ #ifdef SSL_R_LIBRARY_BUG ++ {"LIBRARY_BUG", ERR_LIB_SSL, SSL_R_LIBRARY_BUG}, ++ #else ++ {"LIBRARY_BUG", ERR_LIB_SSL, 274}, ++ #endif ++ #ifdef SSL_R_LIBRARY_HAS_NO_CIPHERS ++ {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS}, ++ #else ++ {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, 161}, ++ #endif ++ #ifdef SSL_R_MESSAGE_TOO_LONG ++ {"MESSAGE_TOO_LONG", ERR_LIB_SSL, SSL_R_MESSAGE_TOO_LONG}, ++ #else ++ {"MESSAGE_TOO_LONG", ERR_LIB_SSL, 296}, ++ #endif ++ #ifdef SSL_R_MISSING_DH_DSA_CERT ++ {"MISSING_DH_DSA_CERT", ERR_LIB_SSL, SSL_R_MISSING_DH_DSA_CERT}, ++ #else ++ {"MISSING_DH_DSA_CERT", ERR_LIB_SSL, 162}, ++ #endif ++ #ifdef SSL_R_MISSING_DH_KEY ++ {"MISSING_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_DH_KEY}, ++ #else ++ {"MISSING_DH_KEY", ERR_LIB_SSL, 163}, ++ #endif ++ #ifdef SSL_R_MISSING_DH_RSA_CERT ++ {"MISSING_DH_RSA_CERT", ERR_LIB_SSL, SSL_R_MISSING_DH_RSA_CERT}, ++ #else ++ {"MISSING_DH_RSA_CERT", ERR_LIB_SSL, 164}, ++ #endif ++ #ifdef SSL_R_MISSING_DSA_SIGNING_CERT ++ {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_DSA_SIGNING_CERT}, ++ #else ++ {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, 165}, ++ #endif ++ #ifdef SSL_R_MISSING_EXPORT_TMP_DH_KEY ++ {"MISSING_EXPORT_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_EXPORT_TMP_DH_KEY}, ++ #else ++ {"MISSING_EXPORT_TMP_DH_KEY", ERR_LIB_SSL, 166}, ++ #endif ++ #ifdef SSL_R_MISSING_EXPORT_TMP_RSA_KEY ++ {"MISSING_EXPORT_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_MISSING_EXPORT_TMP_RSA_KEY}, ++ #else ++ {"MISSING_EXPORT_TMP_RSA_KEY", ERR_LIB_SSL, 167}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_CERTIFICATE ++ {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, ++ #else ++ {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, 168}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_ENCRYPTING_CERT ++ {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_ENCRYPTING_CERT}, ++ #else ++ {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, 169}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_SIGNING_CERT ++ {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_SIGNING_CERT}, ++ #else ++ {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, 170}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_DH_KEY ++ {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, ++ #else ++ {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, 171}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_ECDH_KEY ++ {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_ECDH_KEY}, ++ #else ++ {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, 311}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_RSA_KEY ++ {"MISSING_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_RSA_KEY}, ++ #else ++ {"MISSING_TMP_RSA_KEY", ERR_LIB_SSL, 172}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_RSA_PKEY ++ {"MISSING_TMP_RSA_PKEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_RSA_PKEY}, ++ #else ++ {"MISSING_TMP_RSA_PKEY", ERR_LIB_SSL, 173}, ++ #endif ++ #ifdef SSL_R_MISSING_VERIFY_MESSAGE ++ {"MISSING_VERIFY_MESSAGE", ERR_LIB_SSL, SSL_R_MISSING_VERIFY_MESSAGE}, ++ #else ++ {"MISSING_VERIFY_MESSAGE", ERR_LIB_SSL, 174}, ++ #endif ++ #ifdef SSL_R_NON_SSLV2_INITIAL_PACKET ++ {"NON_SSLV2_INITIAL_PACKET", ERR_LIB_SSL, SSL_R_NON_SSLV2_INITIAL_PACKET}, ++ #else ++ {"NON_SSLV2_INITIAL_PACKET", ERR_LIB_SSL, 175}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATES_RETURNED ++ {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATES_RETURNED}, ++ #else ++ {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, 176}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_ASSIGNED ++ {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED}, ++ #else ++ {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, 177}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_RETURNED ++ {"NO_CERTIFICATE_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_RETURNED}, ++ #else ++ {"NO_CERTIFICATE_RETURNED", ERR_LIB_SSL, 178}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_SET ++ {"NO_CERTIFICATE_SET", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET}, ++ #else ++ {"NO_CERTIFICATE_SET", ERR_LIB_SSL, 179}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_SPECIFIED ++ {"NO_CERTIFICATE_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SPECIFIED}, ++ #else ++ {"NO_CERTIFICATE_SPECIFIED", ERR_LIB_SSL, 180}, ++ #endif ++ #ifdef SSL_R_NO_CIPHERS_AVAILABLE ++ {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_CIPHERS_AVAILABLE}, ++ #else ++ {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, 181}, ++ #endif ++ #ifdef SSL_R_NO_CIPHERS_PASSED ++ {"NO_CIPHERS_PASSED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_PASSED}, ++ #else ++ {"NO_CIPHERS_PASSED", ERR_LIB_SSL, 182}, ++ #endif ++ #ifdef SSL_R_NO_CIPHERS_SPECIFIED ++ {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_SPECIFIED}, ++ #else ++ {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, 183}, ++ #endif ++ #ifdef SSL_R_NO_CIPHER_LIST ++ {"NO_CIPHER_LIST", ERR_LIB_SSL, SSL_R_NO_CIPHER_LIST}, ++ #else ++ {"NO_CIPHER_LIST", ERR_LIB_SSL, 184}, ++ #endif ++ #ifdef SSL_R_NO_CIPHER_MATCH ++ {"NO_CIPHER_MATCH", ERR_LIB_SSL, SSL_R_NO_CIPHER_MATCH}, ++ #else ++ {"NO_CIPHER_MATCH", ERR_LIB_SSL, 185}, ++ #endif ++ #ifdef SSL_R_NO_CLIENT_CERT_METHOD ++ {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_METHOD}, ++ #else ++ {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, 331}, ++ #endif ++ #ifdef SSL_R_NO_CLIENT_CERT_RECEIVED ++ {"NO_CLIENT_CERT_RECEIVED", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_RECEIVED}, ++ #else ++ {"NO_CLIENT_CERT_RECEIVED", ERR_LIB_SSL, 186}, ++ #endif ++ #ifdef SSL_R_NO_COMPRESSION_SPECIFIED ++ {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_COMPRESSION_SPECIFIED}, ++ #else ++ {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, 187}, ++ #endif ++ #ifdef SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER ++ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER}, ++ #else ++ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, 330}, ++ #endif ++ #ifdef SSL_R_NO_METHOD_SPECIFIED ++ {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED}, ++ #else ++ {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, 188}, ++ #endif ++ #ifdef SSL_R_NO_PRIVATEKEY ++ {"NO_PRIVATEKEY", ERR_LIB_SSL, SSL_R_NO_PRIVATEKEY}, ++ #else ++ {"NO_PRIVATEKEY", ERR_LIB_SSL, 189}, ++ #endif ++ #ifdef SSL_R_NO_PRIVATE_KEY_ASSIGNED ++ {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED}, ++ #else ++ {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, 190}, ++ #endif ++ #ifdef SSL_R_NO_PROTOCOLS_AVAILABLE ++ {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_PROTOCOLS_AVAILABLE}, ++ #else ++ {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, 191}, ++ #endif ++ #ifdef SSL_R_NO_PUBLICKEY ++ {"NO_PUBLICKEY", ERR_LIB_SSL, SSL_R_NO_PUBLICKEY}, ++ #else ++ {"NO_PUBLICKEY", ERR_LIB_SSL, 192}, ++ #endif ++ #ifdef SSL_R_NO_RENEGOTIATION ++ {"NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION}, ++ #else ++ {"NO_RENEGOTIATION", ERR_LIB_SSL, 339}, ++ #endif ++ #ifdef SSL_R_NO_REQUIRED_DIGEST ++ {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, SSL_R_NO_REQUIRED_DIGEST}, ++ #else ++ {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, 324}, ++ #endif ++ #ifdef SSL_R_NO_SHARED_CIPHER ++ {"NO_SHARED_CIPHER", ERR_LIB_SSL, SSL_R_NO_SHARED_CIPHER}, ++ #else ++ {"NO_SHARED_CIPHER", ERR_LIB_SSL, 193}, ++ #endif ++ #ifdef SSL_R_NO_VERIFY_CALLBACK ++ {"NO_VERIFY_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_CALLBACK}, ++ #else ++ {"NO_VERIFY_CALLBACK", ERR_LIB_SSL, 194}, ++ #endif ++ #ifdef SSL_R_NULL_SSL_CTX ++ {"NULL_SSL_CTX", ERR_LIB_SSL, SSL_R_NULL_SSL_CTX}, ++ #else ++ {"NULL_SSL_CTX", ERR_LIB_SSL, 195}, ++ #endif ++ #ifdef SSL_R_NULL_SSL_METHOD_PASSED ++ {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED}, ++ #else ++ {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, 196}, ++ #endif ++ #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED ++ {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, ++ #else ++ {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, 197}, ++ #endif ++ #ifdef SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED ++ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED}, ++ #else ++ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, 344}, ++ #endif ++ #ifdef SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE ++ {"ONLY_TLS_ALLOWED_IN_FIPS_MODE", ERR_LIB_SSL, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE}, ++ #else ++ {"ONLY_TLS_ALLOWED_IN_FIPS_MODE", ERR_LIB_SSL, 297}, ++ #endif ++ #ifdef SSL_R_OPAQUE_PRF_INPUT_TOO_LONG ++ {"OPAQUE_PRF_INPUT_TOO_LONG", ERR_LIB_SSL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG}, ++ #else ++ {"OPAQUE_PRF_INPUT_TOO_LONG", ERR_LIB_SSL, 327}, ++ #endif ++ #ifdef SSL_R_PACKET_LENGTH_TOO_LONG ++ {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PACKET_LENGTH_TOO_LONG}, ++ #else ++ {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, 198}, ++ #endif ++ #ifdef SSL_R_PARSE_TLSEXT ++ {"PARSE_TLSEXT", ERR_LIB_SSL, SSL_R_PARSE_TLSEXT}, ++ #else ++ {"PARSE_TLSEXT", ERR_LIB_SSL, 227}, ++ #endif ++ #ifdef SSL_R_PATH_TOO_LONG ++ {"PATH_TOO_LONG", ERR_LIB_SSL, SSL_R_PATH_TOO_LONG}, ++ #else ++ {"PATH_TOO_LONG", ERR_LIB_SSL, 270}, ++ #endif ++ #ifdef SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE ++ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE}, ++ #else ++ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, 199}, ++ #endif ++ #ifdef SSL_R_PEER_ERROR ++ {"PEER_ERROR", ERR_LIB_SSL, SSL_R_PEER_ERROR}, ++ #else ++ {"PEER_ERROR", ERR_LIB_SSL, 200}, ++ #endif ++ #ifdef SSL_R_PEER_ERROR_CERTIFICATE ++ {"PEER_ERROR_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_ERROR_CERTIFICATE}, ++ #else ++ {"PEER_ERROR_CERTIFICATE", ERR_LIB_SSL, 201}, ++ #endif ++ #ifdef SSL_R_PEER_ERROR_NO_CERTIFICATE ++ {"PEER_ERROR_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_ERROR_NO_CERTIFICATE}, ++ #else ++ {"PEER_ERROR_NO_CERTIFICATE", ERR_LIB_SSL, 202}, ++ #endif ++ #ifdef SSL_R_PEER_ERROR_NO_CIPHER ++ {"PEER_ERROR_NO_CIPHER", ERR_LIB_SSL, SSL_R_PEER_ERROR_NO_CIPHER}, ++ #else ++ {"PEER_ERROR_NO_CIPHER", ERR_LIB_SSL, 203}, ++ #endif ++ #ifdef SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE ++ {"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE}, ++ #else ++ {"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE", ERR_LIB_SSL, 204}, ++ #endif ++ #ifdef SSL_R_PRE_MAC_LENGTH_TOO_LONG ++ {"PRE_MAC_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PRE_MAC_LENGTH_TOO_LONG}, ++ #else ++ {"PRE_MAC_LENGTH_TOO_LONG", ERR_LIB_SSL, 205}, ++ #endif ++ #ifdef SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS ++ {"PROBLEMS_MAPPING_CIPHER_FUNCTIONS", ERR_LIB_SSL, SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS}, ++ #else ++ {"PROBLEMS_MAPPING_CIPHER_FUNCTIONS", ERR_LIB_SSL, 206}, ++ #endif ++ #ifdef SSL_R_PROTOCOL_IS_SHUTDOWN ++ {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN}, ++ #else ++ {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, 207}, ++ #endif ++ #ifdef SSL_R_PSK_IDENTITY_NOT_FOUND ++ {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, SSL_R_PSK_IDENTITY_NOT_FOUND}, ++ #else ++ {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, 223}, ++ #endif ++ #ifdef SSL_R_PSK_NO_CLIENT_CB ++ {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, SSL_R_PSK_NO_CLIENT_CB}, ++ #else ++ {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, 224}, ++ #endif ++ #ifdef SSL_R_PSK_NO_SERVER_CB ++ {"PSK_NO_SERVER_CB", ERR_LIB_SSL, SSL_R_PSK_NO_SERVER_CB}, ++ #else ++ {"PSK_NO_SERVER_CB", ERR_LIB_SSL, 225}, ++ #endif ++ #ifdef SSL_R_PUBLIC_KEY_ENCRYPT_ERROR ++ {"PUBLIC_KEY_ENCRYPT_ERROR", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_ENCRYPT_ERROR}, ++ #else ++ {"PUBLIC_KEY_ENCRYPT_ERROR", ERR_LIB_SSL, 208}, ++ #endif ++ #ifdef SSL_R_PUBLIC_KEY_IS_NOT_RSA ++ {"PUBLIC_KEY_IS_NOT_RSA", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_IS_NOT_RSA}, ++ #else ++ {"PUBLIC_KEY_IS_NOT_RSA", ERR_LIB_SSL, 209}, ++ #endif ++ #ifdef SSL_R_PUBLIC_KEY_NOT_RSA ++ {"PUBLIC_KEY_NOT_RSA", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_NOT_RSA}, ++ #else ++ {"PUBLIC_KEY_NOT_RSA", ERR_LIB_SSL, 210}, ++ #endif ++ #ifdef SSL_R_READ_BIO_NOT_SET ++ {"READ_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_READ_BIO_NOT_SET}, ++ #else ++ {"READ_BIO_NOT_SET", ERR_LIB_SSL, 211}, ++ #endif ++ #ifdef SSL_R_READ_TIMEOUT_EXPIRED ++ {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, SSL_R_READ_TIMEOUT_EXPIRED}, ++ #else ++ {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, 312}, ++ #endif ++ #ifdef SSL_R_READ_WRONG_PACKET_TYPE ++ {"READ_WRONG_PACKET_TYPE", ERR_LIB_SSL, SSL_R_READ_WRONG_PACKET_TYPE}, ++ #else ++ {"READ_WRONG_PACKET_TYPE", ERR_LIB_SSL, 212}, ++ #endif ++ #ifdef SSL_R_RECORD_LENGTH_MISMATCH ++ {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_RECORD_LENGTH_MISMATCH}, ++ #else ++ {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, 213}, ++ #endif ++ #ifdef SSL_R_RECORD_TOO_LARGE ++ {"RECORD_TOO_LARGE", ERR_LIB_SSL, SSL_R_RECORD_TOO_LARGE}, ++ #else ++ {"RECORD_TOO_LARGE", ERR_LIB_SSL, 214}, ++ #endif ++ #ifdef SSL_R_RECORD_TOO_SMALL ++ {"RECORD_TOO_SMALL", ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL}, ++ #else ++ {"RECORD_TOO_SMALL", ERR_LIB_SSL, 298}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG ++ {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, SSL_R_RENEGOTIATE_EXT_TOO_LONG}, ++ #else ++ {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, 335}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATION_ENCODING_ERR ++ {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, SSL_R_RENEGOTIATION_ENCODING_ERR}, ++ #else ++ {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, 336}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATION_MISMATCH ++ {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, SSL_R_RENEGOTIATION_MISMATCH}, ++ #else ++ {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, 337}, ++ #endif ++ #ifdef SSL_R_REQUIRED_CIPHER_MISSING ++ {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_CIPHER_MISSING}, ++ #else ++ {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, 215}, ++ #endif ++ #ifdef SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING ++ {"REQUIRED_COMPRESSSION_ALGORITHM_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING}, ++ #else ++ {"REQUIRED_COMPRESSSION_ALGORITHM_MISSING", ERR_LIB_SSL, 342}, ++ #endif ++ #ifdef SSL_R_REUSE_CERT_LENGTH_NOT_ZERO ++ {"REUSE_CERT_LENGTH_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CERT_LENGTH_NOT_ZERO}, ++ #else ++ {"REUSE_CERT_LENGTH_NOT_ZERO", ERR_LIB_SSL, 216}, ++ #endif ++ #ifdef SSL_R_REUSE_CERT_TYPE_NOT_ZERO ++ {"REUSE_CERT_TYPE_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CERT_TYPE_NOT_ZERO}, ++ #else ++ {"REUSE_CERT_TYPE_NOT_ZERO", ERR_LIB_SSL, 217}, ++ #endif ++ #ifdef SSL_R_REUSE_CIPHER_LIST_NOT_ZERO ++ {"REUSE_CIPHER_LIST_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CIPHER_LIST_NOT_ZERO}, ++ #else ++ {"REUSE_CIPHER_LIST_NOT_ZERO", ERR_LIB_SSL, 218}, ++ #endif ++ #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING ++ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING}, ++ #else ++ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, 345}, ++ #endif ++ #ifdef SSL_R_SERVERHELLO_TLSEXT ++ {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_SERVERHELLO_TLSEXT}, ++ #else ++ {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, 275}, ++ #endif ++ #ifdef SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED ++ {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED}, ++ #else ++ {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, 277}, ++ #endif ++ #ifdef SSL_R_SHORT_READ ++ {"SHORT_READ", ERR_LIB_SSL, SSL_R_SHORT_READ}, ++ #else ++ {"SHORT_READ", ERR_LIB_SSL, 219}, ++ #endif ++ #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE ++ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, ++ #else ++ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, 220}, ++ #endif ++ #ifdef SSL_R_SSL23_DOING_SESSION_ID_REUSE ++ {"SSL23_DOING_SESSION_ID_REUSE", ERR_LIB_SSL, SSL_R_SSL23_DOING_SESSION_ID_REUSE}, ++ #else ++ {"SSL23_DOING_SESSION_ID_REUSE", ERR_LIB_SSL, 221}, ++ #endif ++ #ifdef SSL_R_SSL2_CONNECTION_ID_TOO_LONG ++ {"SSL2_CONNECTION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL2_CONNECTION_ID_TOO_LONG}, ++ #else ++ {"SSL2_CONNECTION_ID_TOO_LONG", ERR_LIB_SSL, 299}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT ++ {"SSL3_EXT_INVALID_ECPOINTFORMAT", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT}, ++ #else ++ {"SSL3_EXT_INVALID_ECPOINTFORMAT", ERR_LIB_SSL, 321}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME ++ {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME}, ++ #else ++ {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, 319}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE ++ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE}, ++ #else ++ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, 320}, ++ #endif ++ #ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG ++ {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_LONG}, ++ #else ++ {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, 300}, ++ #endif ++ #ifdef SSL_R_SSL3_SESSION_ID_TOO_SHORT ++ {"SSL3_SESSION_ID_TOO_SHORT", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_SHORT}, ++ #else ++ {"SSL3_SESSION_ID_TOO_SHORT", ERR_LIB_SSL, 222}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE ++ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, 1042}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC ++ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, ++ #else ++ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, 1020}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, 1045}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, 1044}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, 1046}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, ++ #else ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, 1030}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, ++ #else ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, 1040}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, ++ #else ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, 1047}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE ++ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, 1041}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, ++ #else ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, 1010}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, 1043}, ++ #endif ++ #ifdef SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION ++ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION}, ++ #else ++ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, 228}, ++ #endif ++ #ifdef SSL_R_SSL_HANDSHAKE_FAILURE ++ {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSL_HANDSHAKE_FAILURE}, ++ #else ++ {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, 229}, ++ #endif ++ #ifdef SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS ++ {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS}, ++ #else ++ {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, 230}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED ++ {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, ++ #else ++ {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, 301}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CONFLICT ++ {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONFLICT}, ++ #else ++ {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, 302}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG ++ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG}, ++ #else ++ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, 273}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH ++ {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH}, ++ #else ++ {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, 303}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_IS_DIFFERENT ++ {"SSL_SESSION_ID_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_IS_DIFFERENT}, ++ #else ++ {"SSL_SESSION_ID_IS_DIFFERENT", ERR_LIB_SSL, 231}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED ++ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, ++ #else ++ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, 1049}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR ++ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, 1050}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED ++ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, ++ #else ++ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, 1021}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR ++ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, 1051}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, ++ #else ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, 1060}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, ++ #else ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, 1071}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR ++ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, ++ #else ++ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, 1080}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ++ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, ++ #else ++ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, 1100}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION ++ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, ++ #else ++ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, 1070}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW ++ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, ++ #else ++ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, 1022}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA ++ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, ++ #else ++ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, 1048}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED ++ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, ++ #else ++ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, 1090}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, 1114}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, 1113}, ++ #endif ++ #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, ++ #else ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, 1111}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME ++ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, ++ #else ++ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, 1112}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION ++ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, ++ #else ++ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, 1110}, ++ #endif ++ #ifdef SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER ++ {"TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER", ERR_LIB_SSL, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER}, ++ #else ++ {"TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER", ERR_LIB_SSL, 232}, ++ #endif ++ #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST ++ {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, ++ #else ++ {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, 157}, ++ #endif ++ #ifdef SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST ++ {"TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST", ERR_LIB_SSL, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST}, ++ #else ++ {"TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST", ERR_LIB_SSL, 233}, ++ #endif ++ #ifdef SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG ++ {"TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG}, ++ #else ++ {"TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, 234}, ++ #endif ++ #ifdef SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER ++ {"TRIED_TO_USE_UNSUPPORTED_CIPHER", ERR_LIB_SSL, SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER}, ++ #else ++ {"TRIED_TO_USE_UNSUPPORTED_CIPHER", ERR_LIB_SSL, 235}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_DECODE_DH_CERTS ++ {"UNABLE_TO_DECODE_DH_CERTS", ERR_LIB_SSL, SSL_R_UNABLE_TO_DECODE_DH_CERTS}, ++ #else ++ {"UNABLE_TO_DECODE_DH_CERTS", ERR_LIB_SSL, 236}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_DECODE_ECDH_CERTS ++ {"UNABLE_TO_DECODE_ECDH_CERTS", ERR_LIB_SSL, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS}, ++ #else ++ {"UNABLE_TO_DECODE_ECDH_CERTS", ERR_LIB_SSL, 313}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY ++ {"UNABLE_TO_EXTRACT_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY}, ++ #else ++ {"UNABLE_TO_EXTRACT_PUBLIC_KEY", ERR_LIB_SSL, 237}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_DH_PARAMETERS ++ {"UNABLE_TO_FIND_DH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_DH_PARAMETERS}, ++ #else ++ {"UNABLE_TO_FIND_DH_PARAMETERS", ERR_LIB_SSL, 238}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS ++ {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS}, ++ #else ++ {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, 314}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS ++ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS}, ++ #else ++ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, 239}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_SSL_METHOD ++ {"UNABLE_TO_FIND_SSL_METHOD", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_SSL_METHOD}, ++ #else ++ {"UNABLE_TO_FIND_SSL_METHOD", ERR_LIB_SSL, 240}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES ++ {"UNABLE_TO_LOAD_SSL2_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES}, ++ #else ++ {"UNABLE_TO_LOAD_SSL2_MD5_ROUTINES", ERR_LIB_SSL, 241}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES ++ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES}, ++ #else ++ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, 242}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES ++ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES}, ++ #else ++ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, 243}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_MESSAGE ++ {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE}, ++ #else ++ {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, 244}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_RECORD ++ {"UNEXPECTED_RECORD", ERR_LIB_SSL, SSL_R_UNEXPECTED_RECORD}, ++ #else ++ {"UNEXPECTED_RECORD", ERR_LIB_SSL, 245}, ++ #endif ++ #ifdef SSL_R_UNINITIALIZED ++ {"UNINITIALIZED", ERR_LIB_SSL, SSL_R_UNINITIALIZED}, ++ #else ++ {"UNINITIALIZED", ERR_LIB_SSL, 276}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_ALERT_TYPE ++ {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_ALERT_TYPE}, ++ #else ++ {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, 246}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CERTIFICATE_TYPE ++ {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE}, ++ #else ++ {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, 247}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CIPHER_RETURNED ++ {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_RETURNED}, ++ #else ++ {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, 248}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CIPHER_TYPE ++ {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_TYPE}, ++ #else ++ {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, 249}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE ++ {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, ++ #else ++ {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, 250}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_PKEY_TYPE ++ {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_PKEY_TYPE}, ++ #else ++ {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, 251}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_PROTOCOL ++ {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, SSL_R_UNKNOWN_PROTOCOL}, ++ #else ++ {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, 252}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_REMOTE_ERROR_TYPE ++ {"UNKNOWN_REMOTE_ERROR_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_REMOTE_ERROR_TYPE}, ++ #else ++ {"UNKNOWN_REMOTE_ERROR_TYPE", ERR_LIB_SSL, 253}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_SSL_VERSION ++ {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION}, ++ #else ++ {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, 254}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_STATE ++ {"UNKNOWN_STATE", ERR_LIB_SSL, SSL_R_UNKNOWN_STATE}, ++ #else ++ {"UNKNOWN_STATE", ERR_LIB_SSL, 255}, ++ #endif ++ #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED ++ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED}, ++ #else ++ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, 338}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_SSL, SSL_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", ERR_LIB_SSL, 256}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, 257}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_DIGEST_TYPE ++ {"UNSUPPORTED_DIGEST_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_DIGEST_TYPE}, ++ #else ++ {"UNSUPPORTED_DIGEST_TYPE", ERR_LIB_SSL, 326}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_ELLIPTIC_CURVE ++ {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE}, ++ #else ++ {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, 315}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_PROTOCOL ++ {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, SSL_R_UNSUPPORTED_PROTOCOL}, ++ #else ++ {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, 258}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_SSL_VERSION ++ {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION}, ++ #else ++ {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, 259}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_STATUS_TYPE ++ {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_STATUS_TYPE}, ++ #else ++ {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, 329}, ++ #endif ++ #ifdef SSL_R_WRITE_BIO_NOT_SET ++ {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_WRITE_BIO_NOT_SET}, ++ #else ++ {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, 260}, ++ #endif ++ #ifdef SSL_R_WRONG_CIPHER_RETURNED ++ {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, ++ #else ++ {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, 261}, ++ #endif ++ #ifdef SSL_R_WRONG_MESSAGE_TYPE ++ {"WRONG_MESSAGE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_MESSAGE_TYPE}, ++ #else ++ {"WRONG_MESSAGE_TYPE", ERR_LIB_SSL, 262}, ++ #endif ++ #ifdef SSL_R_WRONG_NUMBER_OF_KEY_BITS ++ {"WRONG_NUMBER_OF_KEY_BITS", ERR_LIB_SSL, SSL_R_WRONG_NUMBER_OF_KEY_BITS}, ++ #else ++ {"WRONG_NUMBER_OF_KEY_BITS", ERR_LIB_SSL, 263}, ++ #endif ++ #ifdef SSL_R_WRONG_SIGNATURE_LENGTH ++ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_LENGTH}, ++ #else ++ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, 264}, ++ #endif ++ #ifdef SSL_R_WRONG_SIGNATURE_SIZE ++ {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_SIZE}, ++ #else ++ {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, 265}, ++ #endif ++ #ifdef SSL_R_WRONG_SSL_VERSION ++ {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, ++ #else ++ {"WRONG_SSL_VERSION", ERR_LIB_SSL, 266}, ++ #endif ++ #ifdef SSL_R_WRONG_VERSION_NUMBER ++ {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER}, ++ #else ++ {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, 267}, ++ #endif ++ #ifdef SSL_R_X509_LIB ++ {"X509_LIB", ERR_LIB_SSL, SSL_R_X509_LIB}, ++ #else ++ {"X509_LIB", ERR_LIB_SSL, 268}, ++ #endif ++ #ifdef SSL_R_X509_VERIFICATION_SETUP_PROBLEMS ++ {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS}, ++ #else ++ {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, 269}, ++ #endif ++ #ifdef X509_R_BAD_X509_FILETYPE ++ {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, ++ #else ++ {"BAD_X509_FILETYPE", ERR_LIB_X509, 100}, ++ #endif ++ #ifdef X509_R_BASE64_DECODE_ERROR ++ {"BASE64_DECODE_ERROR", ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR}, ++ #else ++ {"BASE64_DECODE_ERROR", ERR_LIB_X509, 118}, ++ #endif ++ #ifdef X509_R_CANT_CHECK_DH_KEY ++ {"CANT_CHECK_DH_KEY", ERR_LIB_X509, X509_R_CANT_CHECK_DH_KEY}, ++ #else ++ {"CANT_CHECK_DH_KEY", ERR_LIB_X509, 114}, ++ #endif ++ #ifdef X509_R_CERT_ALREADY_IN_HASH_TABLE ++ {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, X509_R_CERT_ALREADY_IN_HASH_TABLE}, ++ #else ++ {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, 101}, ++ #endif ++ #ifdef X509_R_ERR_ASN1_LIB ++ {"ERR_ASN1_LIB", ERR_LIB_X509, X509_R_ERR_ASN1_LIB}, ++ #else ++ {"ERR_ASN1_LIB", ERR_LIB_X509, 102}, ++ #endif ++ #ifdef X509_R_INVALID_DIRECTORY ++ {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, ++ #else ++ {"INVALID_DIRECTORY", ERR_LIB_X509, 113}, ++ #endif ++ #ifdef X509_R_INVALID_FIELD_NAME ++ {"INVALID_FIELD_NAME", ERR_LIB_X509, X509_R_INVALID_FIELD_NAME}, ++ #else ++ {"INVALID_FIELD_NAME", ERR_LIB_X509, 119}, ++ #endif ++ #ifdef X509_R_INVALID_TRUST ++ {"INVALID_TRUST", ERR_LIB_X509, X509_R_INVALID_TRUST}, ++ #else ++ {"INVALID_TRUST", ERR_LIB_X509, 123}, ++ #endif ++ #ifdef X509_R_KEY_TYPE_MISMATCH ++ {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, ++ #else ++ {"KEY_TYPE_MISMATCH", ERR_LIB_X509, 115}, ++ #endif ++ #ifdef X509_R_KEY_VALUES_MISMATCH ++ {"KEY_VALUES_MISMATCH", ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH}, ++ #else ++ {"KEY_VALUES_MISMATCH", ERR_LIB_X509, 116}, ++ #endif ++ #ifdef X509_R_LOADING_CERT_DIR ++ {"LOADING_CERT_DIR", ERR_LIB_X509, X509_R_LOADING_CERT_DIR}, ++ #else ++ {"LOADING_CERT_DIR", ERR_LIB_X509, 103}, ++ #endif ++ #ifdef X509_R_LOADING_DEFAULTS ++ {"LOADING_DEFAULTS", ERR_LIB_X509, X509_R_LOADING_DEFAULTS}, ++ #else ++ {"LOADING_DEFAULTS", ERR_LIB_X509, 104}, ++ #endif ++ #ifdef X509_R_METHOD_NOT_SUPPORTED ++ {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED}, ++ #else ++ {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, 124}, ++ #endif ++ #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY ++ {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, ++ #else ++ {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, 105}, ++ #endif ++ #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR ++ {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, ++ #else ++ {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, 125}, ++ #endif ++ #ifdef X509_R_PUBLIC_KEY_ENCODE_ERROR ++ {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR}, ++ #else ++ {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, 126}, ++ #endif ++ #ifdef X509_R_SHOULD_RETRY ++ {"SHOULD_RETRY", ERR_LIB_X509, X509_R_SHOULD_RETRY}, ++ #else ++ {"SHOULD_RETRY", ERR_LIB_X509, 106}, ++ #endif ++ #ifdef X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN ++ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN}, ++ #else ++ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, 107}, ++ #endif ++ #ifdef X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY ++ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY}, ++ #else ++ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, 108}, ++ #endif ++ #ifdef X509_R_UNKNOWN_KEY_TYPE ++ {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE}, ++ #else ++ {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, 117}, ++ #endif ++ #ifdef X509_R_UNKNOWN_NID ++ {"UNKNOWN_NID", ERR_LIB_X509, X509_R_UNKNOWN_NID}, ++ #else ++ {"UNKNOWN_NID", ERR_LIB_X509, 109}, ++ #endif ++ #ifdef X509_R_UNKNOWN_PURPOSE_ID ++ {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID}, ++ #else ++ {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, 121}, ++ #endif ++ #ifdef X509_R_UNKNOWN_TRUST_ID ++ {"UNKNOWN_TRUST_ID", ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID}, ++ #else ++ {"UNKNOWN_TRUST_ID", ERR_LIB_X509, 120}, ++ #endif ++ #ifdef X509_R_UNSUPPORTED_ALGORITHM ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, 111}, ++ #endif ++ #ifdef X509_R_WRONG_LOOKUP_TYPE ++ {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE}, ++ #else ++ {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, 112}, ++ #endif ++ #ifdef X509_R_WRONG_TYPE ++ {"WRONG_TYPE", ERR_LIB_X509, X509_R_WRONG_TYPE}, ++ #else ++ {"WRONG_TYPE", ERR_LIB_X509, 122}, ++ #endif ++ { NULL } ++}; +diff -up Python-2.7.5/Lib/test/test_support.py.ssl Python-2.7.5/Lib/test/test_support.py +--- Python-2.7.5/Lib/test/test_support.py.ssl 2015-02-24 12:12:20.587171888 +0100 ++++ Python-2.7.5/Lib/test/test_support.py 2015-02-24 12:12:59.495502649 +0100 +@@ -290,7 +290,8 @@ def requires(resource, msg=None): + msg = "Use of the `%s' resource not enabled" % resource + raise ResourceDenied(msg) + +-HOST = 'localhost' ++HOST = "127.0.0.1" ++HOSTv6 = "::1" + + def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): + """Returns an unused port that should be suitable for binding. This is diff --git a/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch b/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch new file mode 100644 index 00000000..34fd3ba4 --- /dev/null +++ b/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch @@ -0,0 +1,26 @@ +diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl2 Python-2.7.5/Lib/test/test_ssl.py +--- Python-2.7.5/Lib/test/test_ssl.py.ssl2 2015-03-04 12:19:26.345387741 +0100 ++++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-04 12:32:43.485702679 +0100 +@@ -689,7 +689,8 @@ class ContextTests(unittest.TestCase): + @skip_if_broken_ubuntu_ssl + def test_options(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- # OP_ALL | OP_NO_SSLv2 is the default value ++ self.assertEqual(ssl.OP_ALL, ctx.options) ++ ctx.options |= ssl.OP_NO_SSLv2 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, + ctx.options) + ctx.options |= ssl.OP_NO_SSLv3 +@@ -2142,9 +2143,9 @@ else: + # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_SSLv2) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + client_options=ssl.OP_NO_SSLv3) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + client_options=ssl.OP_NO_TLSv1) + + @skip_if_broken_ubuntu_ssl + diff --git a/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch b/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch new file mode 100644 index 00000000..87ee80bd --- /dev/null +++ b/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch @@ -0,0 +1,72 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409232801 14400 +# Node ID 97081a80f487841d81aeed55d398a1dba1faca00 +# Parent 3ae399c6ecf685086ebf07e17717955f21e14cb8 +fix load_verify_locations on unicode paths (closes #22244) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -850,11 +850,14 @@ class ContextTests(unittest.TestCase): + ctx.load_verify_locations(cafile=CERTFILE, capath=None) + ctx.load_verify_locations(BYTES_CERTFILE) + ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None) ++ ctx.load_verify_locations(cafile=BYTES_CERTFILE.decode('utf-8')) + self.assertRaises(TypeError, ctx.load_verify_locations) + self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None) + with self.assertRaises(IOError) as cm: + ctx.load_verify_locations(WRONGCERT) + self.assertEqual(cm.exception.errno, errno.ENOENT) ++ with self.assertRaises(IOError): ++ ctx.load_verify_locations(u'') + with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + ctx.load_verify_locations(BADCERT) + ctx.load_verify_locations(CERTFILE, CAPATH) +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -2628,17 +2628,33 @@ load_verify_locations(PySSLContext *self + } + + if (cafile) { +- cafile_bytes = PyString_AsEncodedObject( +- cafile, Py_FileSystemDefaultEncoding, "strict"); +- if (!cafile_bytes) { +- goto error; ++ if (PyString_Check(cafile)) { ++ Py_INCREF(cafile); ++ cafile_bytes = cafile; ++ } else { ++ PyObject *u = PyUnicode_FromObject(cafile); ++ if (!u) ++ goto error; ++ cafile_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!cafile_bytes) ++ goto error; + } + } + if (capath) { +- capath_bytes = PyString_AsEncodedObject( +- capath, Py_FileSystemDefaultEncoding, "strict"); +- if (!capath_bytes) { +- goto error; ++ if (PyString_Check(capath)) { ++ Py_INCREF(capath); ++ capath_bytes = capath; ++ } else { ++ PyObject *u = PyUnicode_FromObject(capath); ++ if (!u) ++ goto error; ++ capath_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!capath_bytes) ++ goto error; + } + } + + diff --git a/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch b/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch new file mode 100644 index 00000000..eb7866cb --- /dev/null +++ b/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch @@ -0,0 +1,189 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409233289 14400 +# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 +# Parent 97081a80f487841d81aeed55d398a1dba1faca00 +PEP 466: backport hashlib algorithm constants (closes #21307) + +diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst +--- a/Doc/library/hashlib.rst ++++ b/Doc/library/hashlib.rst +@@ -88,6 +88,24 @@ This module provides the following const + + .. versionadded:: 2.7 + ++.. data:: algorithms_guaranteed ++ ++ A set containing the names of the hash algorithms guaranteed to be supported ++ by this module on all platforms. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: algorithms_available ++ ++ A set containing the names of the hash algorithms that are available in the ++ running Python interpreter. These names will be recognized when passed to ++ :func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The ++ same algorithm may appear multiple times in this set under different names ++ (thanks to OpenSSL). ++ ++ .. versionadded:: 2.7.9 ++ ++ + The following values are provided as constant attributes of the hash objects + returned by the constructors: + +diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py +--- Python-2.7.5/Lib/hashlib.py.hash 2015-03-04 17:05:57.496598686 +0100 ++++ Python-2.7.5/Lib/hashlib.py 2015-03-04 17:11:34.872739103 +0100 +@@ -18,8 +18,9 @@ than using new(): + + md5(), sha1(), sha224(), sha256(), sha384(), and sha512() + +-More algorithms may be available on your platform but the above are +-guaranteed to exist. ++More algorithms may be available on your platform but the above are guaranteed ++to exist. See the algorithms_guaranteed and algorithms_available attributes ++to find out what algorithm names can be passed to new(). + + NOTE: If you want the adler32 or crc32 hash functions they are available in + the zlib module. +@@ -75,9 +76,14 @@ More condensed: + # always available algorithm is added. + __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') + ++algorithms_guaranteed = set(__always_supported) ++algorithms_available = set(__always_supported) ++ + algorithms = __always_supported + +-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac') ++__all__ = __always_supported + ('new', 'algorithms_guaranteed', ++ 'algorithms_available', 'algorithms', ++ 'pbkdf2_hmac') + + + def __get_openssl_constructor(name): +@@ -110,6 +116,8 @@ try: + import _hashlib + new = __hash_new + __get_hash = __get_openssl_constructor ++ algorithms_available = algorithms_available.union( ++ _hashlib.openssl_md_meth_names) + except ImportError: + # We don't build the legacy modules + raise +diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c +--- Python-2.7.5/Modules/_hashopenssl.c.hash 2015-03-04 17:06:18.246791837 +0100 ++++ Python-2.7.5/Modules/_hashopenssl.c 2015-03-04 17:16:17.696369000 +0100 +@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar + + #endif + ++/* State for our callback function so that it can accumulate a result. */ ++typedef struct _internal_name_mapper_state { ++ PyObject *set; ++ int error; ++} _InternalNameMapperState; ++ ++ ++/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */ ++static void ++_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg) ++{ ++ _InternalNameMapperState *state = (_InternalNameMapperState *)arg; ++ PyObject *py_name; ++ ++ assert(state != NULL); ++ if (openssl_obj_name == NULL) ++ return; ++ /* Ignore aliased names, they pollute the list and OpenSSL appears to ++ * have a its own definition of alias as the resulting list still ++ * contains duplicate and alternate names for several algorithms. */ ++ if (openssl_obj_name->alias) ++ return; ++ ++ py_name = PyString_FromString(openssl_obj_name->name); ++ if (py_name == NULL) { ++ state->error = 1; ++ } else { ++ if (PySet_Add(state->set, py_name) != 0) { ++ state->error = 1; ++ } ++ Py_DECREF(py_name); ++ } ++} ++ ++ ++/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */ ++static PyObject* ++generate_hash_name_list(void) ++{ ++ _InternalNameMapperState state; ++ state.set = PyFrozenSet_New(NULL); ++ if (state.set == NULL) ++ return NULL; ++ state.error = 0; ++ ++ OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state); ++ ++ if (state.error) { ++ Py_DECREF(state.set); ++ return NULL; ++ } ++ return state.set; ++} ++ ++ + /* + * This macro and function generates a family of constructor function + * definitions for specific hash algorithms. These constructors are much +@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[ + PyMODINIT_FUNC + init_hashlib(void) + { +- PyObject *m; ++ PyObject *m, *openssl_md_meth_names; + + SSL_load_error_strings(); + SSL_library_init(); +- OpenSSL_add_all_digests(); ++ ERR_load_crypto_strings(); + + Py_TYPE(&EVPtype) = &PyType_Type; + if (PyType_Ready(&EVPtype) < 0) +@@ -938,6 +993,14 @@ init_hashlib(void) + if (m == NULL) + return; + ++ openssl_md_meth_names = generate_hash_name_list(); ++ if (openssl_md_meth_names == NULL) { ++ return; ++ } ++ if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) { ++ return; ++ } ++ + #if HASH_OBJ_CONSTRUCTOR + Py_INCREF(&EVPtype); + PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); +diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py +--- Python-2.7.5/Lib/test/test_hashlib.py.hash 2015-03-04 18:04:57.823553474 +0100 ++++ Python-2.7.5/Lib/test/test_hashlib.py 2015-03-04 18:06:39.395499123 +0100 +@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase) + tuple([_algo for _algo in self.supported_hash_names if + _algo.islower()])) + ++ def test_algorithms_guaranteed(self): ++ self.assertEqual(hashlib.algorithms_guaranteed, ++ set(_algo for _algo in self.supported_hash_names ++ if _algo.islower())) ++ ++ def test_algorithms_available(self): ++ self.assertTrue(set(hashlib.algorithms_guaranteed). ++ issubset(hashlib.algorithms_available)) ++ + def test_unknown_hash(self): + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) diff --git a/SOURCES/00218-pep466-backport-urandom-pers-fd.patch b/SOURCES/00218-pep466-backport-urandom-pers-fd.patch new file mode 100644 index 00000000..8a97bdcb --- /dev/null +++ b/SOURCES/00218-pep466-backport-urandom-pers-fd.patch @@ -0,0 +1,165 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409243400 14400 +# Node ID 3e7f8855078855a9409bc2c1372de89cb021d6c8 +# Parent 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 +PEP 466: backport persistent urandom fd (closes #21305) + +Patch from Alex Gaynor. + +diff --git a/Python/pythonrun.c b/Python/pythonrun.c +--- a/Python/pythonrun.c ++++ b/Python/pythonrun.c +@@ -536,6 +536,7 @@ Py_Finalize(void) + PyInt_Fini(); + PyFloat_Fini(); + PyDict_Fini(); ++ _PyRandom_Fini(); + + #ifdef Py_USING_UNICODE + /* Cleanup Unicode implementation */ +diff -up Python-2.7.5/Include/pythonrun.h.urandom Python-2.7.5/Include/pythonrun.h +--- Python-2.7.5/Include/pythonrun.h.urandom 2015-03-06 08:16:47.638584015 +0100 ++++ Python-2.7.5/Include/pythonrun.h 2015-03-06 08:21:48.009485462 +0100 +@@ -145,6 +145,7 @@ PyAPI_FUNC(void) PyInt_Fini(void); + PyAPI_FUNC(void) PyFloat_Fini(void); + PyAPI_FUNC(void) PyOS_FiniInterrupts(void); + PyAPI_FUNC(void) PyByteArray_Fini(void); ++PyAPI_FUNC(void) _PyRandom_Fini(void); + + /* Stuff with no proper home (yet) */ + PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *); +diff -up Python-2.7.5/Python/random.c.urandom Python-2.7.5/Python/random.c +--- Python-2.7.5/Python/random.c.urandom 2015-03-06 08:22:10.244699950 +0100 ++++ Python-2.7.5/Python/random.c 2015-03-06 08:24:57.907317272 +0100 +@@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ss + + #if !defined(MS_WINDOWS) && !defined(__VMS) + ++static struct { ++ int fd; ++ dev_t st_dev; ++ ino_t st_ino; ++} urandom_cache = { -1 }; ++ + /* Read size bytes from /dev/urandom into buffer. + Call Py_FatalError() on error. */ + static void +-dev_urandom_noraise(char *buffer, Py_ssize_t size) ++dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) + { + int fd; + Py_ssize_t n; +@@ -156,18 +162,56 @@ dev_urandom_python(char *buffer, Py_ssiz + { + int fd; + Py_ssize_t n; ++ struct stat st; + + if (size <= 0) + return 0; + +- Py_BEGIN_ALLOW_THREADS +- fd = open("/dev/urandom", O_RDONLY); +- Py_END_ALLOW_THREADS +- if (fd < 0) +- { +- PyErr_SetString(PyExc_NotImplementedError, +- "/dev/urandom (or equivalent) not found"); +- return -1; ++ if (urandom_cache.fd >= 0) { ++ /* Does the fd point to the same thing as before? (issue #21207) */ ++ if (fstat(urandom_cache.fd, &st) ++ || st.st_dev != urandom_cache.st_dev ++ || st.st_ino != urandom_cache.st_ino) { ++ /* Something changed: forget the cached fd (but don't close it, ++ since it probably points to something important for some ++ third-party code). */ ++ urandom_cache.fd = -1; ++ } ++ } ++ if (urandom_cache.fd >= 0) ++ fd = urandom_cache.fd; ++ else { ++ Py_BEGIN_ALLOW_THREADS ++ fd = open("/dev/urandom", O_RDONLY); ++ Py_END_ALLOW_THREADS ++ if (fd < 0) ++ { ++ if (errno == ENOENT || errno == ENXIO || ++ errno == ENODEV || errno == EACCES) ++ PyErr_SetString(PyExc_NotImplementedError, ++ "/dev/urandom (or equivalent) not found"); ++ else ++ PyErr_SetFromErrno(PyExc_OSError); ++ return -1; ++ } ++ if (urandom_cache.fd >= 0) { ++ /* urandom_fd was initialized by another thread while we were ++ not holding the GIL, keep it. */ ++ close(fd); ++ fd = urandom_cache.fd; ++ } ++ else { ++ if (fstat(fd, &st)) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ close(fd); ++ return -1; ++ } ++ else { ++ urandom_cache.fd = fd; ++ urandom_cache.st_dev = st.st_dev; ++ urandom_cache.st_ino = st.st_ino; ++ } ++ } + } + + Py_BEGIN_ALLOW_THREADS +@@ -191,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssiz + PyErr_Format(PyExc_RuntimeError, + "Failed to read %zi bytes from /dev/urandom", + size); +- close(fd); + return -1; + } +- close(fd); + return 0; + } ++ ++static void ++dev_urandom_close(void) ++{ ++ if (urandom_cache.fd >= 0) { ++ close(urandom_cache.fd); ++ urandom_cache.fd = -1; ++ } ++} ++ ++ + #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ + + /* Fill buffer with pseudo-random bytes generated by a linear congruent +@@ -300,8 +353,21 @@ _PyRandom_Init(void) + # ifdef __VMS + vms_urandom((unsigned char *)secret, secret_size, 0); + # else +- dev_urandom_noraise((char*)secret, secret_size); ++ dev_urandom_noraise((unsigned char*)secret, secret_size); + # endif + #endif + } + } ++ ++void ++_PyRandom_Fini(void) ++{ ++#ifdef MS_WINDOWS ++ if (hCryptProv) { ++ CryptReleaseContext(hCryptProv, 0); ++ hCryptProv = 0; ++ } ++#else ++ dev_urandom_close(); ++#endif ++} diff --git a/SOURCES/00219-pep466-fix-referenced-sslwrap.patch b/SOURCES/00219-pep466-fix-referenced-sslwrap.patch new file mode 100644 index 00000000..f8ccc909 --- /dev/null +++ b/SOURCES/00219-pep466-fix-referenced-sslwrap.patch @@ -0,0 +1,91 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1412221981 14400 +# Node ID 1a36d4e8cf4edfdc4c7d59a40075b8cf00e3ad3c +# Parent 222e0faa5fa9567f657f13fc78a60069142e09ae +fix sslwrap_simple (closes #22523) + +Thanks Alex Gaynor. + +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -969,16 +969,16 @@ def get_protocol_name(protocol_code): + # a replacement for the old socket.ssl function + + def sslwrap_simple(sock, keyfile=None, certfile=None): +- + """A replacement for the old socket.ssl function. Designed + for compability with Python 2.5 and earlier. Will disappear in + Python 3.0.""" +- + if hasattr(sock, "_sock"): + sock = sock._sock + +- ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE, +- PROTOCOL_SSLv23, None) ++ ctx = SSLContext(PROTOCOL_SSLv23) ++ if keyfile or certfile: ++ ctx.load_cert_chain(certfile, keyfile) ++ ssl_sock = ctx._wrap_socket(sock, server_side=False) + try: + sock.getpeername() + except socket_error: +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -94,6 +94,8 @@ class BasicTests(unittest.TestCase): + pass + else: + raise ++ ++ + def can_clear_options(): + # 0.9.8m or higher + return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) +@@ -2944,7 +2946,7 @@ def test_main(verbose=False): + if not os.path.exists(filename): + raise support.TestFailed("Can't read certificate file %r" % filename) + +- tests = [ContextTests, BasicSocketTests, SSLErrorTests] ++ tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] + + if support.is_resource_enabled('network'): + tests.append(NetworkedTests) +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -517,10 +517,12 @@ newPySSLSocket(PySSLContext *sslctx, PyS + self->socket_type = socket_type; + self->Socket = sock; + Py_INCREF(self->Socket); +- self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); +- if (self->ssl_sock == NULL) { +- Py_DECREF(self); +- return NULL; ++ if (ssl_sock != Py_None) { ++ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); ++ if (self->ssl_sock == NULL) { ++ Py_DECREF(self); ++ return NULL; ++ } + } + return self; + } +@@ -2931,8 +2933,12 @@ static int + + ssl = SSL_get_app_data(s); + assert(PySSLSocket_Check(ssl)); +- ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); +- Py_INCREF(ssl_socket); ++ if (ssl->ssl_sock == NULL) { ++ ssl_socket = Py_None; ++ } else { ++ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); ++ Py_INCREF(ssl_socket); ++ } + if (ssl_socket == Py_None) { + goto error; + } + diff --git a/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch b/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch new file mode 100644 index 00000000..77bdfe5e --- /dev/null +++ b/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch @@ -0,0 +1,673 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1416764565 21600 +# Node ID 1882157b298a164291d2b3a8b9525eb0902895f6 +# Parent 588ebc8fd3daf7307961cd614c4da9525bb67313 +allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection + +This is basically a backport of issues #9003 and #22366. + +diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst +--- a/Doc/library/httplib.rst ++++ b/Doc/library/httplib.rst +@@ -70,12 +70,25 @@ The module provides the following classe + *source_address* was added. + + +-.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]]) ++.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address, context, check_hostname]]]]]]) + + A subclass of :class:`HTTPConnection` that uses SSL for communication with +- secure servers. Default port is ``443``. *key_file* is the name of a PEM +- formatted file that contains your private key. *cert_file* is a PEM formatted +- certificate chain file. ++ secure servers. Default port is ``443``. If *context* is specified, it must ++ be a :class:`ssl.SSLContext` instance describing the various SSL options. ++ ++ *key_file* and *cert_file* are deprecated, please use ++ :meth:`ssl.SSLContext.load_cert_chain` instead, or let ++ :func:`ssl.create_default_context` select the system's trusted CA ++ certificates for you. ++ ++ Please read :ref:`ssl-security` for more information on best practices. ++ ++ .. note:: ++ If *context* is specified and has a :attr:`~ssl.SSLContext.verify_mode` ++ of either :data:`~ssl.CERT_OPTIONAL` or :data:`~ssl.CERT_REQUIRED`, then ++ by default *host* is matched against the host name(s) allowed by the ++ server's certificate. If you want to change that behaviour, you can ++ explicitly set *check_hostname* to False. + + .. warning:: + This does not do any verification of the server's certificate. +@@ -88,6 +101,9 @@ The module provides the following classe + .. versionchanged:: 2.7 + *source_address* was added. + ++ .. versionchanged:: 2.7.9 ++ *context* and *check_hostname* was added. ++ + + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) + +diff --git a/Lib/test/keycert2.pem b/Lib/test/keycert2.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/keycert2.pem +@@ -0,0 +1,31 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc ++PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK ++Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r ++s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI ++BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B ++EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf ++tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc ++JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky ++GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg ++wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz ++HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz ++i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l ++gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV ++d5rWoljEfdou ++-----END PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV ++BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u ++IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x ++NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD ++VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv ++dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF ++AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py ++YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP ++i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA ++AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB ++AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA ++QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74 ++El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7 ++-----END CERTIFICATE----- +diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/selfsigned_pythontestdotnet.pem +@@ -0,0 +1,16 @@ ++-----BEGIN CERTIFICATE----- ++MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV ++BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u ++IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv ++bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG ++A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo ++b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 ++aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ ++Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm ++Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv ++EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl ++bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM ++eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV ++HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 ++vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 ++-----END CERTIFICATE----- +diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py +--- a/Lib/test/test_urllib2.py ++++ b/Lib/test/test_urllib2.py +@@ -8,6 +8,11 @@ import StringIO + import urllib2 + from urllib2 import Request, OpenerDirector + ++try: ++ import ssl ++except ImportError: ++ ssl = None ++ + # XXX + # Request + # CacheFTPHandler (hard to write) +@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase): + for string, list in tests: + self.assertEqual(urllib2.parse_http_list(string), list) + ++ @unittest.skipUnless(ssl, "ssl module required") ++ def test_cafile_and_context(self): ++ context = ssl.create_default_context() ++ with self.assertRaises(ValueError): ++ urllib2.urlopen( ++ "https://localhost", cafile="/nonexistent/path", context=context ++ ) ++ + + def test_request_headers_dict(): + """ +diff --git a/Lib/urllib2.py b/Lib/urllib2.py +--- a/Lib/urllib2.py ++++ b/Lib/urllib2.py +@@ -109,6 +109,14 @@ try: + except ImportError: + from StringIO import StringIO + ++# check for SSL ++try: ++ import ssl ++except ImportError: ++ _have_ssl = False ++else: ++ _have_ssl = True ++ + from urllib import (unwrap, unquote, splittype, splithost, quote, + addinfourl, splitport, splittag, toBytes, + splitattr, ftpwrapper, splituser, splitpasswd, splitvalue) +@@ -120,11 +128,30 @@ from urllib import localhost, url2pathna + __version__ = sys.version[:3] + + _opener = None +-def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): ++def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, ++ cafile=None, capath=None, cadefault=False, context=None): + global _opener +- if _opener is None: +- _opener = build_opener() +- return _opener.open(url, data, timeout) ++ if cafile or capath or cadefault: ++ if context is not None: ++ raise ValueError( ++ "You can't pass both context and any of cafile, capath, and " ++ "cadefault" ++ ) ++ if not _have_ssl: ++ raise ValueError('SSL support not available') ++ context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, ++ cafile=cafile, ++ capath=capath) ++ https_handler = HTTPSHandler(context=context, check_hostname=True) ++ opener = build_opener(https_handler) ++ elif context: ++ https_handler = HTTPSHandler(context=context) ++ opener = build_opener(https_handler) ++ elif _opener is None: ++ _opener = opener = build_opener() ++ else: ++ opener = _opener ++ return opener.open(url, data, timeout) + + def install_opener(opener): + global _opener +@@ -1121,7 +1148,7 @@ class AbstractHTTPHandler(BaseHandler): + + return request + +- def do_open(self, http_class, req): ++ def do_open(self, http_class, req, **http_conn_args): + """Return an addinfourl object for the request, using http_class. + + http_class must implement the HTTPConnection API from httplib. +@@ -1135,7 +1162,8 @@ class AbstractHTTPHandler(BaseHandler): + if not host: + raise URLError('no host given') + +- h = http_class(host, timeout=req.timeout) # will parse host:port ++ # will parse host:port ++ h = http_class(host, timeout=req.timeout, **http_conn_args) + h.set_debuglevel(self._debuglevel) + + headers = dict(req.unredirected_hdrs) +@@ -1203,8 +1231,14 @@ class HTTPHandler(AbstractHTTPHandler): + if hasattr(httplib, 'HTTPS'): + class HTTPSHandler(AbstractHTTPHandler): + ++ def __init__(self, debuglevel=0, context=None, check_hostname=None): ++ AbstractHTTPHandler.__init__(self, debuglevel) ++ self._context = context ++ self._check_hostname = check_hostname ++ + def https_open(self, req): +- return self.do_open(httplib.HTTPSConnection, req) ++ return self.do_open(httplib.HTTPSConnection, req, ++ context=self._context, check_hostname=self._check_hostname) + + https_request = AbstractHTTPHandler.do_request_ + +diff -up Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx Python-2.7.5/Lib/test/test_urllib2_localnet.py +--- Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx 2015-03-30 10:13:48.351310552 +0200 ++++ Python-2.7.5/Lib/test/test_urllib2_localnet.py 2015-03-30 10:14:54.715713679 +0200 +@@ -1,5 +1,6 @@ + #!/usr/bin/env python + ++import os + import urlparse + import urllib2 + import BaseHTTPServer +@@ -11,6 +12,17 @@ from test import test_support + mimetools = test_support.import_module('mimetools', deprecated=True) + threading = test_support.import_module('threading') + ++try: ++ import ssl ++except ImportError: ++ ssl = None ++ ++here = os.path.dirname(__file__) ++# Self-signed cert file for 'localhost' ++CERT_localhost = os.path.join(here, 'keycert.pem') ++# Self-signed cert file for 'fakehostname' ++CERT_fakehostname = os.path.join(here, 'keycert2.pem') ++ + # Loopback http server infrastructure + + class LoopbackHttpServer(BaseHTTPServer.HTTPServer): +@@ -25,7 +37,7 @@ class LoopbackHttpServer(BaseHTTPServer. + + # Set the timeout of our listening socket really low so + # that we can stop the server easily. +- self.socket.settimeout(1.0) ++ self.socket.settimeout(0.1) + + def get_request(self): + """BaseHTTPServer method, overridden.""" +@@ -354,6 +366,19 @@ class TestUrlopen(BaseTestCase): + urllib2.install_opener(opener) + super(TestUrlopen, self).setUp() + ++ def urlopen(self, url, data=None, **kwargs): ++ l = [] ++ f = urllib2.urlopen(url, data, **kwargs) ++ try: ++ # Exercise various methods ++ l.extend(f.readlines(200)) ++ l.append(f.readline()) ++ l.append(f.read(1024)) ++ l.append(f.read()) ++ finally: ++ f.close() ++ return b"".join(l) ++ + def start_server(self, responses): + handler = GetRequestHandler(responses) + +@@ -364,6 +389,16 @@ class TestUrlopen(BaseTestCase): + handler.port = port + return handler + ++ def start_https_server(self, responses=None, **kwargs): ++ if not hasattr(urllib2, 'HTTPSHandler'): ++ self.skipTest('ssl support required') ++ from test.ssl_servers import make_https_server ++ if responses is None: ++ responses = [(200, [], b"we care a bit")] ++ handler = GetRequestHandler(responses) ++ server = make_https_server(self, handler_class=handler, **kwargs) ++ handler.port = server.port ++ return handler + + def test_redirection(self): + expected_response = 'We got here...' +@@ -434,6 +469,28 @@ class TestUrlopen(BaseTestCase): + finally: + self.server.stop() + ++ def test_https(self): ++ handler = self.start_https_server() ++ context = ssl.create_default_context(cafile=CERT_localhost) ++ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) ++ self.assertEqual(data, b"we care a bit") ++ ++ def test_https_with_cafile(self): ++ handler = self.start_https_server(certfile=CERT_localhost) ++ import ssl ++ # Good cert ++ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_localhost) ++ self.assertEqual(data, b"we care a bit") ++ # Bad cert ++ with self.assertRaises(urllib2.URLError) as cm: ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_fakehostname) ++ # Good cert, but mismatching hostname ++ handler = self.start_https_server(certfile=CERT_fakehostname) ++ with self.assertRaises(ssl.CertificateError) as cm: ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_fakehostname) + + def test_sending_headers(self): + handler = self.start_server([(200, [], "we don't care")]) +diff -up Python-2.7.5/Doc/library/urllib2.rst.ctx Python-2.7.5/Doc/library/urllib2.rst +--- Python-2.7.5/Doc/library/urllib2.rst.ctx 2015-03-30 10:20:15.958747076 +0200 ++++ Python-2.7.5/Doc/library/urllib2.rst 2015-03-30 10:30:46.172779366 +0200 +@@ -22,13 +22,10 @@ redirections, cookies and more. + The :mod:`urllib2` module defines the following functions: + + +-.. function:: urlopen(url[, data][, timeout]) ++.. function:: urlopen(url[, data[, timeout[, cafile[, capath[, cadefault[, context]]]]]) + + Open the URL *url*, which can be either a string or a :class:`Request` object. + +- .. warning:: +- HTTPS requests do not do any verification of the server's certificate. +- + *data* may be a string specifying additional data to send to the server, or + ``None`` if no such data is needed. Currently HTTP requests are the only ones + that use *data*; the HTTP request will be a POST instead of a GET when the +@@ -41,7 +38,19 @@ The :mod:`urllib2` module defines the fo + The optional *timeout* parameter specifies a timeout in seconds for blocking + operations like the connection attempt (if not specified, the global default + timeout setting will be used). This actually only works for HTTP, HTTPS and +- FTP connections. ++ FTP connections. ++ ++ If *context* is specified, it must be a :class:`ssl.SSLContext` instance ++ describing the various SSL options. See :class:`~httplib.HTTPSConnection` for ++ more details. ++ ++ The optional *cafile* and *capath* parameters specify a set of trusted CA ++ certificates for HTTPS requests. *cafile* should point to a single file ++ containing a bundle of CA certificates, whereas *capath* should point to a ++ directory of hashed certificate files. More information can be found in ++ :meth:`ssl.SSLContext.load_verify_locations`. ++ ++ The *cadefault* parameter is ignored. + + This function returns a file-like object with two additional methods: + +@@ -66,7 +75,10 @@ The :mod:`urllib2` module defines the fo + handled through the proxy. + + .. versionchanged:: 2.6 +- *timeout* was added. ++ *timeout* was added. ++ ++ .. versionchanged:: 2.7.9 ++ *cafile*, *capath*, *cadefault*, and *context* were added. + + + .. function:: install_opener(opener) +@@ -280,9 +292,13 @@ The following classes are provided: + A class to handle opening of HTTP URLs. + + +-.. class:: HTTPSHandler() ++.. class:: HTTPSHandler([debuglevel[, context[, check_hostname]]]) ++ ++ A class to handle opening of HTTPS URLs. *context* and *check_hostname* have ++ the same meaning as for :class:`httplib.HTTPSConnection`. + +- A class to handle opening of HTTPS URLs. ++ .. versionchanged:: 2.7.9 ++ *context* and *check_hostname* were added. + + + .. class:: FileHandler() +diff -up Python-2.7.5/Lib/httplib.py.ctx Python-2.7.5/Lib/httplib.py +--- Python-2.7.5/Lib/httplib.py.ctx 2015-03-30 10:19:52.551521393 +0200 ++++ Python-2.7.5/Lib/httplib.py 2015-03-30 10:30:05.045386751 +0200 +@@ -1159,21 +1159,44 @@ else: + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, +- source_address=None): ++ source_address=None, context=None, check_hostname=None): + HTTPConnection.__init__(self, host, port, strict, timeout, + source_address) + self.key_file = key_file + self.cert_file = cert_file ++ if context is None: ++ context = ssl.create_default_context() ++ will_verify = context.verify_mode != ssl.CERT_NONE ++ if check_hostname is None: ++ check_hostname = will_verify ++ elif check_hostname and not will_verify: ++ raise ValueError("check_hostname needs a SSL context with " ++ "either CERT_OPTIONAL or CERT_REQUIRED") ++ if key_file or cert_file: ++ context.load_cert_chain(cert_file, key_file) ++ self._context = context ++ self._check_hostname = check_hostname + + def connect(self): + "Connect to a host on a given (SSL) port." + +- sock = socket.create_connection((self.host, self.port), +- self.timeout, self.source_address) ++ HTTPConnection.connect(self) ++ + if self._tunnel_host: +- self.sock = sock +- self._tunnel() +- self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) ++ server_hostname = self._tunnel_host ++ else: ++ server_hostname = self.host ++ sni_hostname = server_hostname if ssl.HAS_SNI else None ++ ++ self.sock = self._context.wrap_socket(self.sock, ++ server_hostname=sni_hostname) ++ if not self._context.check_hostname and self._check_hostname: ++ try: ++ ssl.match_hostname(self.sock.getpeercert(), server_hostname) ++ except Exception: ++ self.sock.shutdown(socket.SHUT_RDWR) ++ self.sock.close() ++ raise + + __all__.append("HTTPSConnection") + +diff -up Python-2.7.5/Lib/test/test_httplib.py.ctx Python-2.7.5/Lib/test/test_httplib.py +--- Python-2.7.5/Lib/test/test_httplib.py.ctx 2015-03-30 10:19:12.905139139 +0200 ++++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 10:27:41.822017804 +0200 +@@ -1,6 +1,7 @@ + import httplib + import array + import httplib ++import os + import StringIO + import socket + import errno +@@ -10,6 +11,14 @@ TestCase = unittest.TestCase + + from test import test_support + ++here = os.path.dirname(__file__) ++# Self-signed cert file for 'localhost' ++CERT_localhost = os.path.join(here, 'keycert.pem') ++# Self-signed cert file for 'fakehostname' ++CERT_fakehostname = os.path.join(here, 'keycert2.pem') ++# Self-signed cert file for self-signed.pythontest.net ++CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') ++ + HOST = test_support.HOST + + class FakeSocket: +@@ -493,40 +502,147 @@ class TimeoutTest(TestCase): + httpConn.close() + + +-class HTTPSTimeoutTest(TestCase): ++class HTTPSTest(TestCase): + # XXX Here should be tests for HTTPS, there isn't any right now! ++ def setUp(self): ++ if not hasattr(httplib, 'HTTPSConnection'): ++ self.skipTest('ssl support required') ++ ++ def make_server(self, certfile): ++ from test.ssl_servers import make_https_server ++ return make_https_server(self, certfile=certfile) + + def test_attributes(self): +- # simple test to check it's storing it +- if hasattr(httplib, 'HTTPSConnection'): +- h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) +- self.assertEqual(h.timeout, 30) ++ # simple test to check it's storing the timeout ++ h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) ++ self.assertEqual(h.timeout, 30) ++ ++ def test_networked(self): ++ # Default settings: requires a valid cert from a trusted CA ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_networked_noverification(self): ++ # Switch off cert verification ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl._create_stdlib_context() ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, ++ context=context) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ self.assertIn('nginx', resp.getheader('server')) ++ ++ def test_networked_trusted_by_default_cert(self): ++ # Default settings: requires a valid cert from a trusted CA ++ test_support.requires('network') ++ with test_support.transient_internet('www.python.org'): ++ h = httplib.HTTPSConnection('www.python.org', 443) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ content_type = resp.getheader('content-type') ++ self.assertIn('text/html', content_type) ++ ++ def test_networked_good_cert(self): ++ # We feed the server's cert as a validating cert ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_selfsigned_pythontestdotnet) ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ server_string = resp.getheader('server') ++ self.assertIn('nginx', server_string) ++ ++ def test_networked_bad_cert(self): ++ # We feed a "CA" cert that is unrelated to the server's cert ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_localhost) ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_local_unknown_cert(self): ++ # The custom cert isn't known to the default trust bundle ++ import ssl ++ server = self.make_server(CERT_localhost) ++ h = httplib.HTTPSConnection('localhost', server.port) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_local_good_hostname(self): ++ # The (valid) cert validates the HTTP hostname ++ import ssl ++ server = self.make_server(CERT_localhost) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_localhost) ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) ++ h.request('GET', '/nonexistent') ++ resp = h.getresponse() ++ self.assertEqual(resp.status, 404) ++ ++ def test_local_bad_hostname(self): ++ # The (valid) cert doesn't validate the HTTP hostname ++ import ssl ++ server = self.make_server(CERT_fakehostname) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_fakehostname) ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) ++ with self.assertRaises(ssl.CertificateError): ++ h.request('GET', '/') ++ # Same with explicit check_hostname=True ++ h = httplib.HTTPSConnection('localhost', server.port, context=context, ++ check_hostname=True) ++ with self.assertRaises(ssl.CertificateError): ++ h.request('GET', '/') ++ # With check_hostname=False, the mismatching is ignored ++ h = httplib.HTTPSConnection('localhost', server.port, context=context, ++ check_hostname=False) ++ h.request('GET', '/nonexistent') ++ resp = h.getresponse() ++ self.assertEqual(resp.status, 404) + +- @unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available') + def test_host_port(self): + # Check invalid host_port + +- # Note that httplib does not accept user:password@ in the host-port. + for hp in ("www.python.org:abc", "user:password@www.python.org"): +- self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp) ++ self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) + +- for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", +- 8000), +- ("pypi.python.org:443", "pypi.python.org", 443), +- ("pypi.python.org", "pypi.python.org", 443), +- ("pypi.python.org:", "pypi.python.org", 443), +- ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)): +- http = httplib.HTTPS(hp) +- c = http._conn +- if h != c.host: +- self.fail("Host incorrectly parsed: %s != %s" % (h, c.host)) +- if p != c.port: +- self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) ++ for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", ++ "fe80::207:e9ff:fe9b", 8000), ++ ("www.python.org:443", "www.python.org", 443), ++ ("www.python.org:", "www.python.org", 443), ++ ("www.python.org", "www.python.org", 443), ++ ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), ++ ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", ++ 443)): ++ c = httplib.HTTPSConnection(hp) ++ self.assertEqual(h, c.host) ++ self.assertEqual(p, c.port) ++ + + ++@test_support.reap_threads + def test_main(verbose=None): + test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, +- HTTPSTimeoutTest, SourceAddressTest) ++ HTTPSTest, SourceAddressTest) + + if __name__ == '__main__': + test_main() +diff -up Python-2.7.5/Lib/test/test_ssl.py.ctx Python-2.7.5/Lib/test/test_ssl.py +--- Python-2.7.5/Lib/test/test_ssl.py.ctx 2015-03-30 10:18:55.677973042 +0200 ++++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-30 10:22:02.323772604 +0200 +@@ -14,7 +14,7 @@ import os + import errno + import pprint + import tempfile +-import urllib ++import urllib2 + import traceback + import weakref + import platform +@@ -2332,9 +2332,10 @@ else: + d1 = f.read() + d2 = '' + # now fetch the same data from the HTTPS server +- url = 'https://%s:%d/%s' % ( +- HOST, server.port, os.path.split(CERTFILE)[1]) +- f = urllib.urlopen(url) ++ url = 'https://localhost:%d/%s' % ( ++ server.port, os.path.split(CERTFILE)[1]) ++ context = ssl.create_default_context(cafile=CERTFILE) ++ f = urllib2.urlopen(url, context=context) + try: + dlen = f.info().getheader("content-length") + if dlen and (int(dlen) > 0): diff --git a/SOURCES/00222-add-2014-bit-dh-key.patch b/SOURCES/00222-add-2014-bit-dh-key.patch new file mode 100644 index 00000000..6a7838e0 --- /dev/null +++ b/SOURCES/00222-add-2014-bit-dh-key.patch @@ -0,0 +1,49 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1427947446 14400 +# Node ID 4f2391e866434a94ca6d87dff5ea01fcab91d08a +# Parent 5d88f653187203d85f4cfd4877f093af3919035b +replace 512 bit dh key with a 2014 bit one (closes #23844) + +Patch by Cédric Krier. + +diff --git a/Lib/test/dh1024.pem b/Lib/test/dh1024.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/dh1024.pem +@@ -0,0 +1,7 @@ ++-----BEGIN DH PARAMETERS----- ++MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt ++rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0 ++RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC ++-----END DH PARAMETERS----- ++ ++Generated with: openssl dhparam -out dh1024.pem 1024 +diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem +deleted file mode 100644 +--- a/Lib/test/dh512.pem ++++ /dev/null +@@ -1,9 +0,0 @@ +------BEGIN DH PARAMETERS----- +-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak +-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC +------END DH PARAMETERS----- +- +-These are the 512 bit DH parameters from "Assigned Number for SKIP Protocols" +-(http://www.skip-vpn.org/spec/numbers.html). +-See there for how they were generated. +-Note that g is not a generator, but this is not a problem since p is a safe prime. +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -66,7 +66,7 @@ BADKEY = data_file("badkey.pem") + NOKIACERT = data_file("nokia.pem") + NULLBYTECERT = data_file("nullbytecert.pem") + +-DHFILE = data_file("dh512.pem") ++DHFILE = data_file("dh1024.pem") + BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) + + + diff --git a/SOURCES/00223-pep476-verify-certs-by-default.patch b/SOURCES/00223-pep476-verify-certs-by-default.patch new file mode 100644 index 00000000..d62703f1 --- /dev/null +++ b/SOURCES/00223-pep476-verify-certs-by-default.patch @@ -0,0 +1,153 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1416798122 21600 +# Node ID fb83916c3ea12899569e88a7505469a90ab1f674 +# Parent c84f36a5f556867c2ec50453dc879a500032d377 +pep 476: verify certificates by default (#22417) + +diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst +--- a/Doc/library/httplib.rst ++++ b/Doc/library/httplib.rst +@@ -90,9 +90,6 @@ The module provides the following classe + server's certificate. If you want to change that behaviour, you can + explicitly set *check_hostname* to False. + +- .. warning:: +- This does not do any verification of the server's certificate. +- + .. versionadded:: 2.0 + + .. versionchanged:: 2.6 +@@ -104,6 +101,11 @@ The module provides the following classe + .. versionchanged:: 2.7.9 + *context* and *check_hostname* was added. + ++ This class now performs all the necessary certificate and hostname checks ++ by default. To revert to the previous, unverified, behavior ++ :func:`ssl._create_unverified_context` can be passed to the *context* ++ parameter. ++ + + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) + +diff --git a/Lib/httplib.py b/Lib/httplib.py +--- a/Lib/httplib.py ++++ b/Lib/httplib.py +@@ -1193,7 +1193,7 @@ else: + self.key_file = key_file + self.cert_file = cert_file + if context is None: +- context = ssl.create_default_context() ++ context = ssl._create_default_https_context() + will_verify = context.verify_mode != ssl.CERT_NONE + if check_hostname is None: + check_hostname = will_verify +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -427,8 +427,7 @@ def create_default_context(purpose=Purpo + context.load_default_certs(purpose) + return context + +- +-def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, ++def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, + check_hostname=False, purpose=Purpose.SERVER_AUTH, + certfile=None, keyfile=None, + cafile=None, capath=None, cadata=None): +@@ -469,6 +468,14 @@ def _create_stdlib_context(protocol=PROT + + return context + ++# Used by http.client if no context is explicitly passed. ++_create_default_https_context = create_default_context ++ ++ ++# Backwards compatibility alias, even though it's not a public name. ++_create_stdlib_context = _create_unverified_context ++ ++ + class SSLSocket(socket): + """This class implements a subtype of socket.socket that wraps + the underlying OS socket in an SSL context when necessary, and +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1,10 +1,9 @@ + import httplib + import array +-import httplib +-import os + import StringIO + import socket + import errno ++import os + + import unittest + TestCase = unittest.TestCase +diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -5,6 +5,7 @@ import urllib2 + import BaseHTTPServer + import unittest + import hashlib ++import ssl + + from test import test_support + +@@ -562,15 +563,37 @@ class TestUrlopen(BaseTestCase): + cafile=CERT_localhost) + self.assertEqual(data, b"we care a bit") + # Bad cert +- with self.assertRaises(urllib2.URLError) as cm: ++ with self.assertRaises(urllib2.URLError): + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) + # Good cert, but mismatching hostname + handler = self.start_https_server(certfile=CERT_fakehostname) +- with self.assertRaises(ssl.CertificateError) as cm: ++ with self.assertRaises(ssl.CertificateError): + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) + ++ def test_https_with_cadefault(self): ++ handler = self.start_https_server(certfile=CERT_localhost) ++ # Self-signed cert should fail verification with system certificate store ++ with self.assertRaises(urllib2.URLError): ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cadefault=True) ++ ++ def test_https_sni(self): ++ if ssl is None: ++ self.skipTest("ssl module required") ++ if not ssl.HAS_SNI: ++ self.skipTest("SNI support required in OpenSSL") ++ sni_name = [None] ++ def cb_sni(ssl_sock, server_name, initial_context): ++ sni_name[0] = server_name ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.set_servername_callback(cb_sni) ++ handler = self.start_https_server(context=context, certfile=CERT_localhost) ++ context = ssl.create_default_context(cafile=CERT_localhost) ++ self.urlopen("https://localhost:%s" % handler.port, context=context) ++ self.assertEqual(sni_name[0], "localhost") ++ + def test_sending_headers(self): + handler = self.start_server([(200, [], "we don't care")]) + +diff -up Python-2.7.5/Doc/library/xmlrpclib.rst.ver Python-2.7.5/Doc/library/xmlrpclib.rst +--- Python-2.7.5/Doc/library/xmlrpclib.rst.ver 2015-03-30 13:59:29.243493601 +0200 ++++ Python-2.7.5/Doc/library/xmlrpclib.rst 2015-03-30 14:03:40.509532180 +0200 +@@ -34,6 +34,10 @@ between conformable Python objects and X + constructed data. If you need to parse untrusted or unauthenticated data see + :ref:`xml-vulnerabilities`. + ++.. versionchanged:: 2.7.9 ++ ++ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate ++ and hostname checks by default + + .. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) + diff --git a/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch b/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch new file mode 100644 index 00000000..1b68ac04 --- /dev/null +++ b/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch @@ -0,0 +1,103 @@ +diff -up Python-2.7.5/Lib/ssl.py.cert Python-2.7.5/Lib/ssl.py +--- Python-2.7.5/Lib/ssl.py.cert 2015-03-30 14:52:12.172241615 +0200 ++++ Python-2.7.5/Lib/ssl.py 2015-03-30 15:16:49.168185354 +0200 +@@ -466,8 +466,27 @@ def _create_unverified_context(protocol= + + return context + ++_cert_verification_config = '/etc/python/cert-verification.cfg' ++ ++def _get_verify_status(protocol): ++ context_factory = { ++ 'platform_default': _create_unverified_context, ++ 'enable': create_default_context, ++ 'disable': _create_unverified_context ++ } ++ import ConfigParser ++ try: ++ config = ConfigParser.RawConfigParser() ++ config.read(_cert_verification_config) ++ status = config.get(protocol, 'verify') ++ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): ++ status = 'platform_default' ++ default = context_factory.get('platform_default') ++ return context_factory.get(status, default) ++ ++ + # Used by http.client if no context is explicitly passed. +-_create_default_https_context = create_default_context ++_create_default_https_context = _get_verify_status('https') + + + # Backwards compatibility alias, even though it's not a public name. +diff -up Python-2.7.5/Lib/test/test_httplib.py.cert Python-2.7.5/Lib/test/test_httplib.py +--- Python-2.7.5/Lib/test/test_httplib.py.cert 2015-03-30 16:45:30.738794461 +0200 ++++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 16:54:48.065062351 +0200 +@@ -516,12 +516,24 @@ class HTTPSTest(TestCase): + h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) + self.assertEqual(h.timeout, 30) + ++ def test_networked_default(self): ++ # specific to RHEL ++ # Default settings: doesnt requires a valid cert from a trusted CA ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ self.assertIn('nginx', resp.getheader('server')) ++ ++ # We have to pass safe context to test cert verification ++ # RHEL by default disable cert verification + def test_networked(self): +- # Default settings: requires a valid cert from a trusted CA + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): +- h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') +@@ -542,8 +554,10 @@ class HTTPSTest(TestCase): + def test_networked_trusted_by_default_cert(self): + # Default settings: requires a valid cert from a trusted CA + test_support.requires('network') ++ import ssl + with test_support.transient_internet('www.python.org'): +- h = httplib.HTTPSConnection('www.python.org', 443) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('www.python.org', 443, context=context) + h.request('GET', '/') + resp = h.getresponse() + content_type = resp.getheader('content-type') +@@ -579,7 +592,8 @@ class HTTPSTest(TestCase): + # The custom cert isn't known to the default trust bundle + import ssl + server = self.make_server(CERT_localhost) +- h = httplib.HTTPSConnection('localhost', server.port) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') +@@ -624,6 +638,9 @@ class HTTPSTest(TestCase): + for hp in ("www.python.org:abc", "user:password@www.python.org"): + self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) + ++ import ssl ++ context = ssl.create_default_context() ++ + for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", + "fe80::207:e9ff:fe9b", 8000), + ("www.python.org:443", "www.python.org", 443), +@@ -632,7 +648,7 @@ class HTTPSTest(TestCase): + ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), + ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", + 443)): +- c = httplib.HTTPSConnection(hp) ++ c = httplib.HTTPSConnection(hp, context=context) + self.assertEqual(h, c.host) + self.assertEqual(p, c.port) + diff --git a/SOURCES/00225-cprofile-sort-option.patch b/SOURCES/00225-cprofile-sort-option.patch new file mode 100644 index 00000000..13943bff --- /dev/null +++ b/SOURCES/00225-cprofile-sort-option.patch @@ -0,0 +1,25 @@ +diff -up Python-2.7.5/Lib/cProfile.py.sort Python-2.7.5/Lib/cProfile.py +--- Python-2.7.5/Lib/cProfile.py.sort 2015-02-09 12:45:46.525657065 +0100 ++++ Python-2.7.5/Lib/cProfile.py 2015-02-09 12:45:05.266316315 +0100 +@@ -161,7 +161,7 @@ def label(code): + # ____________________________________________________________ + + def main(): +- import os, sys ++ import os, pstats, sys + from optparse import OptionParser + usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..." + parser = OptionParser(usage=usage) +@@ -169,8 +169,9 @@ def main(): + parser.add_option('-o', '--outfile', dest="outfile", + help="Save stats to ", default=None) + parser.add_option('-s', '--sort', dest="sort", +- help="Sort order when printing to stdout, based on pstats.Stats class", +- default=-1) ++ help="Sort order when printing to stdout, based on pstats.Stats class", ++ default=-1, ++ choices=pstats.Stats.sort_arg_dict_default.keys()) + + if not sys.argv[1:]: + parser.print_usage() + diff --git a/SOURCES/00227-accept-none-keyfile-loadcertchain.patch b/SOURCES/00227-accept-none-keyfile-loadcertchain.patch new file mode 100644 index 00000000..39d90732 --- /dev/null +++ b/SOURCES/00227-accept-none-keyfile-loadcertchain.patch @@ -0,0 +1,78 @@ +From c1f4979e7019f6c1ce9e5a02c2e3f8ca146645bc Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Mon, 11 Jul 2016 14:20:01 +0200 +Subject: [PATCH] Allow the keyfile argument of SSLContext.load_cert_chain to + be set to None + +--- + Modules/_ssl.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index 38eba1d..1786afd 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -2445,8 +2445,8 @@ static PyObject * + load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) + { + char *kwlist[] = {"certfile", "keyfile", "password", NULL}; +- PyObject *password = NULL; +- char *certfile_bytes = NULL, *keyfile_bytes = NULL; ++ PyObject *keyfile = NULL, *keyfile_bytes = NULL, *password = NULL; ++ char *certfile_bytes = NULL; + pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback; + void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata; + _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; +@@ -2455,11 +2455,27 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) + errno = 0; + ERR_clear_error(); + if (!PyArg_ParseTupleAndKeywords(args, kwds, +- "et|etO:load_cert_chain", kwlist, ++ "et|OO:load_cert_chain", kwlist, + Py_FileSystemDefaultEncoding, &certfile_bytes, +- Py_FileSystemDefaultEncoding, &keyfile_bytes, +- &password)) ++ &keyfile, &password)) + return NULL; ++ ++ if (keyfile && keyfile != Py_None) { ++ if (PyString_Check(keyfile)) { ++ Py_INCREF(keyfile); ++ keyfile_bytes = keyfile; ++ } else { ++ PyObject *u = PyUnicode_FromObject(keyfile); ++ if (!u) ++ goto error; ++ keyfile_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!keyfile_bytes) ++ goto error; ++ } ++ } ++ + if (password && password != Py_None) { + if (PyCallable_Check(password)) { + pw_info.callable = password; +@@ -2489,7 +2505,7 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) + } + PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); + r = SSL_CTX_use_PrivateKey_file(self->ctx, +- keyfile_bytes ? keyfile_bytes : certfile_bytes, ++ keyfile_bytes ? PyBytes_AS_STRING(keyfile_bytes) : certfile_bytes, + SSL_FILETYPE_PEM); + PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); + if (r != 1) { +@@ -2521,8 +2537,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) + error: + SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); ++ Py_XDECREF(keyfile_bytes); + PyMem_Free(pw_info.password); +- PyMem_Free(keyfile_bytes); + PyMem_Free(certfile_bytes); + return NULL; + } +-- +2.7.4 + diff --git a/SOURCES/00228-backport-ssl-version.patch b/SOURCES/00228-backport-ssl-version.patch new file mode 100644 index 00000000..40ac04c5 --- /dev/null +++ b/SOURCES/00228-backport-ssl-version.patch @@ -0,0 +1,260 @@ + +# HG changeset patch +# User Alex Gaynor +# Date 1409862802 25200 +# Node ID 16c86a6bdbe2a545dd2de02dc9f347c2b3ae7220 +# Parent f17ab9fed3b03191df975ecdde2cc07cee915319 +Issue #20421: Add a .version() method to SSL sockets exposing the actual protocol version in use. + +Backport from default. + +diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst +--- a/Doc/library/ssl.rst ++++ b/Doc/library/ssl.rst +@@ -867,10 +867,10 @@ SSL sockets also have the following addi + + .. method:: SSLSocket.selected_npn_protocol() + +- Returns the protocol that was selected during the TLS/SSL handshake. If +- :meth:`SSLContext.set_npn_protocols` was not called, or if the other party +- does not support NPN, or if the handshake has not yet happened, this will +- return ``None``. ++ Returns the higher-level protocol that was selected during the TLS/SSL ++ handshake. If :meth:`SSLContext.set_npn_protocols` was not called, or ++ if the other party does not support NPN, or if the handshake has not yet ++ happened, this will return ``None``. + + .. versionadded:: 2.7.9 + +@@ -882,6 +882,16 @@ SSL sockets also have the following addi + returned socket should always be used for further communication with the + other side of the connection, rather than the original socket. + ++.. method:: SSLSocket.version() ++ ++ Return the actual SSL protocol version negotiated by the connection ++ as a string, or ``None`` is no secure connection is established. ++ As of this writing, possible return values include ``"SSLv2"``, ++ ``"SSLv3"``, ``"TLSv1"``, ``"TLSv1.1"`` and ``"TLSv1.2"``. ++ Recent OpenSSL versions may define more return values. ++ ++ .. versionadded:: 3.5 ++ + .. attribute:: SSLSocket.context + + The :class:`SSLContext` object this SSL socket is tied to. If the SSL +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -862,6 +862,15 @@ class SSLSocket(socket): + return None + return self._sslobj.tls_unique_cb() + ++ def version(self): ++ """ ++ Return a string identifying the protocol version used by the ++ current SSL channel, or None if there is no established channel. ++ """ ++ if self._sslobj is None: ++ return None ++ return self._sslobj.version() ++ + + def wrap_socket(sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1904,7 +1904,8 @@ else: + 'compression': s.compression(), + 'cipher': s.cipher(), + 'peercert': s.getpeercert(), +- 'client_npn_protocol': s.selected_npn_protocol() ++ 'client_npn_protocol': s.selected_npn_protocol(), ++ 'version': s.version(), + }) + s.close() + stats['server_npn_protocols'] = server.selected_protocols +@@ -1912,6 +1913,13 @@ else: + + def try_protocol_combo(server_protocol, client_protocol, expect_success, + certsreqs=None, server_options=0, client_options=0): ++ """ ++ Try to SSL-connect using *client_protocol* to *server_protocol*. ++ If *expect_success* is true, assert that the connection succeeds, ++ if it's false, assert that the connection fails. ++ Also, if *expect_success* is a string, assert that it is the protocol ++ version actually used by the connection. ++ """ + if certsreqs is None: + certsreqs = ssl.CERT_NONE + certtype = { +@@ -1941,8 +1949,8 @@ else: + ctx.load_cert_chain(CERTFILE) + ctx.load_verify_locations(CERTFILE) + try: +- server_params_test(client_context, server_context, +- chatty=False, connectionchatty=False) ++ stats = server_params_test(client_context, server_context, ++ chatty=False, connectionchatty=False) + # Protocol mismatch can result in either an SSLError, or a + # "Connection reset by peer" error. + except ssl.SSLError: +@@ -1957,6 +1965,10 @@ else: + "Client protocol %s succeeded with server protocol %s!" + % (ssl.get_protocol_name(client_protocol), + ssl.get_protocol_name(server_protocol))) ++ elif (expect_success is not True ++ and expect_success != stats['version']): ++ raise AssertionError("version mismatch: expected %r, got %r" ++ % (expect_success, stats['version'])) + + + class ThreadedTests(unittest.TestCase): +@@ -2186,17 +2198,17 @@ else: + sys.stdout.write( + " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" + % str(x)) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3') + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1') + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + + # Server with specific SSL options + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, +@@ -2213,9 +2225,9 @@ else: + """Connecting to an SSLv3 server with various client options""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) +- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3') ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False, +@@ -2223,7 +2235,7 @@ else: + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) + if no_sslv2_implies_sslv3_hello(): + # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs +- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True, ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, 'SSLv3', + client_options=ssl.OP_NO_SSLv2) + + @skip_if_broken_ubuntu_ssl +@@ -2231,9 +2243,9 @@ else: + """Connecting to a TLSv1 server with various client options""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1') ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) +@@ -2248,14 +2260,14 @@ else: + Testing against older TLS versions.""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_TLSv1_1) + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) + +@@ -2268,7 +2280,7 @@ else: + Testing against older TLS versions.""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True, ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2', + server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2, + client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,) + if hasattr(ssl, 'PROTOCOL_SSLv2'): +@@ -2277,7 +2289,7 @@ else: + try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_TLSv1_2) + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2') + try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False) +@@ -2619,6 +2631,21 @@ else: + s.connect((HOST, server.port)) + self.assertIn("no shared cipher", str(server.conn_errors[0])) + ++ def test_version_basic(self): ++ """ ++ Basic tests for SSLSocket.version(). ++ More tests are done in the test_protocol_*() methods. ++ """ ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ with ThreadedEchoServer(CERTFILE, ++ ssl_version=ssl.PROTOCOL_TLSv1, ++ chatty=False) as server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ self.assertIs(s.version(), None) ++ s.connect((HOST, server.port)) ++ self.assertEqual(s.version(), "TLSv1") ++ self.assertIs(s.version(), None) ++ + @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") + def test_default_ecdh_curve(self): + # Issue #21015: elliptic curve-based Diffie Hellman key exchange +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -1384,6 +1384,18 @@ static PyObject *PySSL_cipher (PySSLSock + return NULL; + } + ++static PyObject *PySSL_version(PySSLSocket *self) ++{ ++ const char *version; ++ ++ if (self->ssl == NULL) ++ Py_RETURN_NONE; ++ version = SSL_get_version(self->ssl); ++ if (!strcmp(version, "unknown")) ++ Py_RETURN_NONE; ++ return PyUnicode_FromString(version); ++} ++ + #ifdef OPENSSL_NPN_NEGOTIATED + static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { + const unsigned char *out; +@@ -1907,6 +1919,7 @@ static PyMethodDef PySSLMethods[] = { + {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, + PySSL_peercert_doc}, + {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, ++ {"version", (PyCFunction)PySSL_version, METH_NOARGS}, + #ifdef OPENSSL_NPN_NEGOTIATED + {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, + #endif + diff --git a/SOURCES/00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch b/SOURCES/00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch new file mode 100644 index 00000000..2fee0c05 --- /dev/null +++ b/SOURCES/00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch @@ -0,0 +1,48 @@ +From a1d7acf899fccd0eda10e011e2d11d1d81c2d9e6 Mon Sep 17 00:00:00 2001 +From: Robert Kuska +Date: Wed, 9 Mar 2016 20:16:17 +0100 +Subject: [PATCH] Expect a failure when trying to connect with SSLv2 client to + SSLv23 server. Default value of options in tests enchanced to reflect SSLv2 + being disabled + +--- + Lib/test/test_ssl.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 11122db..b2ba186 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -691,7 +691,7 @@ class ContextTests(unittest.TestCase): + @skip_if_broken_ubuntu_ssl + def test_options(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- self.assertEqual(ssl.OP_ALL, ctx.options) ++ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options) + ctx.options |= ssl.OP_NO_SSLv2 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, + ctx.options) +@@ -2152,17 +2152,17 @@ else: + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) + # SSLv23 client with specific SSL options + if no_sslv2_implies_sslv3_hello(): + # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_SSLv2) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_SSLv3) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_TLSv1) + + @skip_if_broken_ubuntu_ssl +-- +2.5.0 + diff --git a/SOURCES/00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch b/SOURCES/00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch new file mode 100644 index 00000000..b6b52b3a --- /dev/null +++ b/SOURCES/00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch @@ -0,0 +1,18 @@ +diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py +index 413889a..fb312aa 100644 +--- a/Lib/test/test_thread.py ++++ b/Lib/test/test_thread.py +@@ -237,7 +237,12 @@ class TestForkInThread(unittest.TestCase): + if pid == 0: # child + os.close(self.read_fd) + os.write(self.write_fd, "OK") +- sys.exit(0) ++ # Exiting the thread normally in the child process can leave ++ # any additional threads (such as the one started by ++ # importing _tkinter) still running, and this can prevent ++ # the half-zombie child process from being cleaned up. See ++ # Issue #26456. ++ os._exit(0) + else: # parent + os.close(self.write_fd) + diff --git a/SOURCES/00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch b/SOURCES/00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch new file mode 100644 index 00000000..3355ce2b --- /dev/null +++ b/SOURCES/00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch @@ -0,0 +1,11 @@ +diff -up Python-2.7.5/Modules/_hashopenssl.c.digest Python-2.7.5/Modules/_hashopenssl.c +--- Python-2.7.5/Modules/_hashopenssl.c.digest 2016-01-05 10:53:02.947312688 +0100 ++++ Python-2.7.5/Modules/_hashopenssl.c 2016-01-05 10:53:15.504431960 +0100 +@@ -984,6 +984,7 @@ init_hashlib(void) + SSL_load_error_strings(); + SSL_library_init(); + ERR_load_crypto_strings(); ++ OpenSSL_add_all_digests(); + + Py_TYPE(&EVPtype) = &PyType_Type; + if (PyType_Ready(&EVPtype) < 0) diff --git a/SOURCES/00232-man-page-date-macro-removal.patch b/SOURCES/00232-man-page-date-macro-removal.patch new file mode 100644 index 00000000..c79aed68 --- /dev/null +++ b/SOURCES/00232-man-page-date-macro-removal.patch @@ -0,0 +1,9 @@ +diff -r 62e3b7af0697 -r db8d7f376d24 Misc/python.man +--- a/Misc/python.man Mon Mar 21 10:38:58 2016 +0100 ++++ b/Misc/python.man Mon Mar 21 13:54:28 2016 +0100 +@@ -1,4 +1,4 @@ +-.TH PYTHON "1" "$Date$" ++.TH PYTHON "1" + + .\" To view this file while editing, run it through groff: + .\" groff -Tascii -man python.man | less diff --git a/SOURCES/00233-Computed-Goto-dispatch.patch b/SOURCES/00233-Computed-Goto-dispatch.patch new file mode 100644 index 00000000..7b4c5fef --- /dev/null +++ b/SOURCES/00233-Computed-Goto-dispatch.patch @@ -0,0 +1,2274 @@ +From 66818f47df1e37b105fd42d6cbaa756c4d72393c Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Wed, 30 Mar 2016 15:54:29 +0200 +Subject: [PATCH] Computed Goto dispatch for Python2 + +--- + Include/opcode.h | 9 + + Makefile.pre.in | 15 + + Python/ceval.c | 770 +++++++++++++++++++++++++++++++------------- + Python/makeopcodetargets.py | 45 +++ + Python/opcode_targets.h | 258 +++++++++++++++ + configure | 81 +++++ + configure.ac | 51 +++ + pyconfig.h.in | 6 + + 8 files changed, 1005 insertions(+), 230 deletions(-) + +diff --git a/Include/opcode.h b/Include/opcode.h +index 9764109..9ed5487 100644 +--- a/Include/opcode.h ++++ b/Include/opcode.h +@@ -37,12 +37,21 @@ extern "C" { + + #define SLICE 30 + /* Also uses 31-33 */ ++#define SLICE_1 31 ++#define SLICE_2 32 ++#define SLICE_3 33 + + #define STORE_SLICE 40 + /* Also uses 41-43 */ ++#define STORE_SLICE_1 41 ++#define STORE_SLICE_2 42 ++#define STORE_SLICE_3 43 + + #define DELETE_SLICE 50 + /* Also uses 51-53 */ ++#define DELETE_SLICE_1 51 ++#define DELETE_SLICE_2 52 ++#define DELETE_SLICE_3 53 + + #define STORE_MAP 54 + #define INPLACE_ADD 55 +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 4ee61f6..611f63a 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -299,6 +299,16 @@ ASDLGEN= $(srcdir)/Parser/asdl_c.py + + ########################################################################## + # Python ++ ++OPCODETARGETS_H= \ ++ $(srcdir)/Python/opcode_targets.h ++ ++OPCODETARGETGEN= \ ++ $(srcdir)/Python/makeopcodetargets.py ++ ++OPCODETARGETGEN_FILES= \ ++ $(OPCODETARGETGEN) $(srcdir)/Lib/opcode.py ++ + PYTHON_OBJS= \ + Python/_warnings.o \ + Python/Python-ast.o \ +@@ -648,6 +658,11 @@ Objects/bytearrayobject.o: $(srcdir)/Objects/bytearrayobject.c \ + Objects/stringobject.o: $(srcdir)/Objects/stringobject.c \ + $(STRINGLIB_HEADERS) + ++$(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) ++ $(OPCODETARGETGEN) $(OPCODETARGETS_H) ++ ++Python/ceval.o: $(OPCODETARGETS_H) ++ + Python/formatter_unicode.o: $(srcdir)/Python/formatter_unicode.c \ + $(STRINGLIB_HEADERS) + +diff --git a/Python/ceval.c b/Python/ceval.c +index 8c6f8d7..67d1576 100644 +--- a/Python/ceval.c ++++ b/Python/ceval.c +@@ -757,6 +757,99 @@ PyEval_EvalFrame(PyFrameObject *f) { + PyObject * + PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + { ++#ifdef DYNAMIC_EXECUTION_PROFILE ++ #undef USE_COMPUTED_GOTOS ++#endif ++#ifdef HAVE_COMPUTED_GOTOS ++ #ifndef USE_COMPUTED_GOTOS ++ #define USE_COMPUTED_GOTOS 1 ++ #endif ++#else ++ #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS ++ #error "Computed gotos are not supported on this compiler." ++ #endif ++ #undef USE_COMPUTED_GOTOS ++ #define USE_COMPUTED_GOTOS 0 ++#endif ++#if USE_COMPUTED_GOTOS ++/* Import the static jump table */ ++#include "opcode_targets.h" ++ ++ /* This macro is used when several opcodes defer to the same implementation ++ (e.g. SETUP_LOOP, SETUP_FINALLY) */ ++#define TARGET_WITH_IMPL(op, impl) \ ++ TARGET_##op: \ ++ opcode = op; \ ++ oparg = NEXTARG(); \ ++ case op: \ ++ goto impl; \ ++ ++#define TARGET_WITH_IMPL_NOARG(op, impl) \ ++ TARGET_##op: \ ++ opcode = op; \ ++ case op: \ ++ goto impl; \ ++ ++#define TARGET_NOARG(op) \ ++ TARGET_##op: \ ++ opcode = op; \ ++ case op: \ ++ ++#define TARGET(op) \ ++ TARGET_##op: \ ++ opcode = op; \ ++ oparg = NEXTARG(); \ ++ case op:\ ++ ++#define DISPATCH() \ ++ { \ ++ int _tick = _Py_Ticker - 1; \ ++ _Py_Ticker = _tick; \ ++ if (_tick >= 0) { \ ++ FAST_DISPATCH(); \ ++ } \ ++ continue; \ ++ } ++ ++#ifdef LLTRACE ++#define FAST_DISPATCH() \ ++ { \ ++ if (!lltrace && !_Py_TracingPossible) { \ ++ f->f_lasti = INSTR_OFFSET(); \ ++ goto *opcode_targets[*next_instr++]; \ ++ } \ ++ goto fast_next_opcode; \ ++ } ++#else ++#define FAST_DISPATCH() { \ ++ if (!_Py_TracingPossible) { \ ++ f->f_lasti = INSTR_OFFSET(); \ ++ goto *opcode_targets[*next_instr++]; \ ++ } \ ++ goto fast_next_opcode;\ ++} ++#endif ++ ++#else ++#define TARGET(op) \ ++ case op: ++#define TARGET_WITH_IMPL(op, impl) \ ++ /* silence compiler warnings about `impl` unused */ \ ++ if (0) goto impl; ++ case op:\ ++ ++#define TARGET_NOARG(op) \ ++ case op:\ ++ ++#define TARGET_WITH_IMPL_NOARG(op, impl) \ ++ if (0) goto impl; \ ++ case op:\ ++ ++#define DISPATCH() continue ++#define FAST_DISPATCH() goto fast_next_opcode ++#endif ++ ++ + #ifdef DXPAIRS + int lastopcode = 0; + #endif +@@ -874,14 +967,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + counter updates for both opcodes. + */ + +-#ifdef DYNAMIC_EXECUTION_PROFILE ++// Next opcode prediction is also enabled for Computed Gotos as well. ++#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS + #define PREDICT(op) if (0) goto PRED_##op ++#define PREDICTED(op) PRED_##op: ++#define PREDICTED_WITH_ARG(op) PRED_##op: + #else + #define PREDICT(op) if (*next_instr == op) goto PRED_##op +-#endif +- + #define PREDICTED(op) PRED_##op: next_instr++ + #define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 ++#endif ++ + + /* Stack manipulation macros */ + +@@ -1179,55 +1275,71 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + + /* case STOP_CODE: this is an error! */ + +- case NOP: +- goto fast_next_opcode; ++ TARGET_NOARG(NOP) ++ { ++ FAST_DISPATCH(); ++ } ++ TARGET(LOAD_FAST) ++ { + +- case LOAD_FAST: + x = GETLOCAL(oparg); + if (x != NULL) { + Py_INCREF(x); + PUSH(x); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + format_exc_check_arg(PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_varnames, oparg)); + break; + +- case LOAD_CONST: ++ } ++ ++ TARGET(LOAD_CONST) ++ { + x = GETITEM(consts, oparg); + Py_INCREF(x); + PUSH(x); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + + PREDICTED_WITH_ARG(STORE_FAST); +- case STORE_FAST: ++ TARGET(STORE_FAST) ++ { + v = POP(); + SETLOCAL(oparg, v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case POP_TOP: ++ TARGET_NOARG(POP_TOP) ++ { + v = POP(); + Py_DECREF(v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case ROT_TWO: ++ TARGET_NOARG(ROT_TWO) ++ { + v = TOP(); + w = SECOND(); + SET_TOP(w); + SET_SECOND(v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case ROT_THREE: ++ TARGET_NOARG(ROT_THREE) ++ { + v = TOP(); + w = SECOND(); + x = THIRD(); + SET_TOP(w); + SET_SECOND(x); + SET_THIRD(v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case ROT_FOUR: ++ TARGET_NOARG(ROT_FOUR) ++ { + u = TOP(); + v = SECOND(); + w = THIRD(); +@@ -1236,15 +1348,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + SET_SECOND(w); + SET_THIRD(x); + SET_FOURTH(u); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case DUP_TOP: ++ TARGET_NOARG(DUP_TOP) ++ { + v = TOP(); + Py_INCREF(v); + PUSH(v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + +- case DUP_TOPX: ++ TARGET(DUP_TOPX) ++ { + if (oparg == 2) { + x = TOP(); + Py_INCREF(x); +@@ -1253,7 +1369,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + STACKADJ(2); + SET_TOP(x); + SET_SECOND(w); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } else if (oparg == 3) { + x = TOP(); + Py_INCREF(x); +@@ -1265,84 +1381,100 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + SET_TOP(x); + SET_SECOND(w); + SET_THIRD(v); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + Py_FatalError("invalid argument to DUP_TOPX" + " (bytecode corruption?)"); + /* Never returns, so don't bother to set why. */ + break; ++ } + +- case UNARY_POSITIVE: ++ TARGET_NOARG(UNARY_POSITIVE) ++ { + v = TOP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case UNARY_NEGATIVE: ++ TARGET_NOARG( UNARY_NEGATIVE) ++ { + v = TOP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case UNARY_NOT: ++ TARGET_NOARG(UNARY_NOT) ++ { + v = TOP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + SET_TOP(Py_True); +- continue; ++ DISPATCH(); + } + else if (err > 0) { + Py_INCREF(Py_False); + SET_TOP(Py_False); + err = 0; +- continue; ++ DISPATCH(); + } + STACKADJ(-1); + break; ++ } + +- case UNARY_CONVERT: ++ TARGET_NOARG(UNARY_CONVERT) ++ { + v = TOP(); + x = PyObject_Repr(v); + Py_DECREF(v); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case UNARY_INVERT: ++ TARGET_NOARG(UNARY_INVERT) ++ { + v = TOP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_POWER: ++ TARGET_NOARG(BINARY_POWER) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_MULTIPLY: ++ TARGET_NOARG(BINARY_MULTIPLY) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if(x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_DIVIDE: ++ TARGET_NOARG(BINARY_DIVIDE) ++ { + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); +@@ -1350,32 +1482,37 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; + } +- /* -Qnew is in effect: fall through to +- BINARY_TRUE_DIVIDE */ +- case BINARY_TRUE_DIVIDE: ++ } ++ /* -Qnew is in effect: fall through to BINARY_TRUE_DIVIDE */ ++ TARGET_NOARG(BINARY_TRUE_DIVIDE) ++ { + w = POP(); + v = TOP(); + x = PyNumber_TrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_FLOOR_DIVIDE: ++ TARGET_NOARG(BINARY_FLOOR_DIVIDE) ++ { + w = POP(); + v = TOP(); + x = PyNumber_FloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_MODULO: ++ TARGET_NOARG(BINARY_MODULO) ++ { + w = POP(); + v = TOP(); + if (PyString_CheckExact(v)) +@@ -1385,10 +1522,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_ADD: ++ TARGET_NOARG(BINARY_ADD) ++ { + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { +@@ -1417,10 +1556,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + skip_decref_vx: + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_SUBTRACT: ++ TARGET_NOARG(BINARY_SUBTRACT) ++ { + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { +@@ -1442,10 +1583,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_SUBSCR: ++ TARGET_NOARG(BINARY_SUBSCR) ++ { + w = POP(); + v = TOP(); + if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { +@@ -1466,102 +1609,122 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_LSHIFT: ++ TARGET_NOARG(BINARY_LSHIFT) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_RSHIFT: ++ TARGET_NOARG(BINARY_RSHIFT) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_AND: ++ TARGET_NOARG(BINARY_AND) ++ { + w = POP(); + v = TOP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_XOR: ++ TARGET_NOARG(BINARY_XOR) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case BINARY_OR: ++ TARGET_NOARG(BINARY_OR) ++ { + w = POP(); + v = TOP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case LIST_APPEND: ++ TARGET(LIST_APPEND) ++ { + w = POP(); + v = PEEK(oparg); + err = PyList_Append(v, w); + Py_DECREF(w); + if (err == 0) { + PREDICT(JUMP_ABSOLUTE); +- continue; ++ DISPATCH(); + } + break; ++ } + +- case SET_ADD: ++ TARGET(SET_ADD) ++ { + w = POP(); + v = stack_pointer[-oparg]; + err = PySet_Add(v, w); + Py_DECREF(w); + if (err == 0) { + PREDICT(JUMP_ABSOLUTE); +- continue; ++ DISPATCH(); + } + break; ++ } + +- case INPLACE_POWER: ++ TARGET_NOARG(INPLACE_POWER) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlacePower(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_MULTIPLY: ++ TARGET_NOARG(INPLACE_MULTIPLY) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceMultiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_DIVIDE: ++ TARGET_NOARG(INPLACE_DIVIDE) ++ { + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); +@@ -1569,42 +1732,50 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; + } ++ } + /* -Qnew is in effect: fall through to + INPLACE_TRUE_DIVIDE */ +- case INPLACE_TRUE_DIVIDE: ++ TARGET_NOARG(INPLACE_TRUE_DIVIDE) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceTrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_FLOOR_DIVIDE: ++ TARGET_NOARG(INPLACE_FLOOR_DIVIDE) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceFloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_MODULO: ++ TARGET_NOARG(INPLACE_MODULO) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRemainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_ADD: ++ TARGET_NOARG(INPLACE_ADD) ++ { + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { +@@ -1631,10 +1802,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + skip_decref_v: + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_SUBTRACT: ++ TARGET_NOARG(INPLACE_SUBTRACT) ++ { + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { +@@ -1654,63 +1827,78 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_LSHIFT: ++ TARGET_NOARG(INPLACE_LSHIFT) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceLshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_RSHIFT: ++ TARGET_NOARG(INPLACE_RSHIFT) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_AND: ++ TARGET_NOARG(INPLACE_AND) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceAnd(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_XOR: ++ TARGET_NOARG(INPLACE_XOR) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceXor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case INPLACE_OR: ++ TARGET_NOARG(INPLACE_OR) ++ { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceOr(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } ++ + +- case SLICE+0: +- case SLICE+1: +- case SLICE+2: +- case SLICE+3: ++ ++ TARGET_WITH_IMPL_NOARG(SLICE, _slice) ++ TARGET_WITH_IMPL_NOARG(SLICE_1, _slice) ++ TARGET_WITH_IMPL_NOARG(SLICE_2, _slice) ++ TARGET_WITH_IMPL_NOARG(SLICE_3, _slice) ++ _slice: ++ { + if ((opcode-SLICE) & 2) + w = POP(); + else +@@ -1725,13 +1913,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_XDECREF(v); + Py_XDECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } ++ + +- case STORE_SLICE+0: +- case STORE_SLICE+1: +- case STORE_SLICE+2: +- case STORE_SLICE+3: ++ TARGET_WITH_IMPL_NOARG(STORE_SLICE, _store_slice) ++ TARGET_WITH_IMPL_NOARG(STORE_SLICE_1, _store_slice) ++ TARGET_WITH_IMPL_NOARG(STORE_SLICE_2, _store_slice) ++ TARGET_WITH_IMPL_NOARG(STORE_SLICE_3, _store_slice) ++ _store_slice: ++ { + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else +@@ -1747,13 +1939,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } ++ + +- case DELETE_SLICE+0: +- case DELETE_SLICE+1: +- case DELETE_SLICE+2: +- case DELETE_SLICE+3: ++ TARGET_WITH_IMPL_NOARG(DELETE_SLICE, _delete_slice) ++ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_1, _delete_slice) ++ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_2, _delete_slice) ++ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_3, _delete_slice) ++ _delete_slice: ++ { + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else +@@ -1768,10 +1964,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case STORE_SUBSCR: ++ TARGET_NOARG(STORE_SUBSCR) ++ { + w = TOP(); + v = SECOND(); + u = THIRD(); +@@ -1781,10 +1979,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case DELETE_SUBSCR: ++ TARGET_NOARG(DELETE_SUBSCR) ++ { + w = TOP(); + v = SECOND(); + STACKADJ(-2); +@@ -1792,10 +1992,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case PRINT_EXPR: ++ TARGET_NOARG(PRINT_EXPR) ++ { + v = POP(); + w = PySys_GetObject("displayhook"); + if (w == NULL) { +@@ -1818,12 +2020,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_XDECREF(x); + break; ++ } + +- case PRINT_ITEM_TO: ++ TARGET_NOARG(PRINT_ITEM_TO) ++ { + w = stream = POP(); + /* fall through to PRINT_ITEM */ ++ } + +- case PRINT_ITEM: ++ TARGET_NOARG(PRINT_ITEM) ++ { + v = POP(); + if (stream == NULL || stream == Py_None) { + w = PySys_GetObject("stdout"); +@@ -1869,16 +2075,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_XDECREF(stream); + stream = NULL; +- if (err == 0) +- continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case PRINT_NEWLINE_TO: ++ TARGET_NOARG(PRINT_NEWLINE_TO) ++ { + w = stream = POP(); + /* fall through to PRINT_NEWLINE */ ++ } + +- case PRINT_NEWLINE: +- if (stream == NULL || stream == Py_None) { ++ TARGET_NOARG(PRINT_NEWLINE) ++ { ++ if (stream == NULL || stream == Py_None) ++ { + w = PySys_GetObject("stdout"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, +@@ -1899,11 +2109,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + stream = NULL; + break; + +- ++ } + #ifdef CASE_TOO_BIG + default: switch (opcode) { + #endif +- case RAISE_VARARGS: ++ ++ TARGET(RAISE_VARARGS) ++ { + u = v = w = NULL; + switch (oparg) { + case 3: +@@ -1924,28 +2136,37 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + break; + } + break; ++ } + +- case LOAD_LOCALS: +- if ((x = f->f_locals) != NULL) { ++ TARGET_NOARG(LOAD_LOCALS) ++ { ++ if ((x = f->f_locals) != NULL) ++ { + Py_INCREF(x); + PUSH(x); +- continue; ++ DISPATCH(); + } + PyErr_SetString(PyExc_SystemError, "no locals"); + break; ++ } + +- case RETURN_VALUE: ++ TARGET_NOARG(RETURN_VALUE) ++ { + retval = POP(); + why = WHY_RETURN; + goto fast_block_end; ++ } + +- case YIELD_VALUE: ++ TARGET_NOARG(YIELD_VALUE) ++ { + retval = POP(); + f->f_stacktop = stack_pointer; + why = WHY_YIELD; + goto fast_yield; ++ } + +- case EXEC_STMT: ++ TARGET_NOARG(EXEC_STMT) ++ { + w = TOP(); + v = SECOND(); + u = THIRD(); +@@ -1957,8 +2178,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + break; ++ } + +- case POP_BLOCK: ++ TARGET_NOARG(POP_BLOCK) ++ { + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { +@@ -1966,10 +2189,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + } + } +- continue; ++ DISPATCH(); ++ } + + PREDICTED(END_FINALLY); +- case END_FINALLY: ++ TARGET_NOARG(END_FINALLY) ++ { + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AS_LONG(v); +@@ -1993,8 +2218,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + Py_DECREF(v); + break; ++ } + +- case BUILD_CLASS: ++ TARGET_NOARG(BUILD_CLASS) ++ { + u = TOP(); + v = SECOND(); + w = THIRD(); +@@ -2005,8 +2232,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_DECREF(w); + break; ++ } + +- case STORE_NAME: ++ TARGET(STORE_NAME) ++ { + w = GETITEM(names, oparg); + v = POP(); + if ((x = f->f_locals) != NULL) { +@@ -2015,15 +2244,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + else + err = PyObject_SetItem(x, w, v); + Py_DECREF(v); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; + } + PyErr_Format(PyExc_SystemError, + "no locals found when storing %s", + PyObject_REPR(w)); + break; ++ } + +- case DELETE_NAME: ++ TARGET(DELETE_NAME) ++ { + w = GETITEM(names, oparg); + if ((x = f->f_locals) != NULL) { + if ((err = PyObject_DelItem(x, w)) != 0) +@@ -2036,9 +2267,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + "no locals when deleting %s", + PyObject_REPR(w)); + break; ++ } + + PREDICTED_WITH_ARG(UNPACK_SEQUENCE); +- case UNPACK_SEQUENCE: ++ TARGET(UNPACK_SEQUENCE) ++ { + v = POP(); + if (PyTuple_CheckExact(v) && + PyTuple_GET_SIZE(v) == oparg) { +@@ -2050,7 +2283,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + PUSH(w); + } + Py_DECREF(v); +- continue; ++ DISPATCH(); + } else if (PyList_CheckExact(v) && + PyList_GET_SIZE(v) == oparg) { + PyObject **items = \ +@@ -2069,8 +2302,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + Py_DECREF(v); + break; ++ } + +- case STORE_ATTR: ++ TARGET(STORE_ATTR) ++ { + w = GETITEM(names, oparg); + v = TOP(); + u = SECOND(); +@@ -2078,33 +2313,41 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case DELETE_ATTR: ++ TARGET(DELETE_ATTR) ++ { + w = GETITEM(names, oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; ++ } + +- case STORE_GLOBAL: ++ TARGET(STORE_GLOBAL) ++ { + w = GETITEM(names, oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case DELETE_GLOBAL: ++ TARGET(DELETE_GLOBAL) ++ { + w = GETITEM(names, oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + format_exc_check_arg( + PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w); + break; ++ } + +- case LOAD_NAME: ++ TARGET(LOAD_NAME) ++ { + w = GETITEM(names, oparg); + if ((v = f->f_locals) == NULL) { + PyErr_Format(PyExc_SystemError, +@@ -2140,9 +2383,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_INCREF(x); + } + PUSH(x); +- continue; ++ DISPATCH(); ++ } + +- case LOAD_GLOBAL: ++ TARGET(LOAD_GLOBAL) ++ { + w = GETITEM(names, oparg); + if (PyString_CheckExact(w)) { + /* Inline the PyDict_GetItem() calls. +@@ -2162,7 +2407,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + if (x != NULL) { + Py_INCREF(x); + PUSH(x); +- continue; ++ DISPATCH(); + } + d = (PyDictObject *)(f->f_builtins); + e = d->ma_lookup(d, w, hash); +@@ -2174,7 +2419,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + if (x != NULL) { + Py_INCREF(x); + PUSH(x); +- continue; ++ DISPATCH(); + } + goto load_global_error; + } +@@ -2193,13 +2438,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + Py_INCREF(x); + PUSH(x); +- continue; ++ DISPATCH(); ++ } + +- case DELETE_FAST: ++ TARGET(DELETE_FAST) ++ { + x = GETLOCAL(oparg); + if (x != NULL) { + SETLOCAL(oparg, NULL); +- continue; ++ DISPATCH(); + } + format_exc_check_arg( + PyExc_UnboundLocalError, +@@ -2207,20 +2454,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + PyTuple_GetItem(co->co_varnames, oparg) + ); + break; ++ } + +- case LOAD_CLOSURE: ++ TARGET(LOAD_CLOSURE) ++ { + x = freevars[oparg]; + Py_INCREF(x); + PUSH(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case LOAD_DEREF: ++ TARGET(LOAD_DEREF) ++ { + x = freevars[oparg]; + w = PyCell_Get(x); + if (w != NULL) { + PUSH(w); +- continue; ++ DISPATCH(); + } + err = -1; + /* Don't stomp existing exception */ +@@ -2240,15 +2491,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + UNBOUNDFREE_ERROR_MSG, v); + } + break; ++ } + +- case STORE_DEREF: ++ TARGET(STORE_DEREF) ++ { + w = POP(); + x = freevars[oparg]; + PyCell_Set(x, w); + Py_DECREF(w); +- continue; ++ DISPATCH(); ++ } + +- case BUILD_TUPLE: ++ TARGET(BUILD_TUPLE) ++ { + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { +@@ -2256,11 +2511,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); +- continue; ++ DISPATCH(); + } + break; ++ } + +- case BUILD_LIST: ++ TARGET(BUILD_LIST) ++ { + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { +@@ -2268,11 +2525,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + PyList_SET_ITEM(x, oparg, w); + } + PUSH(x); +- continue; ++ DISPATCH(); + } + break; ++ } + +- case BUILD_SET: ++ TARGET(BUILD_SET) ++ { + x = PySet_New(NULL); + if (x != NULL) { + for (; --oparg >= 0;) { +@@ -2286,18 +2545,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + break; + } + PUSH(x); +- continue; ++ DISPATCH(); + } + break; ++ } + +- +- case BUILD_MAP: ++ TARGET(BUILD_MAP) ++ { + x = _PyDict_NewPresized((Py_ssize_t)oparg); + PUSH(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case STORE_MAP: ++ TARGET_NOARG(STORE_MAP) ++ { + w = TOP(); /* key */ + u = SECOND(); /* value */ + v = THIRD(); /* dict */ +@@ -2306,10 +2568,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + err = PyDict_SetItem(v, w, u); /* v[w] = u */ + Py_DECREF(u); + Py_DECREF(w); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case MAP_ADD: ++ TARGET(MAP_ADD) ++ { + w = TOP(); /* key */ + u = SECOND(); /* value */ + STACKADJ(-2); +@@ -2320,20 +2584,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(w); + if (err == 0) { + PREDICT(JUMP_ABSOLUTE); +- continue; ++ DISPATCH(); + } + break; ++ } + +- case LOAD_ATTR: ++ TARGET(LOAD_ATTR) ++ { + w = GETITEM(names, oparg); + v = TOP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case COMPARE_OP: ++ TARGET(COMPARE_OP) ++ { + w = POP(); + v = TOP(); + if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) { +@@ -2366,9 +2634,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + if (x == NULL) break; + PREDICT(POP_JUMP_IF_FALSE); + PREDICT(POP_JUMP_IF_TRUE); +- continue; ++ DISPATCH(); ++ } + +- case IMPORT_NAME: ++ TARGET(IMPORT_NAME) ++ { + w = GETITEM(names, oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { +@@ -2409,10 +2679,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + READ_TIMESTAMP(intr1); + Py_DECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case IMPORT_STAR: ++ TARGET_NOARG(IMPORT_STAR) ++ { + v = POP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { +@@ -2425,34 +2697,40 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + READ_TIMESTAMP(intr1); + PyFrame_LocalsToFast(f, 0); + Py_DECREF(v); +- if (err == 0) continue; ++ if (err == 0) DISPATCH(); + break; ++ } + +- case IMPORT_FROM: ++ TARGET(IMPORT_FROM) ++ { + w = GETITEM(names, oparg); + v = TOP(); + READ_TIMESTAMP(intr0); + x = import_from(v, w); + READ_TIMESTAMP(intr1); + PUSH(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case JUMP_FORWARD: ++ TARGET(JUMP_FORWARD) ++ { + JUMPBY(oparg); +- goto fast_next_opcode; ++ FAST_DISPATCH(); ++ } + + PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE); +- case POP_JUMP_IF_FALSE: ++ TARGET(POP_JUMP_IF_FALSE) ++ { + w = POP(); + if (w == Py_True) { + Py_DECREF(w); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + if (w == Py_False) { + Py_DECREF(w); + JUMPTO(oparg); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + err = PyObject_IsTrue(w); + Py_DECREF(w); +@@ -2462,19 +2740,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + JUMPTO(oparg); + else + break; +- continue; +- ++ DISPATCH(); ++ } + PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE); +- case POP_JUMP_IF_TRUE: ++ TARGET(POP_JUMP_IF_TRUE) ++ { + w = POP(); + if (w == Py_False) { + Py_DECREF(w); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + if (w == Py_True) { + Py_DECREF(w); + JUMPTO(oparg); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + err = PyObject_IsTrue(w); + Py_DECREF(w); +@@ -2486,18 +2765,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + ; + else + break; +- continue; ++ DISPATCH(); ++ } + +- case JUMP_IF_FALSE_OR_POP: ++ TARGET(JUMP_IF_FALSE_OR_POP) ++ { + w = TOP(); + if (w == Py_True) { + STACKADJ(-1); + Py_DECREF(w); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + if (w == Py_False) { + JUMPTO(oparg); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + err = PyObject_IsTrue(w); + if (err > 0) { +@@ -2509,18 +2790,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + JUMPTO(oparg); + else + break; +- continue; ++ DISPATCH(); ++ } + +- case JUMP_IF_TRUE_OR_POP: ++ TARGET(JUMP_IF_TRUE_OR_POP) ++ { + w = TOP(); + if (w == Py_False) { + STACKADJ(-1); + Py_DECREF(w); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + if (w == Py_True) { + JUMPTO(oparg); +- goto fast_next_opcode; ++ FAST_DISPATCH(); + } + err = PyObject_IsTrue(w); + if (err > 0) { +@@ -2533,10 +2816,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + else + break; +- continue; ++ DISPATCH(); ++ } + + PREDICTED_WITH_ARG(JUMP_ABSOLUTE); +- case JUMP_ABSOLUTE: ++ TARGET(JUMP_ABSOLUTE) ++ { + JUMPTO(oparg); + #if FAST_LOOPS + /* Enabling this path speeds-up all while and for-loops by bypassing +@@ -2548,10 +2833,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + */ + goto fast_next_opcode; + #else +- continue; ++ DISPATCH(); + #endif ++ } + +- case GET_ITER: ++ TARGET_NOARG(GET_ITER) ++ { + /* before: [obj]; after [getiter(obj)] */ + v = TOP(); + x = PyObject_GetIter(v); +@@ -2559,13 +2846,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + if (x != NULL) { + SET_TOP(x); + PREDICT(FOR_ITER); +- continue; ++ DISPATCH(); + } + STACKADJ(-1); + break; ++ } + + PREDICTED_WITH_ARG(FOR_ITER); +- case FOR_ITER: ++ TARGET(FOR_ITER) ++ { + /* before: [iter]; after: [iter, iter()] *or* [] */ + v = TOP(); + x = (*v->ob_type->tp_iternext)(v); +@@ -2573,7 +2862,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + PUSH(x); + PREDICT(STORE_FAST); + PREDICT(UNPACK_SEQUENCE); +- continue; ++ DISPATCH(); + } + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches( +@@ -2585,13 +2874,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + x = v = POP(); + Py_DECREF(v); + JUMPBY(oparg); +- continue; ++ DISPATCH(); ++ } + +- case BREAK_LOOP: ++ TARGET_NOARG(BREAK_LOOP) ++ { + why = WHY_BREAK; + goto fast_block_end; ++ } + +- case CONTINUE_LOOP: ++ TARGET(CONTINUE_LOOP) ++ { + retval = PyInt_FromLong(oparg); + if (!retval) { + x = NULL; +@@ -2599,10 +2892,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + why = WHY_CONTINUE; + goto fast_block_end; ++ } + +- case SETUP_LOOP: +- case SETUP_EXCEPT: +- case SETUP_FINALLY: ++ TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally) ++ TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally) ++ TARGET(SETUP_FINALLY) ++ _setup_finally: ++ { + /* NOTE: If you add any new block-setup opcodes that + are not try/except/finally handlers, you may need + to update the PyGen_NeedsFinalizing() function. +@@ -2610,9 +2906,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); +- continue; ++ DISPATCH(); ++ } + +- case SETUP_WITH: ++ ++ TARGET(SETUP_WITH) ++ { + { + static PyObject *exit, *enter; + w = TOP(); +@@ -2638,10 +2937,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + STACK_LEVEL()); + + PUSH(x); +- continue; ++ DISPATCH(); ++ } + } + +- case WITH_CLEANUP: ++ TARGET_NOARG(WITH_CLEANUP) + { + /* At the top of the stack are 1-3 values indicating + how/why we entered the finally clause: +@@ -2729,7 +3029,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + break; + } + +- case CALL_FUNCTION: ++ TARGET(CALL_FUNCTION) + { + PyObject **sp; + PCALL(PCALL_ALL); +@@ -2741,14 +3041,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + #endif + stack_pointer = sp; + PUSH(x); +- if (x != NULL) +- continue; ++ if (x != NULL) DISPATCH(); + break; + } + +- case CALL_FUNCTION_VAR: +- case CALL_FUNCTION_KW: +- case CALL_FUNCTION_VAR_KW: ++ TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw) ++ TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw) ++ TARGET(CALL_FUNCTION_VAR_KW) ++ _call_function_var_kw: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; +@@ -2786,12 +3086,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(w); + } + PUSH(x); +- if (x != NULL) +- continue; ++ if (x != NULL) DISPATCH(); + break; + } + +- case MAKE_FUNCTION: ++ TARGET(MAKE_FUNCTION) ++ { + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); +@@ -2812,8 +3112,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + } + PUSH(x); + break; ++ } + +- case MAKE_CLOSURE: ++ TARGET(MAKE_CLOSURE) + { + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); +@@ -2848,7 +3149,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + break; + } + +- case BUILD_SLICE: ++ TARGET(BUILD_SLICE) ++ { + if (oparg == 3) + w = POP(); + else +@@ -2860,14 +3162,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) + Py_DECREF(v); + Py_XDECREF(w); + SET_TOP(x); +- if (x != NULL) continue; ++ if (x != NULL) DISPATCH(); + break; ++ } + +- case EXTENDED_ARG: ++ TARGET(EXTENDED_ARG) ++ { + opcode = NEXTOP(); + oparg = oparg<<16 | NEXTARG(); + goto dispatch_opcode; + ++ } ++ ++ ++#if USE_COMPUTED_GOTOS ++ _unknown_opcode: ++#endif + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", +diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py +index e69de29..703e5f2 100644 +--- a/Python/makeopcodetargets.py ++++ b/Python/makeopcodetargets.py +@@ -0,0 +1,45 @@ ++#! /usr/bin/env python ++"""Generate C code for the jump table of the threaded code interpreter ++(for compilers supporting computed gotos or "labels-as-values", such as gcc). ++""" ++ ++# This code should stay compatible with Python 2.3, at least while ++# some of the buildbots have Python 2.3 as their system Python. ++ ++import imp ++import os ++ ++ ++def find_module(modname): ++ """Finds and returns a module in the local dist/checkout. ++ """ ++ modpath = os.path.join( ++ os.path.dirname(os.path.dirname(__file__)), "Lib") ++ return imp.load_module(modname, *imp.find_module(modname, [modpath])) ++ ++def write_contents(f): ++ """Write C code contents to the target file object. ++ """ ++ opcode = find_module("opcode") ++ targets = ['_unknown_opcode'] * 256 ++ for opname, op in opcode.opmap.items(): ++ if opname == "STOP_CODE": ++ continue ++ targets[op] = "TARGET_%s" % opname.replace("+0", " ").replace("+", "_") ++ f.write("static void *opcode_targets[256] = {\n") ++ f.write(",\n".join([" &&%s" % s for s in targets])) ++ f.write("\n};\n") ++ ++ ++if __name__ == "__main__": ++ import sys ++ assert len(sys.argv) < 3, "Too many arguments" ++ if len(sys.argv) == 2: ++ target = sys.argv[1] ++ else: ++ target = "Python/opcode_targets.h" ++ f = open(target, "w") ++ try: ++ write_contents(f) ++ finally: ++ f.close() +\ No newline at end of file +diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h +index e69de29..2203566 100644 +--- a/Python/opcode_targets.h ++++ b/Python/opcode_targets.h +@@ -0,0 +1,258 @@ ++static void *opcode_targets[256] = { ++ &&_unknown_opcode, ++ &&TARGET_POP_TOP, ++ &&TARGET_ROT_TWO, ++ &&TARGET_ROT_THREE, ++ &&TARGET_DUP_TOP, ++ &&TARGET_ROT_FOUR, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_NOP, ++ &&TARGET_UNARY_POSITIVE, ++ &&TARGET_UNARY_NEGATIVE, ++ &&TARGET_UNARY_NOT, ++ &&TARGET_UNARY_CONVERT, ++ &&_unknown_opcode, ++ &&TARGET_UNARY_INVERT, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_BINARY_POWER, ++ &&TARGET_BINARY_MULTIPLY, ++ &&TARGET_BINARY_DIVIDE, ++ &&TARGET_BINARY_MODULO, ++ &&TARGET_BINARY_ADD, ++ &&TARGET_BINARY_SUBTRACT, ++ &&TARGET_BINARY_SUBSCR, ++ &&TARGET_BINARY_FLOOR_DIVIDE, ++ &&TARGET_BINARY_TRUE_DIVIDE, ++ &&TARGET_INPLACE_FLOOR_DIVIDE, ++ &&TARGET_INPLACE_TRUE_DIVIDE, ++ &&TARGET_SLICE , ++ &&TARGET_SLICE_1, ++ &&TARGET_SLICE_2, ++ &&TARGET_SLICE_3, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_STORE_SLICE , ++ &&TARGET_STORE_SLICE_1, ++ &&TARGET_STORE_SLICE_2, ++ &&TARGET_STORE_SLICE_3, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_DELETE_SLICE , ++ &&TARGET_DELETE_SLICE_1, ++ &&TARGET_DELETE_SLICE_2, ++ &&TARGET_DELETE_SLICE_3, ++ &&TARGET_STORE_MAP, ++ &&TARGET_INPLACE_ADD, ++ &&TARGET_INPLACE_SUBTRACT, ++ &&TARGET_INPLACE_MULTIPLY, ++ &&TARGET_INPLACE_DIVIDE, ++ &&TARGET_INPLACE_MODULO, ++ &&TARGET_STORE_SUBSCR, ++ &&TARGET_DELETE_SUBSCR, ++ &&TARGET_BINARY_LSHIFT, ++ &&TARGET_BINARY_RSHIFT, ++ &&TARGET_BINARY_AND, ++ &&TARGET_BINARY_XOR, ++ &&TARGET_BINARY_OR, ++ &&TARGET_INPLACE_POWER, ++ &&TARGET_GET_ITER, ++ &&_unknown_opcode, ++ &&TARGET_PRINT_EXPR, ++ &&TARGET_PRINT_ITEM, ++ &&TARGET_PRINT_NEWLINE, ++ &&TARGET_PRINT_ITEM_TO, ++ &&TARGET_PRINT_NEWLINE_TO, ++ &&TARGET_INPLACE_LSHIFT, ++ &&TARGET_INPLACE_RSHIFT, ++ &&TARGET_INPLACE_AND, ++ &&TARGET_INPLACE_XOR, ++ &&TARGET_INPLACE_OR, ++ &&TARGET_BREAK_LOOP, ++ &&TARGET_WITH_CLEANUP, ++ &&TARGET_LOAD_LOCALS, ++ &&TARGET_RETURN_VALUE, ++ &&TARGET_IMPORT_STAR, ++ &&TARGET_EXEC_STMT, ++ &&TARGET_YIELD_VALUE, ++ &&TARGET_POP_BLOCK, ++ &&TARGET_END_FINALLY, ++ &&TARGET_BUILD_CLASS, ++ &&TARGET_STORE_NAME, ++ &&TARGET_DELETE_NAME, ++ &&TARGET_UNPACK_SEQUENCE, ++ &&TARGET_FOR_ITER, ++ &&TARGET_LIST_APPEND, ++ &&TARGET_STORE_ATTR, ++ &&TARGET_DELETE_ATTR, ++ &&TARGET_STORE_GLOBAL, ++ &&TARGET_DELETE_GLOBAL, ++ &&TARGET_DUP_TOPX, ++ &&TARGET_LOAD_CONST, ++ &&TARGET_LOAD_NAME, ++ &&TARGET_BUILD_TUPLE, ++ &&TARGET_BUILD_LIST, ++ &&TARGET_BUILD_SET, ++ &&TARGET_BUILD_MAP, ++ &&TARGET_LOAD_ATTR, ++ &&TARGET_COMPARE_OP, ++ &&TARGET_IMPORT_NAME, ++ &&TARGET_IMPORT_FROM, ++ &&TARGET_JUMP_FORWARD, ++ &&TARGET_JUMP_IF_FALSE_OR_POP, ++ &&TARGET_JUMP_IF_TRUE_OR_POP, ++ &&TARGET_JUMP_ABSOLUTE, ++ &&TARGET_POP_JUMP_IF_FALSE, ++ &&TARGET_POP_JUMP_IF_TRUE, ++ &&TARGET_LOAD_GLOBAL, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_CONTINUE_LOOP, ++ &&TARGET_SETUP_LOOP, ++ &&TARGET_SETUP_EXCEPT, ++ &&TARGET_SETUP_FINALLY, ++ &&_unknown_opcode, ++ &&TARGET_LOAD_FAST, ++ &&TARGET_STORE_FAST, ++ &&TARGET_DELETE_FAST, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_RAISE_VARARGS, ++ &&TARGET_CALL_FUNCTION, ++ &&TARGET_MAKE_FUNCTION, ++ &&TARGET_BUILD_SLICE, ++ &&TARGET_MAKE_CLOSURE, ++ &&TARGET_LOAD_CLOSURE, ++ &&TARGET_LOAD_DEREF, ++ &&TARGET_STORE_DEREF, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&TARGET_CALL_FUNCTION_VAR, ++ &&TARGET_CALL_FUNCTION_KW, ++ &&TARGET_CALL_FUNCTION_VAR_KW, ++ &&TARGET_SETUP_WITH, ++ &&_unknown_opcode, ++ &&TARGET_EXTENDED_ARG, ++ &&TARGET_SET_ADD, ++ &&TARGET_MAP_ADD, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode, ++ &&_unknown_opcode ++}; +\ No newline at end of file +diff --git a/configure b/configure +index 6a47e1a..60a3335 100755 +--- a/configure ++++ b/configure +@@ -810,6 +810,7 @@ with_libm + with_libc + enable_big_digits + enable_unicode ++with_computed_gotos + ' + ac_precious_vars='build_alias + host_alias +@@ -1488,6 +1489,9 @@ Optional Packages: + --with-fpectl enable SIGFPE catching + --with-libm=STRING math library + --with-libc=STRING C library ++ --with(out)-computed-gotos ++ Use computed gotos in evaluation loop (enabled by ++ default on supported compilers) + + Some influential environment variables: + CC C compiler command +@@ -14608,6 +14612,83 @@ for dir in $SRCDIRS; do + mkdir $dir + fi + done ++ ++ BEGIN_COMPUTED_GOTO ++# Check for --with-computed-gotos ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 ++$as_echo_n "checking for --with-computed-gotos... " >&6; } ++ ++# Check whether --with-computed-gotos was given. ++if test "${with_computed_gotos+set}" = set; then : ++ withval=$with_computed_gotos; ++if test "$withval" = yes ++then ++ ++$as_echo "#define USE_COMPUTED_GOTOS 1" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++fi ++if test "$withval" = no ++then ++ ++$as_echo "#define USE_COMPUTED_GOTOS 0" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 ++$as_echo "no value specified" >&6; } ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 ++$as_echo_n "checking whether $CC supports computed gotos... " >&6; } ++if ${ac_cv_computed_gotos+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test "$cross_compiling" = yes; then : ++ if test "${with_computed_gotos+set}" = set; then ++ ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" ++ else ++ ac_cv_computed_gotos=no ++ fi ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++int main(int argc, char **argv) ++{ ++ static void *targets[1] = { &&LABEL1 }; ++ goto LABEL2; ++LABEL1: ++ return 0; ++LABEL2: ++ goto *targets[0]; ++ return 1; ++} ++_ACEOF ++if ac_fn_c_try_run "$LINENO"; then : ++ ac_cv_computed_gotos=yes ++else ++ ac_cv_computed_gotos=no ++fi ++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ++fi ++ ++fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 ++$as_echo "$ac_cv_computed_gotos" >&6; } ++case "$ac_cv_computed_gotos" in yes*) ++ ++$as_echo "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h ++ ++esac ++# END_COMPUTED_GOTO ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 + $as_echo "done" >&6; } + +diff --git a/configure.ac b/configure.ac +index 48eccdd..74bb514 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -4561,6 +4561,57 @@ for dir in $SRCDIRS; do + mkdir $dir + fi + done ++ ++# BEGIN_COMPUTED_GOTO ++# Check for --with-computed-gotos ++AC_MSG_CHECKING(for --with-computed-gotos) ++AC_ARG_WITH(computed-gotos, ++ AS_HELP_STRING([--with(out)-computed-gotos], ++ [Use computed gotos in evaluation loop (enabled by default on supported compilers)]), ++[ ++if test "$withval" = yes ++then ++ AC_DEFINE(USE_COMPUTED_GOTOS, 1, ++ [Define if you want to use computed gotos in ceval.c.]) ++ AC_MSG_RESULT(yes) ++fi ++if test "$withval" = no ++then ++ AC_DEFINE(USE_COMPUTED_GOTOS, 0, ++ [Define if you want to use computed gotos in ceval.c.]) ++ AC_MSG_RESULT(no) ++fi ++], ++[AC_MSG_RESULT(no value specified)]) ++ ++AC_MSG_CHECKING(whether $CC supports computed gotos) ++AC_CACHE_VAL(ac_cv_computed_gotos, ++AC_RUN_IFELSE([AC_LANG_SOURCE([[[ ++int main(int argc, char **argv) ++{ ++ static void *targets[1] = { &&LABEL1 }; ++ goto LABEL2; ++LABEL1: ++ return 0; ++LABEL2: ++ goto *targets[0]; ++ return 1; ++} ++]]])], ++[ac_cv_computed_gotos=yes], ++[ac_cv_computed_gotos=no], ++[if test "${with_computed_gotos+set}" = set; then ++ ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" ++ else ++ ac_cv_computed_gotos=no ++ fi])) ++AC_MSG_RESULT($ac_cv_computed_gotos) ++case "$ac_cv_computed_gotos" in yes*) ++ AC_DEFINE(HAVE_COMPUTED_GOTOS, 1, ++ [Define if the C compiler supports computed gotos.]) ++esac ++# END_COMPUTED_GOTO ++ + AC_MSG_RESULT(done) + + # generate output files +diff --git a/pyconfig.h.in b/pyconfig.h.in +index eace285..ac85729 100644 +--- a/pyconfig.h.in ++++ b/pyconfig.h.in +@@ -121,6 +121,9 @@ + /* Define to 1 if you have the `clock' function. */ + #undef HAVE_CLOCK + ++/* Define if the C compiler supports computed gotos. */ ++#undef HAVE_COMPUTED_GOTOS ++ + /* Define to 1 if you have the `confstr' function. */ + #undef HAVE_CONFSTR + +@@ -1060,6 +1063,9 @@ + /* Define to 1 if your declares `struct tm'. */ + #undef TM_IN_SYS_TIME + ++/* Define if you want to use computed gotos in ceval.c. */ ++#undef USE_COMPUTED_GOTOS ++ + /* Enable extensions on AIX 3, Interix. */ + #ifndef _ALL_SOURCE + # undef _ALL_SOURCE +-- +2.5.5 + diff --git a/SOURCES/00234-PEP493-updated-implementation.patch b/SOURCES/00234-PEP493-updated-implementation.patch new file mode 100644 index 00000000..275fc537 --- /dev/null +++ b/SOURCES/00234-PEP493-updated-implementation.patch @@ -0,0 +1,137 @@ +@@ -, +, @@ +--- + Lib/ssl.py | 53 ++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 38 insertions(+), 15 deletions(-) +--- a/Lib/ssl.py ++++ a/Lib/ssl.py +@@ -466,24 +466,47 @@ def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, + + return context + ++_https_verify_envvar = 'PYTHONHTTPSVERIFY' + _cert_verification_config = '/etc/python/cert-verification.cfg' + +-def _get_verify_status(protocol): +- context_factory = { +- 'platform_default': _create_unverified_context, +- 'enable': create_default_context, +- 'disable': _create_unverified_context +- } +- import ConfigParser +- try: +- config = ConfigParser.RawConfigParser() +- config.read(_cert_verification_config) +- status = config.get(protocol, 'verify') +- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): +- status = 'platform_default' +- default = context_factory.get('platform_default') +- return context_factory.get(status, default) ++# To provide same function name as specified in PEP493 with keeping ++# the old name as defined in our previous patch ++_get_https_context_factory = lambda: _get_verify_status('https') + ++def _get_verify_status(protocol): ++ # See https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports ++ # Check for an environmental override of the default behaviour ++ if not sys.flags.ignore_environment: ++ config_setting = os.environ.get(_https_verify_envvar) ++ if config_setting is not None: ++ if config_setting == '0': ++ return _create_unverified_context ++ return create_default_context ++ ++ # Check for a system-wide override of the default behaviour ++ context_factory = { ++ 'platform_default': create_default_context, ++ 'enable': create_default_context, ++ 'disable': _create_unverified_context ++ } ++ import ConfigParser ++ try: ++ config = ConfigParser.RawConfigParser() ++ config.read(_cert_verification_config) ++ status = config.get(protocol, 'verify') ++ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): ++ status = 'platform_default' ++ default = context_factory.get('platform_default') ++ return context_factory.get(status, default) ++ ++# See https://www.python.org/dev/peps/pep-0493/#feature-configuration-api ++def _https_verify_certificates(enable=True): ++ """Verify server HTTPS certificates by default?""" ++ global _create_default_https_context ++ if enable: ++ _create_default_https_context = create_default_context ++ else: ++ _create_default_https_context = _create_unverified_context + + # Used by http.client if no context is explicitly passed. + _create_default_https_context = _get_verify_status('https') +--- a/Lib/test/test_ssl.py Thu Jan 14 21:57:57 2016 -0800 ++++ a/Lib/test/test_ssl.py Fri Jan 15 17:41:37 2016 +1000 +@@ -4,6 +4,7 @@ + import sys + import unittest + from test import test_support as support ++from test.script_helper import assert_python_ok + import asyncore + import socket + import select +@@ -1149,6 +1149,57 @@ + self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + ++ def test__https_verify_certificates(self): ++ # Unit test to check the contect factory mapping ++ # The factories themselves are tested above ++ # This test will fail by design if run under PYTHONHTTPSVERIFY=0 ++ # (as will various test_httplib tests) ++ ++ # Uses a fresh SSL module to avoid affecting the real one ++ local_ssl = support.import_fresh_module("ssl") ++ # Certificate verification is enabled by default ++ self.assertIs(local_ssl._create_default_https_context, ++ local_ssl.create_default_context) ++ # Turn default verification off ++ local_ssl._https_verify_certificates(enable=False) ++ self.assertIs(local_ssl._create_default_https_context, ++ local_ssl._create_unverified_context) ++ # And back on ++ local_ssl._https_verify_certificates(enable=True) ++ self.assertIs(local_ssl._create_default_https_context, ++ local_ssl.create_default_context) ++ # The default behaviour is to enable ++ local_ssl._https_verify_certificates(enable=False) ++ local_ssl._https_verify_certificates() ++ self.assertIs(local_ssl._create_default_https_context, ++ local_ssl.create_default_context) ++ ++ def test__https_verify_envvar(self): ++ # Unit test to check the PYTHONHTTPSVERIFY handling ++ # Need to use a subprocess so it can still be run under -E ++ https_is_verified = """import ssl, sys; \ ++ status = "Error: _create_default_https_context does not verify certs" \ ++ if ssl._create_default_https_context is \ ++ ssl._create_unverified_context \ ++ else None; \ ++ sys.exit(status)""" ++ https_is_not_verified = """import ssl, sys; \ ++ status = "Error: _create_default_https_context verifies certs" \ ++ if ssl._create_default_https_context is \ ++ ssl.create_default_context \ ++ else None; \ ++ sys.exit(status)""" ++ extra_env = {} ++ # Omitting it leaves verification on ++ assert_python_ok("-c", https_is_verified, **extra_env) ++ # Setting it to zero turns verification off ++ extra_env[ssl._https_verify_envvar] = "0" ++ assert_python_ok("-c", https_is_not_verified, **extra_env) ++ # Any other value should also leave it on ++ for setting in ("", "1", "enabled", "foo"): ++ extra_env[ssl._https_verify_envvar] = setting ++ assert_python_ok("-c", https_is_verified, **extra_env) ++ + def test_check_hostname(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + self.assertFalse(ctx.check_hostname) diff --git a/SOURCES/00235-JSON-decoder-lone-surrogates-fix.patch b/SOURCES/00235-JSON-decoder-lone-surrogates-fix.patch new file mode 100644 index 00000000..d78e8e7a --- /dev/null +++ b/SOURCES/00235-JSON-decoder-lone-surrogates-fix.patch @@ -0,0 +1,226 @@ +From 90986ef48c0df602ab38aa831a24e99e9ed61e7e Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Mon, 4 Apr 2016 15:55:28 +0200 +Subject: [PATCH] JSON decoder now accepts lone surrogates + +--- + Lib/json/decoder.py | 35 ++++++++++++------------ + Lib/json/tests/test_scanstring.py | 56 ++++++++++++++++++++++++++++++++++++--- + Modules/_json.c | 49 +++++++++------------------------- + 3 files changed, 83 insertions(+), 57 deletions(-) + +diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py +index dfcc628..1b43238 100644 +--- a/Lib/json/decoder.py ++++ b/Lib/json/decoder.py +@@ -62,6 +62,16 @@ BACKSLASH = { + + DEFAULT_ENCODING = "utf-8" + ++def _decode_uXXXX(s, pos): ++ esc = s[pos + 1:pos + 5] ++ if len(esc) == 4 and esc[1] not in 'xX': ++ try: ++ return int(esc, 16) ++ except ValueError: ++ pass ++ msg = "Invalid \\uXXXX escape" ++ raise ValueError(errmsg(msg, s, pos)) ++ + def py_scanstring(s, end, encoding=None, strict=True, + _b=BACKSLASH, _m=STRINGCHUNK.match): + """Scan the string s for a JSON string. End is the index of the +@@ -116,25 +126,16 @@ def py_scanstring(s, end, encoding=None, strict=True, + end += 1 + else: + # Unicode escape sequence +- esc = s[end + 1:end + 5] +- next_end = end + 5 +- if len(esc) != 4: +- msg = "Invalid \\uXXXX escape" +- raise ValueError(errmsg(msg, s, end)) +- uni = int(esc, 16) ++ uni = _decode_uXXXX(s, end) ++ end += 5 + # Check for surrogate pair on UCS-4 systems +- if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: +- msg = "Invalid \\uXXXX\\uXXXX surrogate pair" +- if not s[end + 5:end + 7] == '\\u': +- raise ValueError(errmsg(msg, s, end)) +- esc2 = s[end + 7:end + 11] +- if len(esc2) != 4: +- raise ValueError(errmsg(msg, s, end)) +- uni2 = int(esc2, 16) +- uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) +- next_end += 6 ++ if sys.maxunicode > 65535 and \ ++ 0xd800 <= uni <= 0xdbff and s[end:end + 2] == '\\u': ++ uni2 = _decode_uXXXX(s, end + 1) ++ if 0xdc00 <= uni2 <= 0xdfff: ++ uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) ++ end += 6 + char = unichr(uni) +- end = next_end + # Append the unescaped character + _append(char) + return u''.join(chunks), end +diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py +index 4fef8cb..ed80a41 100644 +--- a/Lib/json/tests/test_scanstring.py ++++ b/Lib/json/tests/test_scanstring.py +@@ -5,10 +5,6 @@ from json.tests import PyTest, CTest + class TestScanstring(object): + def test_scanstring(self): + scanstring = self.json.decoder.scanstring +- self.assertEqual( +- scanstring('"z\\ud834\\udd20x"', 1, None, True), +- (u'z\U0001d120x', 16)) +- + if sys.maxunicode == 65535: + self.assertEqual( + scanstring(u'"z\U0001d120x"', 1, None, True), +@@ -94,6 +90,58 @@ class TestScanstring(object): + scanstring('["Bad value", truth]', 2, None, True), + (u'Bad value', 12)) + ++ def test_surrogates(self): ++ scanstring = self.json.decoder.scanstring ++ def assertScan(given, expect): ++ self.assertEqual(scanstring(given, 1, None, True), ++ (expect, len(given))) ++ if not isinstance(given, unicode): ++ given = unicode(given) ++ self.assertEqual(scanstring(given, 1, None, True), ++ (expect, len(given))) ++ ++ surrogates = unichr(0xd834) + unichr(0xdd20) ++ assertScan('"z\\ud834\\u0079x"', u'z\ud834yx') ++ assertScan('"z\\ud834\\udd20x"', u'z\U0001d120x') ++ assertScan('"z\\ud834\\ud834\\udd20x"', u'z\ud834\U0001d120x') ++ assertScan('"z\\ud834x"', u'z\ud834x') ++ assertScan(u'"z\\ud834\udd20x12345"', u'z%sx12345' % surrogates) ++ assertScan('"z\\udd20x"', u'z\udd20x') ++ assertScan(u'"z\ud834\udd20x"', u'z\ud834\udd20x') ++ assertScan(u'"z\ud834\\udd20x"', u'z%sx' % surrogates) ++ assertScan(u'"z\ud834x"', u'z\ud834x') ++ ++ def test_bad_escapes(self): ++ scanstring = self.json.decoder.scanstring ++ bad_escapes = [ ++ '"\\"', ++ '"\\x"', ++ '"\\u"', ++ '"\\u0"', ++ '"\\u01"', ++ '"\\u012"', ++ '"\\uz012"', ++ '"\\u0z12"', ++ '"\\u01z2"', ++ '"\\u012z"', ++ '"\\u0x12"', ++ '"\\u0X12"', ++ '"\\ud834\\"', ++ '"\\ud834\\u"', ++ '"\\ud834\\ud"', ++ '"\\ud834\\udd"', ++ '"\\ud834\\udd2"', ++ '"\\ud834\\uzdd2"', ++ '"\\ud834\\udzd2"', ++ '"\\ud834\\uddz2"', ++ '"\\ud834\\udd2z"', ++ '"\\ud834\\u0x20"', ++ '"\\ud834\\u0X20"', ++ ] ++ for s in bad_escapes: ++ with self.assertRaises(ValueError): ++ scanstring(s, 1, None, True) ++ + def test_issue3623(self): + self.assertRaises(ValueError, self.json.decoder.scanstring, b"xxx", 1, + "xxx") +diff --git a/Modules/_json.c b/Modules/_json.c +index 7c925fd..56d9ee4 100644 +--- a/Modules/_json.c ++++ b/Modules/_json.c +@@ -524,16 +524,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s + } + #ifdef Py_UNICODE_WIDE + /* Surrogate pair */ +- if ((c & 0xfc00) == 0xd800) { ++ if ((c & 0xfc00) == 0xd800 && end + 6 < len && ++ buf[next++] == '\\' && ++ buf[next++] == 'u') { + Py_UNICODE c2 = 0; +- if (end + 6 >= len) { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } +- if (buf[next++] != '\\' || buf[next++] != 'u') { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } + end += 6; + /* Decode 4 hex digits */ + for (; next < end; next++) { +@@ -554,15 +548,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s + goto bail; + } + } +- if ((c2 & 0xfc00) != 0xdc00) { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } +- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); +- } +- else if ((c & 0xfc00) == 0xdc00) { +- raise_errmsg("Unpaired low surrogate", pystr, end - 5); +- goto bail; ++ if ((c2 & 0xfc00) == 0xdc00) ++ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); ++ else ++ end -= 6; + } + #endif + } +@@ -703,16 +692,9 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next + } + #ifdef Py_UNICODE_WIDE + /* Surrogate pair */ +- if ((c & 0xfc00) == 0xd800) { ++ if ((c & 0xfc00) == 0xd800 && end + 6 < len && ++ buf[next++] == '\\' && buf[next++] == 'u') { + Py_UNICODE c2 = 0; +- if (end + 6 >= len) { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } +- if (buf[next++] != '\\' || buf[next++] != 'u') { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } + end += 6; + /* Decode 4 hex digits */ + for (; next < end; next++) { +@@ -733,15 +715,10 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next + goto bail; + } + } +- if ((c2 & 0xfc00) != 0xdc00) { +- raise_errmsg("Unpaired high surrogate", pystr, end - 5); +- goto bail; +- } +- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); +- } +- else if ((c & 0xfc00) == 0xdc00) { +- raise_errmsg("Unpaired low surrogate", pystr, end - 5); +- goto bail; ++ if ((c2 & 0xfc00) == 0xdc00) ++ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); ++ else ++ end -= 6; + } + #endif + } +-- +2.5.5 + diff --git a/SOURCES/00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch b/SOURCES/00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch new file mode 100644 index 00000000..7522dd80 --- /dev/null +++ b/SOURCES/00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch @@ -0,0 +1,101 @@ +From 6bebd55022c82829c0b15d24d2ca99edd22562df Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Wed, 4 May 2016 10:39:40 +0200 +Subject: [PATCH] use Py_ssize_t for file offset and length computations in + iteration + +--- + Lib/test/test_file2k.py | 16 +++++++++++++++- + Objects/fileobject.c | 15 +++++++-------- + 2 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py +index 5a3c354..8f94cee 100644 +--- a/Lib/test/test_file2k.py ++++ b/Lib/test/test_file2k.py +@@ -14,7 +14,7 @@ except ImportError: + threading = None + + from test import test_support +-from test.test_support import TESTFN, run_unittest ++from test.test_support import TESTFN, run_unittest, requires + from UserList import UserList + + class AutoFileTests(unittest.TestCase): +@@ -416,6 +416,20 @@ class OtherFileTests(unittest.TestCase): + finally: + os.unlink(TESTFN) + ++ @test_support.precisionbigmemtest(2**31, 2.5, dry_run=False) ++ def test_very_long_line(self, size): ++ # Issue #22526 ++ requires('largefile') ++ with open(TESTFN, "wb") as fp: ++ fp.seek(size - 1) ++ fp.write("\0") ++ with open(TESTFN, "rb") as fp: ++ for l in fp: ++ pass ++ self.assertEqual(len(l), size) ++ self.assertEqual(l.count("\0"), size) ++ l = None ++ + class FileSubclassTests(unittest.TestCase): + + def testExit(self): +diff --git a/Objects/fileobject.c b/Objects/fileobject.c +index 76cdf74..fabe207 100644 +--- a/Objects/fileobject.c ++++ b/Objects/fileobject.c +@@ -2230,7 +2230,7 @@ drop_readahead(PyFileObject *f) + (unless at EOF) and no more than bufsize. Returns negative value on + error, will set MemoryError if bufsize bytes cannot be allocated. */ + static int +-readahead(PyFileObject *f, int bufsize) ++readahead(PyFileObject *f, Py_ssize_t bufsize) + { + Py_ssize_t chunksize; + +@@ -2268,7 +2268,7 @@ readahead(PyFileObject *f, int bufsize) + logarithmic buffer growth to about 50 even when reading a 1gb line. */ + + static PyStringObject * +-readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) ++readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize) + { + PyStringObject* s; + char *bufptr; +@@ -2288,10 +2288,10 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) + bufptr++; /* Count the '\n' */ + len = bufptr - f->f_bufptr; + s = (PyStringObject *) +- PyString_FromStringAndSize(NULL, skip+len); ++ PyString_FromStringAndSize(NULL, skip + len); + if (s == NULL) + return NULL; +- memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); ++ memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len); + f->f_bufptr = bufptr; + if (bufptr == f->f_bufend) + drop_readahead(f); +@@ -2299,14 +2299,13 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) + bufptr = f->f_bufptr; + buf = f->f_buf; + f->f_buf = NULL; /* Force new readahead buffer */ +- assert(skip+len < INT_MAX); +- s = readahead_get_line_skip( +- f, (int)(skip+len), bufsize + (bufsize>>2) ); ++ assert(len <= PY_SSIZE_T_MAX - skip); ++ s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2)); + if (s == NULL) { + PyMem_Free(buf); + return NULL; + } +- memcpy(PyString_AS_STRING(s)+skip, bufptr, len); ++ memcpy(PyString_AS_STRING(s) + skip, bufptr, len); + PyMem_Free(buf); + } + return s; +-- +2.5.5 + diff --git a/SOURCES/00237-CVE-2016-0772-smtplib.patch b/SOURCES/00237-CVE-2016-0772-smtplib.patch new file mode 100644 index 00000000..b11fac10 --- /dev/null +++ b/SOURCES/00237-CVE-2016-0772-smtplib.patch @@ -0,0 +1,34 @@ +From 5b67aca6fb4246e84981d6361ba218bd52e73ac2 Mon Sep 17 00:00:00 2001 +From: Tomas Orsava +Date: Tue, 21 Jun 2016 15:52:03 +0200 +Subject: [PATCH] Raise an error when STARTTLS fails + +CVE-2016-0772 python: smtplib StartTLS stripping attack +rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647 + +Based on an upstream change by Benjamin Peterson +- in changeset 101886:b3ce713fb9be 2.7 +- https://hg.python.org/cpython/rev/b3ce713fb9be +--- + Lib/smtplib.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/Lib/smtplib.py b/Lib/smtplib.py +index dc16ef6..8bc806b 100755 +--- a/Lib/smtplib.py ++++ b/Lib/smtplib.py +@@ -655,6 +655,11 @@ class SMTP: + self.ehlo_resp = None + self.esmtp_features = {} + self.does_esmtp = 0 ++ else: ++ # RFC 3207: ++ # 501 Syntax error (no parameters allowed) ++ # 454 TLS not available due to temporary reason ++ raise SMTPResponseException(resp, reply) + return (resp, reply) + + def sendmail(self, from_addr, to_addrs, msg, mail_options=[], +-- +2.5.5 + diff --git a/SOURCES/00238-CVE-2016-5699-httplib.patch b/SOURCES/00238-CVE-2016-5699-httplib.patch new file mode 100644 index 00000000..e8cf7a4d --- /dev/null +++ b/SOURCES/00238-CVE-2016-5699-httplib.patch @@ -0,0 +1,158 @@ +From e91c46c7a1a904eba04e29cdf896c99cb546d989 Mon Sep 17 00:00:00 2001 +From: Tomas Orsava +Date: Wed, 22 Jun 2016 17:06:01 +0200 +Subject: [PATCH] Disabled HTTP header injections in httplib + +CVE-2016-5699 python: http protocol steam injection attack +rhbz#1303699 : https://bugzilla.redhat.com/show_bug.cgi?id=1303699 + +Based on an upstream change by Demian Brecht and Serhiy Storchaka +- in changeset 94951:1c45047c5102 2.7 +- https://hg.python.org/cpython/rev/1c45047c5102 +--- + Lib/httplib.py | 40 +++++++++++++++++++++++++++++++++- + Lib/test/test_httplib.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 95 insertions(+), 1 deletion(-) + +diff --git a/Lib/httplib.py b/Lib/httplib.py +index 8e02ac3..592ee57 100644 +--- a/Lib/httplib.py ++++ b/Lib/httplib.py +@@ -68,6 +68,7 @@ Req-sent-unread-response _CS_REQ_SENT + + from array import array + import os ++import re + import socket + from sys import py3kwarning + from urlparse import urlsplit +@@ -218,6 +219,34 @@ _MAXLINE = 65536 + # maximum amount of headers accepted + _MAXHEADERS = 100 + ++# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) ++# ++# VCHAR = %x21-7E ++# obs-text = %x80-FF ++# header-field = field-name ":" OWS field-value OWS ++# field-name = token ++# field-value = *( field-content / obs-fold ) ++# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] ++# field-vchar = VCHAR / obs-text ++# ++# obs-fold = CRLF 1*( SP / HTAB ) ++# ; obsolete line folding ++# ; see Section 3.2.4 ++ ++# token = 1*tchar ++# ++# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" ++# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" ++# / DIGIT / ALPHA ++# ; any VCHAR, except delimiters ++# ++# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 ++ ++# the patterns for both name and value are more leniant than RFC ++# definitions to allow for backwards compatibility ++_is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match ++_is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search ++ + + class HTTPMessage(mimetools.Message): + +@@ -956,7 +985,16 @@ class HTTPConnection: + if self.__state != _CS_REQ_STARTED: + raise CannotSendHeader() + +- hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values])) ++ header = '%s' % header ++ if not _is_legal_header_name(header): ++ raise ValueError('Invalid header name %r' % (header,)) ++ ++ values = [str(v) for v in values] ++ for one_value in values: ++ if _is_illegal_header_value(one_value): ++ raise ValueError('Invalid header value %r' % (one_value,)) ++ ++ hdr = '%s: %s' % (header, '\r\n\t'.join(values)) + self._output(hdr) + + def endheaders(self, message_body=None): +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index c29aceb..29af589 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -133,6 +133,33 @@ class HeaderTests(TestCase): + conn.putheader('Content-length',42) + self.assertTrue('Content-length: 42' in conn._buffer) + ++ conn.putheader('Foo', ' bar ') ++ self.assertIn(b'Foo: bar ', conn._buffer) ++ conn.putheader('Bar', '\tbaz\t') ++ self.assertIn(b'Bar: \tbaz\t', conn._buffer) ++ conn.putheader('Authorization', 'Bearer mytoken') ++ self.assertIn(b'Authorization: Bearer mytoken', conn._buffer) ++ conn.putheader('IterHeader', 'IterA', 'IterB') ++ self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer) ++ conn.putheader('LatinHeader', b'\xFF') ++ self.assertIn(b'LatinHeader: \xFF', conn._buffer) ++ conn.putheader('Utf8Header', b'\xc3\x80') ++ self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer) ++ conn.putheader('C1-Control', b'next\x85line') ++ self.assertIn(b'C1-Control: next\x85line', conn._buffer) ++ conn.putheader('Embedded-Fold-Space', 'is\r\n allowed') ++ self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer) ++ conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed') ++ self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer) ++ conn.putheader('Key Space', 'value') ++ self.assertIn(b'Key Space: value', conn._buffer) ++ conn.putheader('KeySpace ', 'value') ++ self.assertIn(b'KeySpace : value', conn._buffer) ++ conn.putheader(b'Nonbreak\xa0Space', 'value') ++ self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer) ++ conn.putheader(b'\xa0NonbreakSpace', 'value') ++ self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer) ++ + def test_ipv6host_header(self): + # Default host header on IPv6 transaction should wrapped by [] if + # its actual IPv6 address +@@ -152,6 +179,35 @@ class HeaderTests(TestCase): + conn.request('GET', '/foo') + self.assertTrue(sock.data.startswith(expected)) + ++ def test_invalid_headers(self): ++ conn = httplib.HTTPConnection('example.com') ++ conn.sock = FakeSocket('') ++ conn.putrequest('GET', '/') ++ ++ # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no ++ # longer allowed in header names ++ cases = ( ++ (b'Invalid\r\nName', b'ValidValue'), ++ (b'Invalid\rName', b'ValidValue'), ++ (b'Invalid\nName', b'ValidValue'), ++ (b'\r\nInvalidName', b'ValidValue'), ++ (b'\rInvalidName', b'ValidValue'), ++ (b'\nInvalidName', b'ValidValue'), ++ (b' InvalidName', b'ValidValue'), ++ (b'\tInvalidName', b'ValidValue'), ++ (b'Invalid:Name', b'ValidValue'), ++ (b':InvalidName', b'ValidValue'), ++ (b'ValidName', b'Invalid\r\nValue'), ++ (b'ValidName', b'Invalid\rValue'), ++ (b'ValidName', b'Invalid\nValue'), ++ (b'ValidName', b'InvalidValue\r\n'), ++ (b'ValidName', b'InvalidValue\r'), ++ (b'ValidName', b'InvalidValue\n'), ++ ) ++ for name, value in cases: ++ with self.assertRaisesRegexp(ValueError, 'Invalid header'): ++ conn.putheader(name, value) ++ + + class BasicTest(TestCase): + def test_status_lines(self): +-- +2.9.0 + diff --git a/SOURCES/00240-increase-smtplib-tests-timeouts.patch b/SOURCES/00240-increase-smtplib-tests-timeouts.patch new file mode 100644 index 00000000..ae61b18a --- /dev/null +++ b/SOURCES/00240-increase-smtplib-tests-timeouts.patch @@ -0,0 +1,66 @@ +diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py +index 14d0060d8ec..1bb66901880 100644 +--- a/Lib/test/test_smtplib.py ++++ b/Lib/test/test_smtplib.py +@@ -179,31 +179,31 @@ def tearDown(self): + + def testBasic(self): + # connect +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + smtp.quit() + + def testNOOP(self): +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + expected = (250, 'Ok') + self.assertEqual(smtp.noop(), expected) + smtp.quit() + + def testRSET(self): +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + expected = (250, 'Ok') + self.assertEqual(smtp.rset(), expected) + smtp.quit() + + def testNotImplemented(self): + # EHLO isn't implemented in DebuggingServer +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + expected = (502, 'Error: command "EHLO" not implemented') + self.assertEqual(smtp.ehlo(), expected) + smtp.quit() + + def testVRFY(self): + # VRFY isn't implemented in DebuggingServer +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + expected = (502, 'Error: command "VRFY" not implemented') + self.assertEqual(smtp.vrfy('nobody@nowhere.com'), expected) + self.assertEqual(smtp.verify('nobody@nowhere.com'), expected) +@@ -212,21 +212,21 @@ def testVRFY(self): + def testSecondHELO(self): + # check that a second HELO returns a message that it's a duplicate + # (this behavior is specific to smtpd.SMTPChannel) +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + smtp.helo() + expected = (503, 'Duplicate HELO/EHLO') + self.assertEqual(smtp.helo(), expected) + smtp.quit() + + def testHELP(self): +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + self.assertEqual(smtp.help(), 'Error: command "HELP" not implemented') + smtp.quit() + + def testSend(self): + # connect and send mail + m = 'A test message' +- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) ++ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + smtp.sendmail('John', 'Sally', m) + # XXX(nnorwitz): this test is flaky and dies with a bad file descriptor + # in asyncore. This sleep might help, but should really be fixed diff --git a/SOURCES/00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch b/SOURCES/00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch new file mode 100644 index 00000000..f166d019 --- /dev/null +++ b/SOURCES/00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch @@ -0,0 +1,39 @@ +From 0f12cb75c708978f9201c1dd3464d2a8572b4544 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Fri, 8 Jul 2016 20:24:10 +0200 +Subject: [PATCH] CVE-2016-5636 fix + +--- + Modules/zipimport.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/Modules/zipimport.c b/Modules/zipimport.c +index 7240cb4..2e6a61f 100644 +--- a/Modules/zipimport.c ++++ b/Modules/zipimport.c +@@ -861,6 +861,10 @@ get_data(char *archive, PyObject *toc_entry) + &date, &crc)) { + return NULL; + } ++ if (data_size < 0) { ++ PyErr_Format(ZipImportError, "negative data size"); ++ return NULL; ++ } + + fp = fopen(archive, "rb"); + if (!fp) { +@@ -895,6 +899,11 @@ get_data(char *archive, PyObject *toc_entry) + PyMarshal_ReadShortFromFile(fp); /* local header size */ + file_offset += l; /* Start of file data */ + ++ if (data_size > LONG_MAX - 1) { ++ fclose(fp); ++ PyErr_NoMemory(); ++ return NULL; ++ } + raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ? + data_size : data_size + 1); + if (raw_data == NULL) { +-- +2.7.4 + diff --git a/SOURCES/00242-CVE-2016-1000110-httpoxy.patch b/SOURCES/00242-CVE-2016-1000110-httpoxy.patch new file mode 100644 index 00000000..ada467c5 --- /dev/null +++ b/SOURCES/00242-CVE-2016-1000110-httpoxy.patch @@ -0,0 +1,121 @@ +From 3a184cc875709d4324d234a4b939d614a2c9bb0f Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Mon, 1 Aug 2016 11:20:11 +0200 +Subject: [PATCH] =?UTF-8?q?Fix=20for=20CVE-2016-1000110=20http://bugs.pyth?= + =?UTF-8?q?on.org/issue27568=20Based=20on=20the=20patch=20by=20R=C3=A9mi?= + =?UTF-8?q?=20Rampin?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + Doc/howto/urllib2.rst | 5 +++++ + Doc/library/urllib.rst | 10 ++++++++++ + Doc/library/urllib2.rst | 4 ++++ + Lib/test/test_urllib.py | 12 ++++++++++++ + Lib/urllib.py | 9 +++++++++ + 5 files changed, 40 insertions(+) + +diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst +index f84bf08..6542846 100644 +--- a/Doc/howto/urllib2.rst ++++ b/Doc/howto/urllib2.rst +@@ -523,6 +523,11 @@ setting up a `Basic Authentication`_ handler : :: + through a proxy. However, this can be enabled by extending urllib2 as + shown in the recipe [#]_. + ++.. note:: ++ ++ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; see ++ the documentation on :func:`~urllib.getproxies`. ++ + + Sockets and Layers + ================== +diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst +index c7d200d..3b9876e 100644 +--- a/Doc/library/urllib.rst ++++ b/Doc/library/urllib.rst +@@ -280,6 +280,16 @@ Utility functions + find it, looks for proxy information from Mac OSX System Configuration for + Mac OS X and Windows Systems Registry for Windows. + ++ .. note:: ++ ++ If the environment variable ``REQUEST_METHOD`` is set, which usually ++ indicates your script is running in a CGI environment, the environment ++ variable ``HTTP_PROXY`` (uppercase ``_PROXY``) will be ignored. This is ++ because that variable can be injected by a client using the "Proxy:" ++ HTTP header. If you need to use an HTTP proxy in a CGI environment, ++ either use ``ProxyHandler`` explicitly, or make sure the variable name ++ is in lowercase (or at least the ``_proxy`` suffix). ++ + .. note:: + urllib also exposes certain utility functions like splittype, splithost and + others parsing url into various components. But it is recommended to use +diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst +index 24deeb4..46fce59 100644 +--- a/Doc/library/urllib2.rst ++++ b/Doc/library/urllib2.rst +@@ -224,6 +224,10 @@ The following classes are provided: + + To disable autodetected proxy pass an empty dictionary. + ++ .. note:: ++ ++ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; ++ see the documentation on :func:`~urllib.getproxies`. + + .. class:: HTTPPasswordMgr() + +diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py +index 3a273f8..3845012 100644 +--- a/Lib/test/test_urllib.py ++++ b/Lib/test/test_urllib.py +@@ -161,6 +161,18 @@ class ProxyTests(unittest.TestCase): + self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com') + self.assertTrue(urllib.proxy_bypass_environment('anotherdomain.com')) + ++ def test_proxy_cgi_ignore(self): ++ try: ++ self.env.set('HTTP_PROXY', 'http://somewhere:3128') ++ proxies = urllib.getproxies_environment() ++ self.assertEqual('http://somewhere:3128', proxies['http']) ++ self.env.set('REQUEST_METHOD', 'GET') ++ proxies = urllib.getproxies_environment() ++ self.assertNotIn('http', proxies) ++ finally: ++ self.env.unset('REQUEST_METHOD') ++ self.env.unset('HTTP_PROXY') ++ + + class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin): + """Test urlopen() opening a fake http connection.""" +diff --git a/Lib/urllib.py b/Lib/urllib.py +index f9655f9..9b31df1 100644 +--- a/Lib/urllib.py ++++ b/Lib/urllib.py +@@ -1361,11 +1361,20 @@ def getproxies_environment(): + [Fancy]URLopener constructor. + + """ ++ # Get all variables + proxies = {} + for name, value in os.environ.items(): + name = name.lower() + if value and name[-6:] == '_proxy': + proxies[name[:-6]] = value ++ ++ # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY ++ # (non-all-lowercase) as it may be set from the web server by a "Proxy:" ++ # header from the client ++ # If "proxy" is lowercase, it will still be used thanks to the next block ++ if 'REQUEST_METHOD' in os.environ: ++ proxies.pop('http', None) ++ + return proxies + + def proxy_bypass_environment(host): +-- +2.7.4 + diff --git a/SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch b/SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch new file mode 100644 index 00000000..e28bb04c --- /dev/null +++ b/SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch @@ -0,0 +1,235 @@ + +# HG changeset patch +# User Christian Heimes +# Date 1473197135 -7200 +# Node ID 74805fd9e7343649372d0b9c76b4490b2975a674 +# Parent 6f4f19217d9be12be7a9c86cf1e118b140564b4f +Issue #27691: Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs. + +diff --git a/Lib/test/allsans.pem b/Lib/test/allsans.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/allsans.pem +@@ -0,0 +1,37 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE ++6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG ++Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm ++DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu ++A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az ++61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk ++elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb ++tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G ++kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l ++xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J ++b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/ ++EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa ++czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2 ++/CyWR2P3yLtOmA== ++-----END PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV ++BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u ++IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1 ++MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO ++Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0 ++aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB ++gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO ++ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA ++pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw ++ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp ++ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC ++AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu ++b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw ++IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly ++bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA ++AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT ++VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG ++iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f ++3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ== ++-----END CERTIFICATE----- +diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py +--- a/Lib/test/make_ssl_certs.py ++++ b/Lib/test/make_ssl_certs.py +@@ -20,7 +20,28 @@ req_template = """ + CN = {hostname} + + [req_x509_extensions] +- subjectAltName = DNS:{hostname} ++ subjectAltName = @san ++ ++ [san] ++ DNS.1 = {hostname} ++ {extra_san} ++ ++ [dir_sect] ++ C = XY ++ L = Castle Anthrax ++ O = Python Software Foundation ++ CN = dirname example ++ ++ [princ_name] ++ realm = EXP:0, GeneralString:KERBEROS.REALM ++ principal_name = EXP:1, SEQUENCE:principal_seq ++ ++ [principal_seq] ++ name_type = EXP:0, INTEGER:1 ++ name_string = EXP:1, SEQUENCE:principals ++ ++ [principals] ++ princ1 = GeneralString:username + + [ ca ] + default_ca = CA_default +@@ -67,7 +88,7 @@ req_template = """ + + here = os.path.abspath(os.path.dirname(__file__)) + +-def make_cert_key(hostname, sign=False): ++def make_cert_key(hostname, sign=False, extra_san=''): + print("creating cert for " + hostname) + tempnames = [] + for i in range(3): +@@ -75,8 +96,9 @@ def make_cert_key(hostname, sign=False): + tempnames.append(f.name) + req_file, cert_file, key_file = tempnames + try: ++ req = req_template.format(hostname=hostname, extra_san=extra_san) + with open(req_file, 'w') as f: +- f.write(req_template.format(hostname=hostname)) ++ f.write(req) + args = ['req', '-new', '-days', '3650', '-nodes', + '-newkey', 'rsa:1024', '-keyout', key_file, + '-config', req_file] +@@ -120,7 +142,7 @@ def make_ca(): + f.write('unique_subject = no') + + with tempfile.NamedTemporaryFile("w") as t: +- t.write(req_template.format(hostname='our-ca-server')) ++ t.write(req_template.format(hostname='our-ca-server', extra_san='')) + t.flush() + with tempfile.NamedTemporaryFile() as f: + args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes', +@@ -171,6 +193,25 @@ if __name__ == '__main__': + f.write(key) + f.write(cert) + ++ extra_san = [ ++ 'otherName.1 = 1.2.3.4;UTF8:some other identifier', ++ 'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name', ++ 'email.1 = user@example.org', ++ 'DNS.2 = www.example.org', ++ # GEN_X400 ++ 'dirName.1 = dir_sect', ++ # GEN_EDIPARTY ++ 'URI.1 = https://www.python.org/', ++ 'IP.1 = 127.0.0.1', ++ 'IP.2 = ::1', ++ 'RID.1 = 1.2.3.4.5', ++ ] ++ ++ cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san)) ++ with open('allsans.pem', 'w') as f: ++ f.write(key) ++ f.write(cert) ++ + unmake_ca() + print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber") + check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout']) +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index fa59641..9d5816b 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -57,6 +57,8 @@ CRLFILE = data_file("revocation.crl") + SIGNED_CERTFILE = data_file("keycert3.pem") + SIGNED_CERTFILE2 = data_file("keycert4.pem") + SIGNING_CA = data_file("pycacert.pem") ++# cert with all kinds of subject alt names ++ALLSANFILE = data_file("allsans.pem") + + SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem") + +@@ -236,6 +238,28 @@ class BasicSocketTests(unittest.TestCase): + ('IP Address', '2001:DB8:0:0:0:0:0:1\n')) + ) + ++ def test_parse_all_sans(self): ++ p = ssl._ssl._test_decode_cert(ALLSANFILE) ++ self.assertEqual(p['subjectAltName'], ++ ( ++ ('DNS', 'allsans'), ++ ('othername', ''), ++ ('othername', ''), ++ ('email', 'user@example.org'), ++ ('DNS', 'www.example.org'), ++ ('DirName', ++ ((('countryName', 'XY'),), ++ (('localityName', 'Castle Anthrax'),), ++ (('organizationName', 'Python Software Foundation'),), ++ (('commonName', 'dirname example'),))), ++ ('URI', 'https://www.python.org/'), ++ ('IP Address', '127.0.0.1'), ++ ('IP Address', '0:0:0:0:0:0:0:1\n'), ++ ('Registered ID', '1.2.3.4.5') ++ ) ++ ) ++ ++ + def test_DER_to_PEM(self): + with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f: + pem = f.read() +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -953,6 +953,35 @@ static PyObject * + PyTuple_SET_ITEM(t, 1, v); + break; + ++ case GEN_RID: ++ t = PyTuple_New(2); ++ if (t == NULL) ++ goto fail; ++ ++ v = PyUnicode_FromString("Registered ID"); ++ if (v == NULL) { ++ Py_DECREF(t); ++ goto fail; ++ } ++ PyTuple_SET_ITEM(t, 0, v); ++ ++ len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid); ++ if (len < 0) { ++ Py_DECREF(t); ++ _setSSLError(NULL, 0, __FILE__, __LINE__); ++ goto fail; ++ } else if (len >= (int)sizeof(buf)) { ++ v = PyUnicode_FromString(""); ++ } else { ++ v = PyUnicode_FromStringAndSize(buf, len); ++ } ++ if (v == NULL) { ++ Py_DECREF(t); ++ goto fail; ++ } ++ PyTuple_SET_ITEM(t, 1, v); ++ break; ++ + default: + /* for everything else, we use the OpenSSL print form */ + switch (gntype) { +@@ -978,8 +1007,12 @@ static PyObject * + goto fail; + } + vptr = strchr(buf, ':'); +- if (vptr == NULL) ++ if (vptr == NULL) { ++ PyErr_Format(PyExc_ValueError, ++ "Invalid value %.200s", ++ buf); + goto fail; ++ } + t = PyTuple_New(2); + if (t == NULL) + goto fail; + diff --git a/SOURCES/00257-threading-wait-clamp-remaining-time.patch b/SOURCES/00257-threading-wait-clamp-remaining-time.patch new file mode 100644 index 00000000..526d9411 --- /dev/null +++ b/SOURCES/00257-threading-wait-clamp-remaining-time.patch @@ -0,0 +1,20 @@ +diff --git a/Lib/threading.py b/Lib/threading.py +index e4c7f35..91b3849 100644 +--- a/Lib/threading.py ++++ b/Lib/threading.py +@@ -351,13 +351,14 @@ class _Condition(_Verbose): + gotit = waiter.acquire(0) + if gotit: + break +- remaining = endtime - _time() ++ remaining = min(endtime - _time(), timeout) + if remaining <= 0: + break + if balancing: + delay = min(delay * 2, remaining, 0.05) + else: + delay = remaining ++ endtime = _time() + remaining + _sleep(delay) + if not gotit: + if __debug__: diff --git a/SOURCES/00263-fix-ssl-reference-leaks.patch b/SOURCES/00263-fix-ssl-reference-leaks.patch new file mode 100644 index 00000000..34d22c62 --- /dev/null +++ b/SOURCES/00263-fix-ssl-reference-leaks.patch @@ -0,0 +1,14 @@ +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index a3ea254..d0a3830 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -2564,7 +2564,9 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) + } + SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); ++ Py_XDECREF(keyfile_bytes); + PyMem_Free(pw_info.password); ++ PyMem_Free(certfile_bytes); + Py_RETURN_NONE; + + error: diff --git a/SOURCES/00265-protect-key-list-during-fork.patch b/SOURCES/00265-protect-key-list-during-fork.patch new file mode 100644 index 00000000..1f820f8c --- /dev/null +++ b/SOURCES/00265-protect-key-list-during-fork.patch @@ -0,0 +1,114 @@ +diff --git a/Include/pythread.h b/Include/pythread.h +index dfd6157..f3e6259 100644 +--- a/Include/pythread.h ++++ b/Include/pythread.h +@@ -30,6 +30,8 @@ PyAPI_FUNC(void) PyThread_delete_key(int); + PyAPI_FUNC(int) PyThread_set_key_value(int, void *); + PyAPI_FUNC(void *) PyThread_get_key_value(int); + PyAPI_FUNC(void) PyThread_delete_key_value(int key); ++PyAPI_FUNC(int) _PyThread_AcquireKeyLock(void); ++PyAPI_FUNC(void) _PyThread_ReleaseKeyLock(void); + + /* Cleanup after a fork */ + PyAPI_FUNC(void) PyThread_ReInitTLS(void); +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index 022d7aa..8f6cbb2 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -65,6 +65,10 @@ corresponding Unix manual entries for more information on calls."); + #include "osdefs.h" + #endif + ++#ifdef WITH_THREAD ++#include "pythread.h" ++#endif ++ + #ifdef HAVE_SYS_TYPES_H + #include + #endif /* HAVE_SYS_TYPES_H */ +@@ -3796,7 +3800,18 @@ posix_fork1(PyObject *self, PyObject *noargs) + pid_t pid; + int result = 0; + _PyImport_AcquireLock(); ++#ifdef WITH_THREAD ++ if (_PyThread_AcquireKeyLock() == 0) { ++ _PyImport_ReleaseLock(); ++ PyErr_SetString(PyExc_RuntimeError, ++ "could not acquire thread key lock"); ++ return NULL; ++ } ++#endif + pid = fork1(); ++#ifdef WITH_THREAD ++ _PyThread_ReleaseKeyLock(); ++#endif + if (pid == 0) { + /* child: this clobbers and resets the import lock. */ + PyOS_AfterFork(); +@@ -3829,7 +3844,18 @@ posix_fork(PyObject *self, PyObject *noargs) + pid_t pid; + int result = 0; + _PyImport_AcquireLock(); ++#ifdef WITH_THREAD ++ if (_PyThread_AcquireKeyLock() == 0) { ++ _PyImport_ReleaseLock(); ++ PyErr_SetString(PyExc_RuntimeError, ++ "could not acquire thread key lock"); ++ return NULL; ++ } ++#endif + pid = fork(); ++#ifdef WITH_THREAD ++ _PyThread_ReleaseKeyLock(); ++#endif + if (pid == 0) { + /* child: this clobbers and resets the import lock. */ + PyOS_AfterFork(); +@@ -3955,7 +3981,18 @@ posix_forkpty(PyObject *self, PyObject *noargs) + pid_t pid; + + _PyImport_AcquireLock(); ++#ifdef WITH_THREAD ++ if (_PyThread_AcquireKeyLock() == 0) { ++ _PyImport_ReleaseLock(); ++ PyErr_SetString(PyExc_RuntimeError, ++ "could not acquire thread key lock"); ++ return NULL; ++ } ++#endif + pid = forkpty(&master_fd, NULL, NULL, NULL); ++#ifdef WITH_THREAD ++ _PyThread_ReleaseKeyLock(); ++#endif + if (pid == 0) { + /* child: this clobbers and resets the import lock. */ + PyOS_AfterFork(); +diff --git a/Python/thread.c b/Python/thread.c +index dd333e8..957739e 100644 +--- a/Python/thread.c ++++ b/Python/thread.c +@@ -387,6 +387,24 @@ PyThread_delete_key_value(int key) + PyThread_release_lock(keymutex); + } + ++int ++_PyThread_AcquireKeyLock(void) ++{ ++ if (keymutex == NULL) { ++ keymutex = PyThread_allocate_lock(); ++ } ++ if (keymutex == NULL) { ++ return 0; ++ } ++ return PyThread_acquire_lock(keymutex, 1); ++} ++ ++void ++_PyThread_ReleaseKeyLock(void) ++{ ++ PyThread_release_lock(keymutex); ++} ++ + /* Forget everything not associated with the current thread id. + * This function is called from PyOS_AfterFork(). It is necessary + * because other thread ids which were in use at the time of the fork diff --git a/SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch b/SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch new file mode 100644 index 00000000..aa2d6ef1 --- /dev/null +++ b/SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch @@ -0,0 +1,376 @@ +diff --git a/Lib/shutil.py b/Lib/shutil.py +index 420802f..d0ff2ef 100644 +--- a/Lib/shutil.py ++++ b/Lib/shutil.py +@@ -446,17 +446,24 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): + zip_filename, base_dir) + + if not dry_run: +- zip = zipfile.ZipFile(zip_filename, "w", +- compression=zipfile.ZIP_DEFLATED) +- +- for dirpath, dirnames, filenames in os.walk(base_dir): +- for name in filenames: +- path = os.path.normpath(os.path.join(dirpath, name)) +- if os.path.isfile(path): +- zip.write(path, path) ++ with zipfile.ZipFile(zip_filename, "w", ++ compression=zipfile.ZIP_DEFLATED) as zf: ++ path = os.path.normpath(base_dir) ++ zf.write(path, path) ++ if logger is not None: ++ logger.info("adding '%s'", path) ++ for dirpath, dirnames, filenames in os.walk(base_dir): ++ for name in sorted(dirnames): ++ path = os.path.normpath(os.path.join(dirpath, name)) ++ zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) +- zip.close() ++ for name in filenames: ++ path = os.path.normpath(os.path.join(dirpath, name)) ++ if os.path.isfile(path): ++ zf.write(path, path) ++ if logger is not None: ++ logger.info("adding '%s'", path) + + return zip_filename + +diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py +index 9bdb724..9238489 100644 +--- a/Lib/test/test_shutil.py ++++ b/Lib/test/test_shutil.py +@@ -10,13 +10,13 @@ import os.path + import errno + from os.path import splitdrive + from distutils.spawn import find_executable, spawn +-from shutil import (_make_tarball, _make_zipfile, make_archive, ++from shutil import (make_archive, + register_archive_format, unregister_archive_format, + get_archive_formats) + import tarfile + import warnings + +-from test import test_support ++from test import test_support as support + from test.test_support import TESTFN, check_warnings, captured_stdout + + TESTFN2 = TESTFN + "2" +@@ -372,139 +372,135 @@ class TestShutil(unittest.TestCase): + @unittest.skipUnless(zlib, "requires zlib") + def test_make_tarball(self): + # creating something to tar +- tmpdir = self.mkdtemp() +- self.write_file([tmpdir, 'file1'], 'xxx') +- self.write_file([tmpdir, 'file2'], 'xxx') +- os.mkdir(os.path.join(tmpdir, 'sub')) +- self.write_file([tmpdir, 'sub', 'file3'], 'xxx') ++ root_dir, base_dir = self._create_files('') + + tmpdir2 = self.mkdtemp() + # force shutil to create the directory + os.rmdir(tmpdir2) +- unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], ++ unittest.skipUnless(splitdrive(root_dir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive") + + base_name = os.path.join(tmpdir2, 'archive') + + # working with relative paths to avoid tar warnings +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- _make_tarball(splitdrive(base_name)[1], '.') +- finally: +- os.chdir(old_dir) ++ make_archive(splitdrive(base_name)[1], 'gztar', root_dir, '.') + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertTrue(os.path.isfile(tarball)) ++ self.assertTrue(tarfile.is_tarfile(tarball)) ++ with tarfile.open(tarball, 'r:gz') as tf: ++ self.assertEqual(sorted(tf.getnames()), ++ ['.', './file1', './file2', ++ './sub', './sub/file3', './sub2']) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- _make_tarball(splitdrive(base_name)[1], '.', compress=None) +- finally: +- os.chdir(old_dir) ++ make_archive(splitdrive(base_name)[1], 'tar', root_dir, '.') + tarball = base_name + '.tar' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertTrue(os.path.isfile(tarball)) ++ self.assertTrue(tarfile.is_tarfile(tarball)) ++ with tarfile.open(tarball, 'r') as tf: ++ self.assertEqual(sorted(tf.getnames()), ++ ['.', './file1', './file2', ++ './sub', './sub/file3', './sub2']) + + def _tarinfo(self, path): +- tar = tarfile.open(path) +- try: ++ with tarfile.open(path) as tar: + names = tar.getnames() + names.sort() + return tuple(names) +- finally: +- tar.close() + +- def _create_files(self): ++ def _create_files(self, base_dir='dist'): + # creating something to tar +- tmpdir = self.mkdtemp() +- dist = os.path.join(tmpdir, 'dist') +- os.mkdir(dist) +- self.write_file([dist, 'file1'], 'xxx') +- self.write_file([dist, 'file2'], 'xxx') ++ root_dir = self.mkdtemp() ++ dist = os.path.join(root_dir, base_dir) ++ if not os.path.isdir(dist): ++ os.makedirs(dist) ++ self.write_file((dist, 'file1'), 'xxx') ++ self.write_file((dist, 'file2'), 'xxx') + os.mkdir(os.path.join(dist, 'sub')) +- self.write_file([dist, 'sub', 'file3'], 'xxx') ++ self.write_file((dist, 'sub', 'file3'), 'xxx') + os.mkdir(os.path.join(dist, 'sub2')) +- tmpdir2 = self.mkdtemp() +- base_name = os.path.join(tmpdir2, 'archive') +- return tmpdir, tmpdir2, base_name ++ if base_dir: ++ self.write_file((root_dir, 'outer'), 'xxx') ++ return root_dir, base_dir + + @unittest.skipUnless(zlib, "Requires zlib") +- @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), ++ @unittest.skipUnless(find_executable('tar'), + 'Need the tar command to run') + def test_tarfile_vs_tar(self): +- tmpdir, tmpdir2, base_name = self._create_files() +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- _make_tarball(base_name, 'dist') +- finally: +- os.chdir(old_dir) ++ root_dir, base_dir = self._create_files() ++ base_name = os.path.join(self.mkdtemp(), 'archive') ++ make_archive(base_name, 'gztar', root_dir, base_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertTrue(os.path.isfile(tarball)) + + # now create another tarball using `tar` +- tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') +- tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] +- gzip_cmd = ['gzip', '-f9', 'archive2.tar'] +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- with captured_stdout() as s: +- spawn(tar_cmd) +- spawn(gzip_cmd) +- finally: +- os.chdir(old_dir) ++ tarball2 = os.path.join(root_dir, 'archive2.tar') ++ tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir] ++ with support.change_cwd(root_dir), captured_stdout(): ++ spawn(tar_cmd) + +- self.assertTrue(os.path.exists(tarball2)) ++ self.assertTrue(os.path.isfile(tarball2)) + # let's compare both tarballs + self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2)) + + # trying an uncompressed one +- base_name = os.path.join(tmpdir2, 'archive') +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- _make_tarball(base_name, 'dist', compress=None) +- finally: +- os.chdir(old_dir) ++ make_archive(base_name, 'tar', root_dir, base_dir) + tarball = base_name + '.tar' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertTrue(os.path.isfile(tarball)) + + # now for a dry_run +- base_name = os.path.join(tmpdir2, 'archive') +- old_dir = os.getcwd() +- os.chdir(tmpdir) +- try: +- _make_tarball(base_name, 'dist', compress=None, dry_run=True) +- finally: +- os.chdir(old_dir) ++ make_archive(base_name, 'tar', root_dir, base_dir, dry_run=True) + tarball = base_name + '.tar' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertTrue(os.path.isfile(tarball)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') + def test_make_zipfile(self): +- # creating something to tar +- tmpdir = self.mkdtemp() +- self.write_file([tmpdir, 'file1'], 'xxx') +- self.write_file([tmpdir, 'file2'], 'xxx') ++ # creating something to zip ++ root_dir, base_dir = self._create_files() ++ base_name = os.path.join(self.mkdtemp(), 'archive') + +- tmpdir2 = self.mkdtemp() +- # force shutil to create the directory +- os.rmdir(tmpdir2) +- base_name = os.path.join(tmpdir2, 'archive') +- _make_zipfile(base_name, tmpdir) ++ res = make_archive(base_name, 'zip', root_dir, base_dir) + +- # check if the compressed tarball was created +- tarball = base_name + '.zip' +- self.assertTrue(os.path.exists(tarball)) ++ self.assertEqual(res, base_name + '.zip') ++ self.assertTrue(os.path.isfile(res)) ++ self.assertTrue(zipfile.is_zipfile(res)) ++ with zipfile.ZipFile(res) as zf: ++ self.assertEqual(sorted(zf.namelist()), ++ ['dist/', 'dist/file1', 'dist/file2', ++ 'dist/sub/', 'dist/sub/file3', 'dist/sub2/']) + ++ @unittest.skipUnless(zlib, "Requires zlib") ++ @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') ++ @unittest.skipUnless(find_executable('zip'), ++ 'Need the zip command to run') ++ def test_zipfile_vs_zip(self): ++ root_dir, base_dir = self._create_files() ++ base_name = os.path.join(self.mkdtemp(), 'archive') ++ archive = make_archive(base_name, 'zip', root_dir, base_dir) ++ ++ # check if ZIP file was created ++ self.assertEqual(archive, base_name + '.zip') ++ self.assertTrue(os.path.isfile(archive)) ++ ++ # now create another ZIP file using `zip` ++ archive2 = os.path.join(root_dir, 'archive2.zip') ++ zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir] ++ with support.change_cwd(root_dir): ++ spawn(zip_cmd) ++ ++ self.assertTrue(os.path.isfile(archive2)) ++ # let's compare both ZIP files ++ with zipfile.ZipFile(archive) as zf: ++ names = zf.namelist() ++ with zipfile.ZipFile(archive2) as zf: ++ names2 = zf.namelist() ++ self.assertEqual(sorted(names), sorted(names2)) + + def test_make_archive(self): + tmpdir = self.mkdtemp() +@@ -521,39 +517,36 @@ class TestShutil(unittest.TestCase): + else: + group = owner = 'root' + +- base_dir, root_dir, base_name = self._create_files() +- base_name = os.path.join(self.mkdtemp() , 'archive') ++ root_dir, base_dir = self._create_files() ++ base_name = os.path.join(self.mkdtemp(), 'archive') + res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, + group=group) +- self.assertTrue(os.path.exists(res)) ++ self.assertTrue(os.path.isfile(res)) + + res = make_archive(base_name, 'zip', root_dir, base_dir) +- self.assertTrue(os.path.exists(res)) ++ self.assertTrue(os.path.isfile(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner=owner, group=group) +- self.assertTrue(os.path.exists(res)) ++ self.assertTrue(os.path.isfile(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner='kjhkjhkjg', group='oihohoh') +- self.assertTrue(os.path.exists(res)) ++ self.assertTrue(os.path.isfile(res)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + def test_tarfile_root_owner(self): +- tmpdir, tmpdir2, base_name = self._create_files() +- old_dir = os.getcwd() +- os.chdir(tmpdir) ++ root_dir, base_dir = self._create_files() ++ base_name = os.path.join(self.mkdtemp(), 'archive') + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] +- try: +- archive_name = _make_tarball(base_name, 'dist', compress=None, +- owner=owner, group=group) +- finally: +- os.chdir(old_dir) ++ with support.change_cwd(root_dir): ++ archive_name = make_archive(base_name, 'gztar', root_dir, 'dist', ++ owner=owner, group=group) + + # check if the compressed tarball was created +- self.assertTrue(os.path.exists(archive_name)) ++ self.assertTrue(os.path.isfile(archive_name)) + + # now checks the rights + archive = tarfile.open(archive_name) +@@ -859,7 +852,7 @@ class TestCopyFile(unittest.TestCase): + + + def test_main(): +- test_support.run_unittest(TestShutil, TestMove, TestCopyFile) ++ support.run_unittest(TestShutil, TestMove, TestCopyFile) + + if __name__ == '__main__': + test_main() +diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py +index 42c1b4d..98a9275 100644 +--- a/Lib/test/test_support.py ++++ b/Lib/test/test_support.py +@@ -491,6 +491,33 @@ TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid()) + SAVEDCWD = os.getcwd() + + @contextlib.contextmanager ++def change_cwd(path, quiet=False): ++ """Return a context manager that changes the current working directory. ++ ++ Arguments: ++ ++ path: the directory to use as the temporary current working directory. ++ ++ quiet: if False (the default), the context manager raises an exception ++ on error. Otherwise, it issues only a warning and keeps the current ++ working directory the same. ++ ++ """ ++ saved_dir = os.getcwd() ++ try: ++ os.chdir(path) ++ except OSError: ++ if not quiet: ++ raise ++ warnings.warn('tests may fail, unable to change CWD to: ' + path, ++ RuntimeWarning, stacklevel=3) ++ try: ++ yield os.getcwd() ++ finally: ++ os.chdir(saved_dir) ++ ++ ++@contextlib.contextmanager + def temp_cwd(name='tempcwd', quiet=False): + """ + Context manager that creates a temporary directory and set it as CWD. diff --git a/SOURCES/00268-set-stream-name-to-None.patch b/SOURCES/00268-set-stream-name-to-None.patch new file mode 100644 index 00000000..0a79050f --- /dev/null +++ b/SOURCES/00268-set-stream-name-to-None.patch @@ -0,0 +1,20 @@ + +# HG changeset patch +# User Vinay Sajip +# Date 1402737594 -3600 +# Node ID bb8b0c7fefd0c5ed99b3f336178a4f9554a1d0ef +# Parent 31adcc4c43916f7448c9dd8048ad5be7e5bb6456 +Issue #21742: Set stream to None after closing. + +diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py +--- a/Lib/logging/handlers.py ++++ b/Lib/logging/handlers.py +@@ -423,6 +423,7 @@ class WatchedFileHandler(logging.FileHan + # we have an open file handle, clean it up + self.stream.flush() + self.stream.close() ++ self.stream = None # See Issue #21742: _open () might fail. + # open a new file handle and get new stat info from that fd + self.stream = self._open() + self._statstream() + diff --git a/SOURCES/00275-fix-fnctl-with-integer-on-big-endian.patch b/SOURCES/00275-fix-fnctl-with-integer-on-big-endian.patch new file mode 100644 index 00000000..c14b9817 --- /dev/null +++ b/SOURCES/00275-fix-fnctl-with-integer-on-big-endian.patch @@ -0,0 +1,22 @@ +diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c +index 997867a..2bd2f55 100644 +--- a/Modules/fcntlmodule.c ++++ b/Modules/fcntlmodule.c +@@ -34,7 +34,7 @@ fcntl_fcntl(PyObject *self, PyObject *args) + { + int fd; + int code; +- long arg; ++ int arg; + int ret; + char *str; + Py_ssize_t len; +@@ -61,7 +61,7 @@ fcntl_fcntl(PyObject *self, PyObject *args) + PyErr_Clear(); + arg = 0; + if (!PyArg_ParseTuple(args, +- "O&i|l;fcntl requires a file or file descriptor," ++ "O&i|I;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + conv_descriptor, &fd, &code, &arg)) { + return NULL; diff --git a/SOURCES/00276-increase-imaplib-MAXLINE.patch b/SOURCES/00276-increase-imaplib-MAXLINE.patch new file mode 100644 index 00000000..34da36bc --- /dev/null +++ b/SOURCES/00276-increase-imaplib-MAXLINE.patch @@ -0,0 +1,22 @@ +diff --git a/Lib/imaplib.py b/Lib/imaplib.py +index 4586fb3..d8243e5 100644 +--- a/Lib/imaplib.py ++++ b/Lib/imaplib.py +@@ -37,11 +37,12 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first + + # Maximal line length when calling readline(). This is to prevent + # reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) +-# don't specify a line length. RFC 2683 however suggests limiting client +-# command lines to 1000 octets and server command lines to 8000 octets. +-# We have selected 10000 for some extra margin and since that is supposedly +-# also what UW and Panda IMAP does. +-_MAXLINE = 10000 ++# don't specify a line length. RFC 2683 suggests limiting client ++# command lines to 1000 octets and that servers should be prepared ++# to accept command lines up to 8000 octets, so we used to use 10K here. ++# In the modern world (eg: gmail) the response to, for example, a ++# search command can be quite large, so we now use 1M. ++_MAXLINE = 1000000 + + + # Commands diff --git a/SOURCES/00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch b/SOURCES/00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch new file mode 100644 index 00000000..282437fc --- /dev/null +++ b/SOURCES/00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch @@ -0,0 +1,91 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1417319735 18000 +# Node ID 62bd574e95d5ec4b37ca8f72ae6523ea7d6c11cd +# Parent 1ac5aec658f6972c3372f139ce69ee6799dc0b2e +add context parameter to xmlrpclib.ServerProxy (#22960) + +Patch from Alex Gaynor. + +diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst +--- a/Doc/library/xmlrpclib.rst ++++ b/Doc/library/xmlrpclib.rst +@@ -39,7 +39,7 @@ between conformable Python objects and X + For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate + and hostname checks by default + +-.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) ++.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]]) + + A :class:`ServerProxy` instance is an object that manages communication with a + remote XML-RPC server. The required first argument is a URI (Uniform Resource +@@ -57,11 +57,13 @@ between conformable Python objects and X + :class:`datetime.datetime` objects may be passed to calls. + + Both the HTTP and HTTPS transports support the URL syntax extension for HTTP +- Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass`` ++ Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass`` + portion will be base64-encoded as an HTTP 'Authorization' header, and sent to + the remote server as part of the connection process when invoking an XML-RPC + method. You only need to use this if the remote server requires a Basic +- Authentication user and password. ++ Authentication user and password. If an HTTPS url is provided, *context* may ++ be :class:`ssl.SSLContext` and configures the SSL settings of the underlying ++ HTTPS connection. + + The returned instance is a proxy object with methods that can be used to invoke + corresponding RPC calls on the remote server. If the remote server supports the +@@ -131,6 +133,9 @@ between conformable Python objects and X + *__dict__* attribute and don't have a base class that is marshalled in a + special way. + ++ .. versionchanged:: 2.7.9 ++ Added the *context* argument. ++ + + .. seealso:: + +diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py +--- a/Lib/xmlrpclib.py ++++ b/Lib/xmlrpclib.py +@@ -1478,6 +1478,10 @@ class Transport: + class SafeTransport(Transport): + """Handles an HTTPS transaction to an XML-RPC server.""" + ++ def __init__(self, use_datetime=0, context=None): ++ Transport.__init__(self, use_datetime=use_datetime) ++ self.context = context ++ + # FIXME: mostly untested + + def make_connection(self, host): +@@ -1493,7 +1497,7 @@ class SafeTransport(Transport): + ) + else: + chost, self._extra_headers, x509 = self.get_host_info(host) +- self._connection = host, HTTPS(chost, None, **(x509 or {})) ++ self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {})) + return self._connection[1] + + ## +@@ -1536,7 +1540,7 @@ class ServerProxy: + """ + + def __init__(self, uri, transport=None, encoding=None, verbose=0, +- allow_none=0, use_datetime=0): ++ allow_none=0, use_datetime=0, context=None): + # establish a "logical" server connection + + if isinstance(uri, unicode): +@@ -1553,7 +1557,7 @@ class ServerProxy: + + if transport is None: + if type == "https": +- transport = SafeTransport(use_datetime=use_datetime) ++ transport = SafeTransport(use_datetime=use_datetime, context=context) + else: + transport = Transport(use_datetime=use_datetime) + self.__transport = transport + + diff --git a/SOURCES/00282-obmalloc-mmap-threshold.patch b/SOURCES/00282-obmalloc-mmap-threshold.patch new file mode 100644 index 00000000..fde9c3f5 --- /dev/null +++ b/SOURCES/00282-obmalloc-mmap-threshold.patch @@ -0,0 +1,157 @@ +Make it more likely for the system allocator to release free()d memory arenas on glibc-based systems. +Patch by Charles-François Natali. +https://bugs.python.org/issue20494 + +diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c +--- a/Objects/obmalloc.c ++++ b/Objects/obmalloc.c +@@ -2,6 +2,13 @@ + + #ifdef WITH_PYMALLOC + ++#ifdef HAVE_MMAP ++ #include ++ #ifdef MAP_ANONYMOUS ++ #define ARENAS_USE_MMAP ++ #endif ++#endif ++ + #ifdef WITH_VALGRIND + #include + +@@ -75,7 +82,8 @@ static int running_on_valgrind = -1; + * Allocation strategy abstract: + * + * For small requests, the allocator sub-allocates blocks of memory. +- * Requests greater than 256 bytes are routed to the system's allocator. ++ * Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the ++ * system's allocator. + * + * Small requests are grouped in size classes spaced 8 bytes apart, due + * to the required valid alignment of the returned address. Requests of +@@ -107,10 +115,11 @@ static int running_on_valgrind = -1; + * 57-64 64 7 + * 65-72 72 8 + * ... ... ... +- * 241-248 248 30 +- * 249-256 256 31 ++ * 497-504 504 62 ++ * 505-512 512 63 + * +- * 0, 257 and up: routed to the underlying allocator. ++ * 0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying ++ * allocator. + */ + + /*==========================================================================*/ +@@ -143,10 +152,13 @@ static int running_on_valgrind = -1; + * 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256 + * 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT + * ++ * Note: a size threshold of 512 guarantees that newly created dictionaries ++ * will be allocated from preallocated memory pools on 64-bit. ++ * + * Although not required, for better performance and space efficiency, + * it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2. + */ +-#define SMALL_REQUEST_THRESHOLD 256 ++#define SMALL_REQUEST_THRESHOLD 512 + #define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT) + + /* +@@ -174,15 +186,15 @@ static int running_on_valgrind = -1; + /* + * The allocator sub-allocates blocks of memory (called arenas) aligned + * on a page boundary. This is a reserved virtual address space for the +- * current process (obtained through a malloc call). In no way this means +- * that the memory arenas will be used entirely. A malloc() is usually +- * an address range reservation for bytes, unless all pages within this +- * space are referenced subsequently. So malloc'ing big blocks and not using +- * them does not mean "wasting memory". It's an addressable range wastage... ++ * current process (obtained through a malloc()/mmap() call). In no way this ++ * means that the memory arenas will be used entirely. A malloc() is ++ * usually an address range reservation for bytes, unless all pages within ++ * this space are referenced subsequently. So malloc'ing big blocks and not ++ * using them does not mean "wasting memory". It's an addressable range ++ * wastage... + * +- * Therefore, allocating arenas with malloc is not optimal, because there is +- * some address space wastage, but this is the most portable way to request +- * memory from the system across various platforms. ++ * Arenas are allocated with mmap() on systems supporting anonymous memory ++ * mappings to reduce heap fragmentation. + */ + #define ARENA_SIZE (256 << 10) /* 256KB */ + +@@ -440,6 +452,9 @@ static poolp usedpools[2 * ((NB_SMALL_SI + , PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55) + #if NB_SMALL_SIZE_CLASSES > 56 + , PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63) ++#if NB_SMALL_SIZE_CLASSES > 64 ++#error "NB_SMALL_SIZE_CLASSES should be less than 64" ++#endif /* NB_SMALL_SIZE_CLASSES > 64 */ + #endif /* NB_SMALL_SIZE_CLASSES > 56 */ + #endif /* NB_SMALL_SIZE_CLASSES > 48 */ + #endif /* NB_SMALL_SIZE_CLASSES > 40 */ +@@ -577,7 +592,12 @@ new_arena(void) + arenaobj = unused_arena_objects; + unused_arena_objects = arenaobj->nextarena; + assert(arenaobj->address == 0); ++#ifdef ARENAS_USE_MMAP ++ arenaobj->address = (uptr)mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, ++ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++#else + arenaobj->address = (uptr)malloc(ARENA_SIZE); ++#endif + if (arenaobj->address == 0) { + /* The allocation failed: return NULL after putting the + * arenaobj back. +@@ -1054,7 +1074,11 @@ PyObject_Free(void *p) + unused_arena_objects = ao; + + /* Free the entire arena. */ ++#ifdef ARENAS_USE_MMAP ++ munmap((void *)ao->address, ARENA_SIZE); ++#else + free((void *)ao->address); ++#endif + ao->address = 0; /* mark unassociated */ + --narenas_currently_allocated; + +diff --git a/configure b/configure +--- a/configure ++++ b/configure +@@ -10164,7 +10164,7 @@ for ac_func in alarm setitimer getitimer + clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \ + gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ + getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ +- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \ ++ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \ + mremap nice pathconf pause plock poll pthread_init \ + putenv readlink realpath \ + select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ +diff --git a/configure.ac b/configure.ac +--- a/configure.ac ++++ b/configure.ac +@@ -2905,7 +2905,7 @@ AC_CHECK_FUNCS(alarm setitimer getitimer + clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \ + gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ + getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ +- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \ ++ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \ + mremap nice pathconf pause plock poll pthread_init \ + putenv readlink realpath \ + select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ +diff --git a/pyconfig.h.in b/pyconfig.h.in +--- a/pyconfig.h.in ++++ b/pyconfig.h.in +@@ -475,6 +475,9 @@ + /* Define to 1 if you have the `mktime' function. */ + #undef HAVE_MKTIME + ++/* Define to 1 if you have the `mmap' function. */ ++#undef HAVE_MMAP ++ + /* Define to 1 if you have the `mremap' function. */ + #undef HAVE_MREMAP + diff --git a/SOURCES/00285-fix-non-deterministic-read-in-test_pty.patch b/SOURCES/00285-fix-non-deterministic-read-in-test_pty.patch new file mode 100644 index 00000000..8605809b --- /dev/null +++ b/SOURCES/00285-fix-non-deterministic-read-in-test_pty.patch @@ -0,0 +1,59 @@ +diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py +index bec38c45456..f623aa09620 100644 +--- a/Lib/test/test_pty.py ++++ b/Lib/test/test_pty.py +@@ -11,6 +11,7 @@ + import select + import signal + import socket ++import io # readline + import unittest + + TEST_STRING_1 = "I wish to buy a fish license.\n" +@@ -24,6 +25,16 @@ def debug(msg): + pass + + ++# Note that os.read() is nondeterministic so we need to be very careful ++# to make the test suite deterministic. A normal call to os.read() may ++# give us less than expected. ++# ++# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get ++# back 'foo\r\n' at the other end. The behavior depends on the termios ++# setting. The newline translation may be OS-specific. To make the ++# test suite deterministic and OS-independent, the functions _readline ++# and normalize_output can be used. ++ + def normalize_output(data): + # Some operating systems do conversions on newline. We could possibly + # fix that by doing the appropriate termios.tcsetattr()s. I couldn't +@@ -45,6 +56,12 @@ def normalize_output(data): + + return data + ++def _readline(fd): ++ """Read one line. May block forever if no newline is read.""" ++ reader = io.FileIO(fd, mode='rb', closefd=False) ++ return reader.readline() ++ ++ + + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing + # because pty code is not too portable. +@@ -97,14 +114,14 @@ def test_basic(self): + + debug("Writing to slave_fd") + os.write(slave_fd, TEST_STRING_1) +- s1 = os.read(master_fd, 1024) ++ s1 = _readline(master_fd) + self.assertEqual('I wish to buy a fish license.\n', + normalize_output(s1)) + + debug("Writing chunked output") + os.write(slave_fd, TEST_STRING_2[:5]) + os.write(slave_fd, TEST_STRING_2[5:]) +- s2 = os.read(master_fd, 1024) ++ s2 = _readline(master_fd) + self.assertEqual('For my pet fish, Eric.\n', normalize_output(s2)) + + os.close(slave_fd) diff --git a/SOURCES/00287-fix-thread-hanging-on-inaccessible-nfs-server.patch b/SOURCES/00287-fix-thread-hanging-on-inaccessible-nfs-server.patch new file mode 100644 index 00000000..1dbb62f9 --- /dev/null +++ b/SOURCES/00287-fix-thread-hanging-on-inaccessible-nfs-server.patch @@ -0,0 +1,135 @@ +diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c +index 4a71a57ec0d..2b40ada195a 100644 +--- a/Modules/_io/fileio.c ++++ b/Modules/_io/fileio.c +@@ -146,9 +146,15 @@ dircheck(fileio* self, PyObject *nameobj) + { + #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) + struct stat buf; ++ int res; + if (self->fd < 0) + return 0; +- if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { ++ ++ Py_BEGIN_ALLOW_THREADS ++ res = fstat(self->fd, &buf); ++ Py_END_ALLOW_THREADS ++ ++ if (res == 0 && S_ISDIR(buf.st_mode)) { + errno = EISDIR; + PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); + return -1; +@@ -162,17 +168,34 @@ check_fd(int fd) + { + #if defined(HAVE_FSTAT) + struct stat buf; +- if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { +- PyObject *exc; +- char *msg = strerror(EBADF); +- exc = PyObject_CallFunction(PyExc_OSError, "(is)", +- EBADF, msg); +- PyErr_SetObject(PyExc_OSError, exc); +- Py_XDECREF(exc); +- return -1; ++ int res; ++ PyObject *exc; ++ char *msg; ++ ++ if (!_PyVerify_fd(fd)) { ++ goto badfd; + } +-#endif ++ ++ Py_BEGIN_ALLOW_THREADS ++ res = fstat(fd, &buf); ++ Py_END_ALLOW_THREADS ++ ++ if (res < 0 && errno == EBADF) { ++ goto badfd; ++ } ++ + return 0; ++ ++badfd: ++ msg = strerror(EBADF); ++ exc = PyObject_CallFunction(PyExc_OSError, "(is)", ++ EBADF, msg); ++ PyErr_SetObject(PyExc_OSError, exc); ++ Py_XDECREF(exc); ++ return -1; ++#else ++ return 0; ++#endif + } + + +@@ -519,9 +542,19 @@ new_buffersize(fileio *self, size_t currentsize) + #ifdef HAVE_FSTAT + off_t pos, end; + struct stat st; +- if (fstat(self->fd, &st) == 0) { ++ int res; ++ ++ Py_BEGIN_ALLOW_THREADS ++ res = fstat(self->fd, &st); ++ Py_END_ALLOW_THREADS ++ ++ if (res == 0) { + end = st.st_size; ++ ++ Py_BEGIN_ALLOW_THREADS + pos = lseek(self->fd, 0L, SEEK_CUR); ++ Py_END_ALLOW_THREADS ++ + /* Files claiming a size smaller than SMALLCHUNK may + actually be streaming pseudo-files. In this case, we + apply the more aggressive algorithm below. +diff --git a/Objects/fileobject.c b/Objects/fileobject.c +index 2f63c374d1e..8d1c5812f0d 100644 +--- a/Objects/fileobject.c ++++ b/Objects/fileobject.c +@@ -121,10 +121,15 @@ dircheck(PyFileObject* f) + { + #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) + struct stat buf; ++ int res; + if (f->f_fp == NULL) + return f; +- if (fstat(fileno(f->f_fp), &buf) == 0 && +- S_ISDIR(buf.st_mode)) { ++ ++ Py_BEGIN_ALLOW_THREADS ++ res = fstat(fileno(f->f_fp), &buf); ++ Py_END_ALLOW_THREADS ++ ++ if (res == 0 && S_ISDIR(buf.st_mode)) { + char *msg = strerror(EISDIR); + PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)", + EISDIR, msg, f->f_name); +@@ -1010,7 +1015,13 @@ new_buffersize(PyFileObject *f, size_t currentsize) + #ifdef HAVE_FSTAT + off_t pos, end; + struct stat st; +- if (fstat(fileno(f->f_fp), &st) == 0) { ++ int res; ++ ++ Py_BEGIN_ALLOW_THREADS ++ res = fstat(fileno(f->f_fp), &st); ++ Py_END_ALLOW_THREADS ++ ++ if (res == 0) { + end = st.st_size; + /* The following is not a bug: we really need to call lseek() + *and* ftell(). The reason is that some stdio libraries +@@ -1021,7 +1032,11 @@ new_buffersize(PyFileObject *f, size_t currentsize) + works. We can't use the lseek() value either, because we + need to take the amount of buffered data into account. + (Yet another reason why stdio stinks. :-) */ ++ ++ Py_BEGIN_ALLOW_THREADS + pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR); ++ Py_END_ALLOW_THREADS ++ + if (pos >= 0) { + pos = ftell(f->f_fp); + } diff --git a/SOURCES/00295-fix-https-behind-proxy.patch b/SOURCES/00295-fix-https-behind-proxy.patch new file mode 100644 index 00000000..2d545924 --- /dev/null +++ b/SOURCES/00295-fix-https-behind-proxy.patch @@ -0,0 +1,250 @@ +diff --git a/Lib/httplib.py b/Lib/httplib.py +index 592ee57..b69145b 100644 +--- a/Lib/httplib.py ++++ b/Lib/httplib.py +@@ -735,25 +735,40 @@ class HTTPConnection: + self._tunnel_host = None + self._tunnel_port = None + self._tunnel_headers = {} +- +- self._set_hostport(host, port) + if strict is not None: + self.strict = strict + ++ (self.host, self.port) = self._get_hostport(host, port) ++ ++ # This is stored as an instance variable to allow unittests ++ # to replace with a suitable mock ++ self._create_connection = socket.create_connection ++ + def set_tunnel(self, host, port=None, headers=None): +- """ Sets up the host and the port for the HTTP CONNECT Tunnelling. ++ """ Set up host and port for HTTP CONNECT tunnelling. ++ ++ In a connection that uses HTTP Connect tunneling, the host passed to the ++ constructor is used as proxy server that relays all communication to the ++ endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT ++ request to the proxy server when the connection is established. ++ ++ This method must be called before the HTTP connection has been ++ established. + + The headers argument should be a mapping of extra HTTP headers + to send with the CONNECT request. + """ +- self._tunnel_host = host +- self._tunnel_port = port ++ # Verify if this is required. ++ if self.sock: ++ raise RuntimeError("Can't setup tunnel for established connection.") ++ ++ self._tunnel_host, self._tunnel_port = self._get_hostport(host, port) + if headers: + self._tunnel_headers = headers + else: + self._tunnel_headers.clear() + +- def _set_hostport(self, host, port): ++ def _get_hostport(self, host, port): + if port is None: + i = host.rfind(':') + j = host.rfind(']') # ipv6 addresses have [...] +@@ -770,15 +785,14 @@ class HTTPConnection: + port = self.default_port + if host and host[0] == '[' and host[-1] == ']': + host = host[1:-1] +- self.host = host +- self.port = port ++ return (host, port) + + def set_debuglevel(self, level): + self.debuglevel = level + + def _tunnel(self): +- self._set_hostport(self._tunnel_host, self._tunnel_port) +- self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port)) ++ self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self._tunnel_host, ++ self._tunnel_port)) + for header, value in self._tunnel_headers.iteritems(): + self.send("%s: %s\r\n" % (header, value)) + self.send("\r\n") +@@ -803,8 +817,8 @@ class HTTPConnection: + + def connect(self): + """Connect to the host and port specified in __init__.""" +- self.sock = socket.create_connection((self.host,self.port), +- self.timeout, self.source_address) ++ self.sock = self._create_connection((self.host,self.port), ++ self.timeout, self.source_address) + + if self._tunnel_host: + self._tunnel() +@@ -942,17 +956,24 @@ class HTTPConnection: + netloc_enc = netloc.encode("idna") + self.putheader('Host', netloc_enc) + else: ++ if self._tunnel_host: ++ host = self._tunnel_host ++ port = self._tunnel_port ++ else: ++ host = self.host ++ port = self.port ++ + try: +- host_enc = self.host.encode("ascii") ++ host_enc = host.encode("ascii") + except UnicodeEncodeError: +- host_enc = self.host.encode("idna") ++ host_enc = host.encode("idna") + # Wrap the IPv6 Host Header with [] (RFC 2732) + if host_enc.find(':') >= 0: + host_enc = "[" + host_enc + "]" +- if self.port == self.default_port: ++ if port == self.default_port: + self.putheader('Host', host_enc) + else: +- self.putheader('Host', "%s:%s" % (host_enc, self.port)) ++ self.putheader('Host', "%s:%s" % (host_enc, port)) + + # note: we are assuming that clients will not attempt to set these + # headers since *this* library must deal with the +@@ -1141,7 +1162,7 @@ class HTTP: + "Accept arguments to set the host/port, since the superclass doesn't." + + if host is not None: +- self._conn._set_hostport(host, port) ++ (self._conn.host, self._conn.port) = self._conn._get_hostport(host, port) + self._conn.connect() + + def getfile(self): +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index 29af589..9db30cc 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -21,10 +21,12 @@ CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotn + HOST = test_support.HOST + + class FakeSocket: +- def __init__(self, text, fileclass=StringIO.StringIO): ++ def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None): + self.text = text + self.fileclass = fileclass + self.data = '' ++ self.host = host ++ self.port = port + + def sendall(self, data): + self.data += ''.join(data) +@@ -34,6 +36,9 @@ class FakeSocket: + raise httplib.UnimplementedFileMode() + return self.fileclass(self.text) + ++ def close(self): ++ pass ++ + class EPipeSocket(FakeSocket): + + def __init__(self, text, pipe_trigger): +@@ -487,7 +492,11 @@ class OfflineTest(TestCase): + self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found") + + +-class SourceAddressTest(TestCase): ++class TestServerMixin: ++ """A limited socket server mixin. ++ ++ This is used by test cases for testing http connection end points. ++ """ + def setUp(self): + self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.port = test_support.bind_port(self.serv) +@@ -502,6 +511,7 @@ class SourceAddressTest(TestCase): + self.serv.close() + self.serv = None + ++class SourceAddressTest(TestServerMixin, TestCase): + def testHTTPConnectionSourceAddress(self): + self.conn = httplib.HTTPConnection(HOST, self.port, + source_address=('', self.source_port)) +@@ -518,6 +528,24 @@ class SourceAddressTest(TestCase): + # for an ssl_wrapped connect() to actually return from. + + ++class HTTPTest(TestServerMixin, TestCase): ++ def testHTTPConnection(self): ++ self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None) ++ self.conn.connect() ++ self.assertEqual(self.conn._conn.host, HOST) ++ self.assertEqual(self.conn._conn.port, self.port) ++ ++ def testHTTPWithConnectHostPort(self): ++ testhost = 'unreachable.test.domain' ++ testport = '80' ++ self.conn = httplib.HTTP(host=testhost, port=testport) ++ self.conn.connect(host=HOST, port=self.port) ++ self.assertNotEqual(self.conn._conn.host, testhost) ++ self.assertNotEqual(self.conn._conn.port, testport) ++ self.assertEqual(self.conn._conn.host, HOST) ++ self.assertEqual(self.conn._conn.port, self.port) ++ ++ + class TimeoutTest(TestCase): + PORT = None + +@@ -716,13 +744,54 @@ class HTTPSTest(TestCase): + c = httplib.HTTPSConnection(hp, context=context) + self.assertEqual(h, c.host) + self.assertEqual(p, c.port) +- ++ ++class TunnelTests(TestCase): ++ def test_connect(self): ++ response_text = ( ++ 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT ++ 'HTTP/1.1 200 OK\r\n' # Reply to HEAD ++ 'Content-Length: 42\r\n\r\n' ++ ) ++ ++ def create_connection(address, timeout=None, source_address=None): ++ return FakeSocket(response_text, host=address[0], port=address[1]) ++ ++ conn = httplib.HTTPConnection('proxy.com') ++ conn._create_connection = create_connection ++ ++ # Once connected, we should not be able to tunnel anymore ++ conn.connect() ++ self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com') ++ ++ # But if close the connection, we are good. ++ conn.close() ++ conn.set_tunnel('destination.com') ++ conn.request('HEAD', '/', '') ++ ++ self.assertEqual(conn.sock.host, 'proxy.com') ++ self.assertEqual(conn.sock.port, 80) ++ self.assertIn('CONNECT destination.com', conn.sock.data) ++ # issue22095 ++ self.assertNotIn('Host: destination.com:None', conn.sock.data) ++ # issue22095 ++ ++ self.assertNotIn('Host: proxy.com', conn.sock.data) ++ ++ conn.close() ++ ++ conn.request('PUT', '/', '') ++ self.assertEqual(conn.sock.host, 'proxy.com') ++ self.assertEqual(conn.sock.port, 80) ++ self.assertTrue('CONNECT destination.com' in conn.sock.data) ++ self.assertTrue('Host: destination.com' in conn.sock.data) ++ + + + @test_support.reap_threads + def test_main(verbose=None): + test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, +- HTTPSTest, SourceAddressTest) ++ HTTPTest, HTTPSTest, SourceAddressTest, ++ TunnelTests) + + if __name__ == '__main__': + test_main() diff --git a/SOURCES/00296-Readd-the-private-_set_hostport-api-to-httplib.patch b/SOURCES/00296-Readd-the-private-_set_hostport-api-to-httplib.patch new file mode 100644 index 00000000..56c3952e --- /dev/null +++ b/SOURCES/00296-Readd-the-private-_set_hostport-api-to-httplib.patch @@ -0,0 +1,26 @@ +From 8a91bb4ea0a7f50d024fe55014c2e86e36e67751 Mon Sep 17 00:00:00 2001 +From: Tomas Orsava +Date: Mon, 19 Feb 2018 14:42:13 +0100 +Subject: [PATCH] Readd the private `_set_hostport` api to httplib + +--- + Lib/httplib.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Lib/httplib.py b/Lib/httplib.py +index b69145b..da2f346 100644 +--- a/Lib/httplib.py ++++ b/Lib/httplib.py +@@ -787,6 +787,9 @@ class HTTPConnection: + host = host[1:-1] + return (host, port) + ++ def _set_hostport(self, host, port): ++ (self.host, self.port) = self._get_hostport(host, port) ++ + def set_debuglevel(self, level): + self.debuglevel = level + +-- +2.13.6 + diff --git a/SOURCES/00298-do-not-send-IP-in-SNI-TLS-extension.patch b/SOURCES/00298-do-not-send-IP-in-SNI-TLS-extension.patch new file mode 100644 index 00000000..99ed83cc --- /dev/null +++ b/SOURCES/00298-do-not-send-IP-in-SNI-TLS-extension.patch @@ -0,0 +1,60 @@ +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index d0a3830..51b192c 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -50,6 +50,11 @@ + #include + #endif + ++#ifndef MS_WINDOWS ++/* inet_pton */ ++#include ++#endif ++ + /* Include OpenSSL header files */ + #include "openssl/rsa.h" + #include "openssl/crypto.h" +@@ -493,8 +498,41 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, + SSL_set_mode(self->ssl, mode); + + #if HAVE_SNI +- if (server_hostname != NULL) +- SSL_set_tlsext_host_name(self->ssl, server_hostname); ++ if (server_hostname != NULL) { ++/* Don't send SNI for IP addresses. We cannot simply use inet_aton() and ++ * inet_pton() here. inet_aton() may be linked weakly and inet_pton() isn't ++ * available on all platforms. Use OpenSSL's IP address parser. It's ++ * available since 1.0.2 and LibreSSL since at least 2.3.0. */ ++ int send_sni = 1; ++#if OPENSSL_VERSION_NUMBER >= 0x10200000L ++ ASN1_OCTET_STRING *ip = a2i_IPADDRESS(server_hostname); ++ if (ip == NULL) { ++ send_sni = 1; ++ ERR_clear_error(); ++ } else { ++ send_sni = 0; ++ ASN1_OCTET_STRING_free(ip); ++ } ++#elif defined(HAVE_INET_PTON) ++#ifdef ENABLE_IPV6 ++ char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; ++#else ++ char packed[sizeof(struct in_addr)]; ++#endif /* ENABLE_IPV6 */ ++ if (inet_pton(AF_INET, server_hostname, packed)) { ++ send_sni = 0; ++#ifdef ENABLE_IPV6 ++ } else if(inet_pton(AF_INET6, server_hostname, packed)) { ++ send_sni = 0; ++#endif /* ENABLE_IPV6 */ ++ } else { ++ send_sni = 1; ++ } ++#endif /* HAVE_INET_PTON */ ++ if (send_sni) { ++ SSL_set_tlsext_host_name(self->ssl, server_hostname); ++ } ++ } + #endif + + /* If the socket is in non-blocking mode or timeout mode, set the BIO diff --git a/SOURCES/00299-fix-ssl-module-pymax.patch b/SOURCES/00299-fix-ssl-module-pymax.patch new file mode 100644 index 00000000..4f8c8dac --- /dev/null +++ b/SOURCES/00299-fix-ssl-module-pymax.patch @@ -0,0 +1,24 @@ +From 439956a149f8a3eb44646498c63b2ef3337d5f3d Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Sun, 25 Feb 2018 13:08:05 +0100 +Subject: [PATCH] Fix ssl module, Python 2.7 doesn't have Py_MAX (#5878) + +Signed-off-by: Christian Heimes +--- + Modules/_ssl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index af66a581e15a..f9ed94dee1e1 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -610,7 +610,8 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, + } + #elif defined(HAVE_INET_PTON) + #ifdef ENABLE_IPV6 +- char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; ++ #define PySSL_MAX(x, y) (((x) > (y)) ? (x) : (y)) ++ char packed[PySSL_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; + #else + char packed[sizeof(struct in_addr)]; + #endif /* ENABLE_IPV6 */ diff --git a/SOURCES/00303-CVE-2018-1060-1.patch b/SOURCES/00303-CVE-2018-1060-1.patch new file mode 100644 index 00000000..4d455a5e --- /dev/null +++ b/SOURCES/00303-CVE-2018-1060-1.patch @@ -0,0 +1,86 @@ +diff --git a/Lib/difflib.py b/Lib/difflib.py +index 1c6fbdbedcb7..788a92df3f89 100644 +--- a/Lib/difflib.py ++++ b/Lib/difflib.py +@@ -1103,7 +1103,7 @@ def _qformat(self, aline, bline, atags, btags): + + import re + +-def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match): ++def IS_LINE_JUNK(line, pat=re.compile(r"\s*(?:#\s*)?$").match): + r""" + Return 1 for ignorable line: iff `line` is blank or contains a single '#'. + +diff --git a/Lib/poplib.py b/Lib/poplib.py +index b91e5f72d2ca..a238510b38fc 100644 +--- a/Lib/poplib.py ++++ b/Lib/poplib.py +@@ -274,7 +274,7 @@ def rpop(self, user): + return self._shortcmd('RPOP %s' % user) + + +- timestamp = re.compile(r'\+OK.*(<[^>]+>)') ++ timestamp = re.compile(br'\+OK.[^<]*(<.*>)') + + def apop(self, user, secret): + """Authorisation +diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py +index 35f2c36ca70a..d8277b79b880 100644 +--- a/Lib/test/test_difflib.py ++++ b/Lib/test/test_difflib.py +@@ -269,13 +269,33 @@ def test_range_format_context(self): + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + ++class TestJunkAPIs(unittest.TestCase): ++ def test_is_line_junk_true(self): ++ for line in ['#', ' ', ' #', '# ', ' # ', '']: ++ self.assertTrue(difflib.IS_LINE_JUNK(line), repr(line)) ++ ++ def test_is_line_junk_false(self): ++ for line in ['##', ' ##', '## ', 'abc ', 'abc #', 'Mr. Moose is up!']: ++ self.assertFalse(difflib.IS_LINE_JUNK(line), repr(line)) ++ ++ def test_is_line_junk_REDOS(self): ++ evil_input = ('\t' * 1000000) + '##' ++ self.assertFalse(difflib.IS_LINE_JUNK(evil_input)) ++ ++ def test_is_character_junk_true(self): ++ for char in [' ', '\t']: ++ self.assertTrue(difflib.IS_CHARACTER_JUNK(char), repr(char)) ++ ++ def test_is_character_junk_false(self): ++ for char in ['a', '#', '\n', '\f', '\r', '\v']: ++ self.assertFalse(difflib.IS_CHARACTER_JUNK(char), repr(char)) + + def test_main(): + difflib.HtmlDiff._default_prefix = 0 + Doctests = doctest.DocTestSuite(difflib) + run_unittest( + TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs, +- TestOutputFormat, Doctests) ++ TestOutputFormat, TestJunkAPIs) + + if __name__ == '__main__': + test_main() +diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py +index 23d688724b95..d2143759ba66 100644 +--- a/Lib/test/test_poplib.py ++++ b/Lib/test/test_poplib.py +@@ -211,6 +211,16 @@ def test_noop(self): + def test_rpop(self): + self.assertOK(self.client.rpop('foo')) + ++ def test_apop_REDOS(self): ++ # Replace welcome with very long evil welcome. ++ # NB The upper bound on welcome length is currently 2048. ++ # At this length, evil input makes each apop call take ++ # on the order of milliseconds instead of microseconds. ++ evil_welcome = b'+OK' + (b'<' * 1000000) ++ with test_support.swap_attr(self.client, 'welcome', evil_welcome): ++ # The evil welcome is invalid, so apop should throw. ++ self.assertRaises(poplib.error_proto, self.client.apop, 'a', 'kb') ++ + def test_top(self): + expected = ('+OK 116 bytes', + ['From: postmaster@python.org', 'Content-Type: text/plain', diff --git a/SOURCES/00305-CVE-2016-2183.patch b/SOURCES/00305-CVE-2016-2183.patch new file mode 100644 index 00000000..a846cb5b --- /dev/null +++ b/SOURCES/00305-CVE-2016-2183.patch @@ -0,0 +1,53 @@ +diff --git a/Lib/ssl.py b/Lib/ssl.py +index 038daa4..5311321 100644 +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -143,38 +143,36 @@ if _ssl.HAS_TLS_UNIQUE: + else: + CHANNEL_BINDING_TYPES = [] + ++ + # Disable weak or insecure ciphers by default + # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') + # Enable a better set of ciphers by default + # This list has been explicitly chosen to: + # * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) + # * Prefer ECDHE over DHE for better performance +-# * Prefer any AES-GCM over any AES-CBC for better performance and security ++# * Prefer AEAD over CBC for better performance and security + # * Then Use HIGH cipher suites as a fallback +-# * Then Use 3DES as fallback which is secure but slow + # * Finally use RC4 as a fallback which is problematic but needed for + # compatibility some times. +-# * Disable NULL authentication, NULL encryption, and MD5 MACs for security +-# reasons ++# * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs ++# for security reasons + _DEFAULT_CIPHERS = ( + 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' +- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' +- 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' ++ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:ECDH+RC4:DH+RC4:RSA+RC4:!aNULL:!eNULL:' ++ '!MD5:!3DES' + ) + + # Restricted and more secure ciphers for the server side + # This list has been explicitly chosen to: + # * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) + # * Prefer ECDHE over DHE for better performance +-# * Prefer any AES-GCM over any AES-CBC for better performance and security ++# * Prefer AEAD over CBC for better performance and security + # * Then Use HIGH cipher suites as a fallback +-# * Then Use 3DES as fallback which is secure but slow +-# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for +-# security reasons ++# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and ++# 3DES for security reasons + _RESTRICTED_SERVER_CIPHERS = ( + 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' +- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' +- '!eNULL:!MD5:!DSS:!RC4' ++ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES' + ) + + diff --git a/SOURCES/00306-fix-oserror-17-upon-semaphores-creation.patch b/SOURCES/00306-fix-oserror-17-upon-semaphores-creation.patch new file mode 100644 index 00000000..b6070a46 --- /dev/null +++ b/SOURCES/00306-fix-oserror-17-upon-semaphores-creation.patch @@ -0,0 +1,44 @@ + +# HG changeset patch +# User Charles-François Natali +# Date 1455316761 0 +# Node ID d3662c088db8fb2c89f754031f18b1543419fed9 +# Parent 5715a6d9ff12053e81f7ad75268ac059b079b351 +Issue #24303: Fix random EEXIST upon multiprocessing semaphores creation with +Linux PID namespaces enabled. + +diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c +--- a/Modules/_multiprocessing/semaphore.c ++++ b/Modules/_multiprocessing/semaphore.c +@@ -429,7 +429,7 @@ semlock_new(PyTypeObject *type, PyObject + int kind, maxvalue, value; + PyObject *result; + static char *kwlist[] = {"kind", "value", "maxvalue", NULL}; +- static int counter = 0; ++ int try = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist, + &kind, &value, &maxvalue)) +@@ -440,10 +440,18 @@ semlock_new(PyTypeObject *type, PyObject + return NULL; + } + +- PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++); ++ /* Create a semaphore with a unique name. The bytes returned by ++ * _PyOS_URandom() are treated as unsigned long to ensure that the filename ++ * is valid (no special characters). */ ++ do { ++ unsigned long suffix; ++ _PyOS_URandom((char *)&suffix, sizeof(suffix)); ++ PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%lu", (long)getpid(), ++ suffix); ++ SEM_CLEAR_ERROR(); ++ handle = SEM_CREATE(buffer, value, maxvalue); ++ } while ((handle == SEM_FAILED) && (errno == EEXIST) && (++try < 100)); + +- SEM_CLEAR_ERROR(); +- handle = SEM_CREATE(buffer, value, maxvalue); + /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ + if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) + goto failure; + diff --git a/SOURCES/05000-autotool-intermediates.patch b/SOURCES/05000-autotool-intermediates.patch new file mode 100644 index 00000000..cfedc25a --- /dev/null +++ b/SOURCES/05000-autotool-intermediates.patch @@ -0,0 +1,216 @@ +diff -up ./configure.autotool-intermediates ./configure +--- ./configure.autotool-intermediates 2013-04-09 11:24:01.024185796 +0200 ++++ ./configure 2013-04-09 11:24:01.780183954 +0200 +@@ -639,6 +639,8 @@ TRUE + MACHDEP_OBJS + DYNLOADFILE + DLINCLDIR ++DTRACEHDRS ++DTRACEOBJS + THREADOBJ + LDLAST + USE_THREAD_MODULE +@@ -659,6 +661,8 @@ OTHER_LIBTOOL_OPT + UNIVERSAL_ARCH_FLAGS + BASECFLAGS + OPT ++DEBUG_SUFFIX ++DEBUG_EXT + LN + MKDIR_P + INSTALL_DATA +@@ -795,8 +799,11 @@ with_pth + enable_ipv6 + with_doc_strings + with_tsc ++with_count_allocs ++with_call_profile + with_pymalloc + with_valgrind ++with_dtrace + with_wctype_functions + with_fpectl + with_libm +@@ -1472,8 +1479,11 @@ Optional Packages: + --with-pth use GNU pth threading libraries + --with(out)-doc-strings disable/enable documentation strings + --with(out)-tsc enable/disable timestamp counter profile ++ --with(out)count-allocs enable/disable per-type instance accounting ++ --with(out)-call-profile enable/disable statistics on function call invocation + --with(out)-pymalloc disable/enable specialized mallocs + --with-valgrind Enable Valgrind support ++ --with(out)-dtrace disable/enable dtrace support + --with-wctype-functions use wctype.h functions + --with-fpectl enable SIGFPE catching + --with-libm=STRING math library +@@ -5171,7 +5181,7 @@ esac + $as_echo_n "checking LIBRARY... " >&6; } + if test -z "$LIBRARY" + then +- LIBRARY='libpython$(VERSION).a' ++ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a' + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBRARY" >&5 + $as_echo "$LIBRARY" >&6; } +@@ -5343,8 +5353,8 @@ $as_echo "#define Py_ENABLE_SHARED 1" >> + INSTSONAME="$LDLIBRARY".$SOVERSION + ;; + Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*) +- LDLIBRARY='libpython$(VERSION).so' +- BLDLIBRARY='-L. -lpython$(VERSION)' ++ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so' ++ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)' + RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} + case $ac_sys_system in + FreeBSD*) +@@ -5367,7 +5377,7 @@ $as_echo "#define Py_ENABLE_SHARED 1" >> + ;; + OSF*) + LDLIBRARY='libpython$(VERSION).so' +- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)' ++ BLDLIBRARY='-L. -lpython$(VERSION)' + RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} + ;; + atheos*) +@@ -5894,6 +5904,14 @@ $as_echo "no" >&6; } + fi + + ++if test "$Py_DEBUG" = 'true' ++then ++ DEBUG_EXT=_d ++ DEBUG_SUFFIX=-debug ++fi ++ ++ ++ + # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be + # merged with this chunk of code? + +@@ -9958,6 +9976,50 @@ $as_echo "no" >&6; } + fi + + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-count-allocs" >&5 ++$as_echo_n "checking for --with-count-allocs... " >&6; } ++ ++# Check whether --with-count-allocs was given. ++if test "${with_count_allocs+set}" = set; then : ++ withval=$with_count_allocs; ++if test "$withval" != no ++then ++ ++$as_echo "#define COUNT_ALLOCS 1" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-call-profile" >&5 ++$as_echo_n "checking for --with-call-profile... " >&6; } ++ ++# Check whether --with-call-profile was given. ++if test "${with_call_profile+set}" = set; then : ++ withval=$with_call_profile; ++if test "$withval" != no ++then ++ ++$as_echo "#define CALL_PROFILE 1" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ + # Check for Python-specific malloc support + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc" >&5 + $as_echo_n "checking for --with-pymalloc... " >&6; } +@@ -10007,6 +10069,46 @@ fi + + fi + ++# Check for dtrace support ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5 ++$as_echo_n "checking for --with-dtrace... " >&6; } ++ ++# Check whether --with-dtrace was given. ++if test "${with_dtrace+set}" = set; then : ++ withval=$with_dtrace; ++fi ++ ++ ++if test ! -z "$with_dtrace" ++then ++ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null ++ then ++ ++$as_echo "#define WITH_DTRACE 1" >>confdefs.h ++ ++ with_dtrace="Sun" ++ DTRACEOBJS="Python/dtrace.o" ++ DTRADEHDRS="" ++ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d ++ then ++ ++$as_echo "#define WITH_DTRACE 1" >>confdefs.h ++ ++ with_dtrace="Apple" ++ DTRACEOBJS="" ++ DTRADEHDRS="pydtrace.h" ++ else ++ with_dtrace="no" ++ fi ++else ++ with_dtrace="no" ++fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 ++$as_echo "$with_dtrace" >&6; } ++ ++ ++ + # Check for --with-wctype-functions + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-wctype-functions" >&5 + $as_echo_n "checking for --with-wctype-functions... " >&6; } +diff -up ./pyconfig.h.in.autotool-intermediates ./pyconfig.h.in +--- ./pyconfig.h.in.autotool-intermediates 2013-04-09 11:24:01.020185806 +0200 ++++ ./pyconfig.h.in 2013-04-09 11:24:02.088183204 +0200 +@@ -18,6 +18,12 @@ + /* Define this if you have BeOS threads. */ + #undef BEOS_THREADS + ++/* Define to keep records on function call invocation */ ++#undef CALL_PROFILE ++ ++/* Define to keep records of the number of instances of each type */ ++#undef COUNT_ALLOCS ++ + /* Define if you have the Mach cthreads package */ + #undef C_THREADS + +@@ -1119,12 +1125,6 @@ + /* Define to profile with the Pentium timestamp counter */ + #undef WITH_TSC + +-/* Define to keep records of the number of instances of each type */ +-#undef COUNT_ALLOCS +- +-/* Define to keep records on function call invocation */ +-#undef CALL_PROFILE +- + /* Define if you want pymalloc to be disabled when running under valgrind */ + #undef WITH_VALGRIND + diff --git a/SOURCES/cert-verification.cfg b/SOURCES/cert-verification.cfg new file mode 100755 index 00000000..3583e46d --- /dev/null +++ b/SOURCES/cert-verification.cfg @@ -0,0 +1,8 @@ +# Possible values are: +# 'enable' to ensure HTTPS certificate verification is enabled by default +# 'disable' to ensure HTTPS certificate verification is disabled by default +# 'platform_default' to delegate the decision to the redistributor providing this particular Python version + +# For more info refer to https://www.python.org/dev/peps/pep-0493/ +[https] +verify=platform_default diff --git a/SOURCES/macros.python b/SOURCES/macros.python new file mode 100644 index 00000000..8b168b5d --- /dev/null +++ b/SOURCES/macros.python @@ -0,0 +1,73 @@ +%py_setup setup.py +%py_shbang_opts -s + +# Use the slashes after expand so that the command starts on the same line as +# the macro +%py_build() %{expand:\\\ + CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py_shbang_opts}" %{?*} + sleep 1 +} + +%py_build_egg() %{expand:\\\ + CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_egg %{?*} + sleep 1 +} + +%py_build_wheel() %{expand:\\\ + CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*} + sleep 1 +} + +%py_install() %{expand:\\\ + CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*} +} + +%py_install_egg() %{expand:\\\ + mkdir -p %{buildroot}%{python_sitelib} + easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python_version}.egg %{?*} +} + +%py_install_wheel() %{expand:\\\ + pip install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps +} + +%python_provide() %{lua: + function string.starts(String,Start) + return string.sub(String,1,string.len(Start))==Start + end + package = rpm.expand("%{?1}") + vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}") + if (string.starts(package, "python2-")) then + if (rpm.expand("%{?buildarch}") ~= "noarch") then + str = "Provides: python-" .. string.sub(package,9,string.len(package)) .. "%{?_isa} = " .. vr + print(rpm.expand(str)) + end + print("\\nProvides: python-") + print(string.sub(package,9,string.len(package))) + print(" = ") + print(vr) + --Obsoleting the previous default python package + print("\\nObsoletes: python-") + print(string.sub(package,9,string.len(package))) + print(" < ") + print(vr) + elseif (string.starts(package, "python" .. rpm.expand("%{python3_pkgversion}") .. "-")) then + --No unversioned provides as python3 is not default + elseif (rpm.expand("%{?python3_other_pkgversion}") ~= "" and string.starts(package, "python" .. rpm.expand("%{python3_other_pkgversion}") .. "-")) then + --No unversioned provides as python3_other is not default + elseif (string.starts(package, "pypy-")) then + --No unversioned provides as pypy is not default + elseif (string.starts(package, "pypy3-")) then + --No unversioned provides as pypy is not default + elseif (string.starts(package, "python-")) then + --Providing the current default python + print("Provides: python2-") + print(string.sub(package,8,string.len(package))) + print(" = ") + print(vr) + else + print("%python_provide: ERROR: ") + print(package) + print(" not recognized.") + end +} diff --git a/SOURCES/macros.python2 b/SOURCES/macros.python2 new file mode 100644 index 00000000..169d48fe --- /dev/null +++ b/SOURCES/macros.python2 @@ -0,0 +1,37 @@ +%__python2 /usr/bin/python2 +%python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") +%python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))") +%python2_version %(%{__python2} -c "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))") +%python2_version_nodots %(%{__python2} -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))") + +%py2_shbang_opts -s + +# Use the slashes after expand so that the command starts on the same line as +# the macro +%py2_build() %{expand:\\\ + CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py2_shbang_opts}" %{?*} + sleep 1 +} + +%py2_build_egg() %{expand:\\\ + CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_egg %{?*} + sleep 1 +} + +%py2_build_wheel() %{expand:\\\ + CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_wheel %{?*} + sleep 1 +} + +%py2_install() %{expand:\\\ + CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*} +} + +%py2_install_egg() %{expand:\\\ + mkdir -p %{buildroot}%{python2_sitelib} + easy_install-%{python2_version} -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python2_version}.egg %{?*} +} + +%py2_install_wheel() %{expand:\\\ + pip%{python2_version} install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps +} diff --git a/SOURCES/pynche b/SOURCES/pynche new file mode 100644 index 00000000..368d7403 --- /dev/null +++ b/SOURCES/pynche @@ -0,0 +1,2 @@ +#!/bin/bash +exec `python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific = True))"`/pynche/pynche diff --git a/SOURCES/python-2.5-cflags.patch b/SOURCES/python-2.5-cflags.patch new file mode 100644 index 00000000..32243bf9 --- /dev/null +++ b/SOURCES/python-2.5-cflags.patch @@ -0,0 +1,11 @@ +--- Python-2.5c1/Makefile.pre.in.cflags 2006-08-18 11:05:40.000000000 -0400 ++++ Python-2.5c1/Makefile.pre.in 2006-08-18 11:09:26.000000000 -0400 +@@ -334,7 +334,7 @@ + + # Build the interpreter + $(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) +- $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ ++ $(LINKCC) $(CFLAGS) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ + Modules/python.o \ + $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) + diff --git a/SOURCES/python-2.5.1-plural-fix.patch b/SOURCES/python-2.5.1-plural-fix.patch new file mode 100644 index 00000000..040adaf1 --- /dev/null +++ b/SOURCES/python-2.5.1-plural-fix.patch @@ -0,0 +1,12 @@ +diff -up Python-2.5.1/Lib/gettext.py.plural Python-2.5.1/Lib/gettext.py +--- Python-2.5.1/Lib/gettext.py.plural 2007-09-10 11:38:57.000000000 -0400 ++++ Python-2.5.1/Lib/gettext.py 2007-09-10 11:39:00.000000000 -0400 +@@ -299,6 +299,8 @@ class GNUTranslations(NullTranslations): + item = item.strip() + if not item: + continue ++ if item.startswith("#"): ++ continue + if ':' in item: + k, v = item.split(':', 1) + k = k.strip().lower() diff --git a/SOURCES/python-2.5.1-sqlite-encoding.patch b/SOURCES/python-2.5.1-sqlite-encoding.patch new file mode 100644 index 00000000..ff2a3f87 --- /dev/null +++ b/SOURCES/python-2.5.1-sqlite-encoding.patch @@ -0,0 +1,24 @@ +diff -up Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding Python-2.5.1/Lib/sqlite3/dbapi2.py +--- Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding 2007-09-14 10:41:50.000000000 -0400 ++++ Python-2.5.1/Lib/sqlite3/dbapi2.py 2007-09-14 10:42:00.000000000 -0400 +@@ -1,7 +1,6 @@ +-# -*- coding: iso-8859-1 -*- + # pysqlite2/dbapi2.py: the DB-API 2.0 interface + # +-# Copyright (C) 2004-2005 Gerhard Hring ++# Copyright (C) 2004-2005 Gerhard Haering + # + # This file is part of pysqlite. + # +diff -up Python-2.5.1/Lib/sqlite3/__init__.py.encoding Python-2.5.1/Lib/sqlite3/__init__.py +--- Python-2.5.1/Lib/sqlite3/__init__.py.encoding 2007-09-14 10:41:47.000000000 -0400 ++++ Python-2.5.1/Lib/sqlite3/__init__.py 2007-09-14 10:42:06.000000000 -0400 +@@ -1,7 +1,6 @@ +-#-*- coding: ISO-8859-1 -*- + # pysqlite2/__init__.py: the pysqlite2 package. + # +-# Copyright (C) 2005 Gerhard Hring ++# Copyright (C) 2005 Gerhard Haering + # + # This file is part of pysqlite. + # diff --git a/SOURCES/python-2.6-rpath.patch b/SOURCES/python-2.6-rpath.patch new file mode 100644 index 00000000..43e3ec43 --- /dev/null +++ b/SOURCES/python-2.6-rpath.patch @@ -0,0 +1,12 @@ +diff -up Python-2.6/configure.ac.rpath Python-2.6/configure.ac +--- Python-2.6/configure.ac.rpath 2008-11-24 02:51:06.000000000 -0500 ++++ Python-2.6/configure.ac 2008-11-24 02:51:21.000000000 -0500 +@@ -729,7 +729,7 @@ if test $enable_shared = "yes"; then + ;; + OSF*) + LDLIBRARY='libpython$(VERSION).so' +- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)' ++ BLDLIBRARY='-L. -lpython$(VERSION)' + RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} + ;; + atheos*) diff --git a/SOURCES/python-2.6.4-distutils-rpath.patch b/SOURCES/python-2.6.4-distutils-rpath.patch new file mode 100644 index 00000000..f1565076 --- /dev/null +++ b/SOURCES/python-2.6.4-distutils-rpath.patch @@ -0,0 +1,20 @@ +diff -up Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath Python-2.6.4/Lib/distutils/unixccompiler.py +--- Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath 2009-09-09 04:34:06.000000000 -0400 ++++ Python-2.6.4/Lib/distutils/unixccompiler.py 2010-03-15 21:33:25.000000000 -0400 +@@ -142,6 +142,16 @@ class UnixCCompiler(CCompiler): + if sys.platform == "cygwin": + exe_extension = ".exe" + ++ def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): ++ """Remove standard library path from rpath""" ++ libraries, library_dirs, runtime_library_dirs = \ ++ CCompiler._fix_lib_args(self, libraries, library_dirs, ++ runtime_library_dirs) ++ libdir = sysconfig.get_config_var('LIBDIR') ++ if runtime_library_dirs and (libdir in runtime_library_dirs): ++ runtime_library_dirs.remove(libdir) ++ return libraries, library_dirs, runtime_library_dirs ++ + def preprocess(self, source, + output_file=None, macros=None, include_dirs=None, + extra_preargs=None, extra_postargs=None): diff --git a/SOURCES/python-2.7-lib64-sysconfig.patch b/SOURCES/python-2.7-lib64-sysconfig.patch new file mode 100644 index 00000000..0cef3619 --- /dev/null +++ b/SOURCES/python-2.7-lib64-sysconfig.patch @@ -0,0 +1,44 @@ +diff -up Python-2.7/Lib/sysconfig.py.lib64-sysconfig Python-2.7/Lib/sysconfig.py +--- Python-2.7/Lib/sysconfig.py.lib64-sysconfig 2010-07-08 14:18:41.386898476 -0400 ++++ Python-2.7/Lib/sysconfig.py 2010-07-08 14:22:02.837896461 -0400 +@@ -7,20 +7,20 @@ from os.path import pardir, realpath + + _INSTALL_SCHEMES = { + 'posix_prefix': { +- 'stdlib': '{base}/lib/python{py_version_short}', +- 'platstdlib': '{platbase}/lib/python{py_version_short}', ++ 'stdlib': '{base}/lib64/python{py_version_short}', ++ 'platstdlib': '{platbase}/lib64/python{py_version_short}', + 'purelib': '{base}/lib/python{py_version_short}/site-packages', +- 'platlib': '{platbase}/lib/python{py_version_short}/site-packages', ++ 'platlib': '{platbase}/lib64/python{py_version_short}/site-packages', + 'include': '{base}/include/python{py_version_short}', + 'platinclude': '{platbase}/include/python{py_version_short}', + 'scripts': '{base}/bin', + 'data': '{base}', + }, + 'posix_home': { +- 'stdlib': '{base}/lib/python', +- 'platstdlib': '{base}/lib/python', ++ 'stdlib': '{base}/lib64/python', ++ 'platstdlib': '{base}/lib64/python', + 'purelib': '{base}/lib/python', +- 'platlib': '{base}/lib/python', ++ 'platlib': '{base}/lib64/python', + 'include': '{base}/include/python', + 'platinclude': '{base}/include/python', + 'scripts': '{base}/bin', +@@ -65,10 +65,10 @@ _INSTALL_SCHEMES = { + 'data' : '{userbase}', + }, + 'posix_user': { +- 'stdlib': '{userbase}/lib/python{py_version_short}', +- 'platstdlib': '{userbase}/lib/python{py_version_short}', ++ 'stdlib': '{userbase}/lib64/python{py_version_short}', ++ 'platstdlib': '{userbase}/lib64/python{py_version_short}', + 'purelib': '{userbase}/lib/python{py_version_short}/site-packages', +- 'platlib': '{userbase}/lib/python{py_version_short}/site-packages', ++ 'platlib': '{userbase}/lib64/python{py_version_short}/site-packages', + 'include': '{userbase}/include/python{py_version_short}', + 'scripts': '{userbase}/bin', + 'data' : '{userbase}', diff --git a/SOURCES/python-2.7.1-config.patch b/SOURCES/python-2.7.1-config.patch new file mode 100644 index 00000000..6976d5cd --- /dev/null +++ b/SOURCES/python-2.7.1-config.patch @@ -0,0 +1,283 @@ +--- Python-2.7.4/Modules/Setup.dist.rhconfig 2013-04-06 16:02:34.000000000 +0200 ++++ Python-2.7.4/Modules/Setup.dist 2013-04-08 10:05:16.369985654 +0200 +@@ -153,7 +153,7 @@ GLHACK=-Dclear=__GLclear + # modules are to be built as shared libraries (see above for more + # detail; also note that *static* reverses this effect): + +-#*shared* ++*shared* + + # GNU readline. Unlike previous Python incarnations, GNU readline is + # now incorporated in an optional module, configured in the Setup file +@@ -163,77 +163,77 @@ GLHACK=-Dclear=__GLclear + # it, depending on your system -- see the GNU readline instructions. + # It's okay for this to be a shared library, too. + +-#readline readline.c -lreadline -ltermcap ++readline readline.c -lreadline -ltermcap + + + # Modules that should always be present (non UNIX dependent): + +-#array arraymodule.c # array objects +-#cmath cmathmodule.c _math.c # -lm # complex math library functions +-#math mathmodule.c _math.c # -lm # math library functions, e.g. sin() +-#_struct _struct.c # binary structure packing/unpacking +-#time timemodule.c # -lm # time operations and variables +-#operator operator.c # operator.add() and similar goodies +-#_testcapi _testcapimodule.c # Python C API test module +-#_random _randommodule.c # Random number generator +-#_collections _collectionsmodule.c # Container types ++array arraymodule.c # array objects ++cmath cmathmodule.c _math.c # -lm # complex math library functions ++math mathmodule.c _math.c # -lm # math library functions, e.g. sin() ++_struct _struct.c # binary structure packing/unpacking ++time timemodule.c # -lm # time operations and variables ++operator operator.c # operator.add() and similar goodies ++_testcapi _testcapimodule.c # Python C API test module ++_random _randommodule.c # Random number generator ++_collections _collectionsmodule.c # Container types + #_heapq _heapqmodule.c # Heapq type +-#itertools itertoolsmodule.c # Functions creating iterators for efficient looping +-#strop stropmodule.c # String manipulations +-#_functools _functoolsmodule.c # Tools for working with functions and callable objects ++itertools itertoolsmodule.c # Functions creating iterators for efficient looping ++strop stropmodule.c # String manipulations ++_functools _functoolsmodule.c # Tools for working with functions and callable objects + #_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator + #_pickle _pickle.c # pickle accelerator + #datetime datetimemodule.c # date/time type +-#_bisect _bisectmodule.c # Bisection algorithms ++_bisect _bisectmodule.c # Bisection algorithms + +-#unicodedata unicodedata.c # static Unicode character database ++unicodedata unicodedata.c # static Unicode character database + + # access to ISO C locale support +-#_locale _localemodule.c # -lintl ++_locale _localemodule.c # -lintl + + # Standard I/O baseline + #_io -I$(srcdir)/Modules/_io _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c + + + # Modules with some UNIX dependencies -- on by default: + # (If you have a really backward UNIX, select and socket may not be + # supported...) + +-#fcntl fcntlmodule.c # fcntl(2) and ioctl(2) +-#spwd spwdmodule.c # spwd(3) +-#grp grpmodule.c # grp(3) +-#select selectmodule.c # select(2); not on ancient System V ++fcntl fcntlmodule.c # fcntl(2) and ioctl(2) ++spwd spwdmodule.c # spwd(3) ++grp grpmodule.c # grp(3) ++select selectmodule.c # select(2); not on ancient System V + + # Memory-mapped files (also works on Win32). +-#mmap mmapmodule.c ++mmap mmapmodule.c + + # CSV file helper +-#_csv _csv.c ++_csv _csv.c + + # Socket module helper for socket(2) +-#_socket socketmodule.c timemodule.c ++_socket socketmodule.c timemodule.c + + # Socket module helper for SSL support; you must comment out the other + # socket line above, and possibly edit the SSL variable: + #SSL=/usr/local/ssl +-#_ssl _ssl.c \ +-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ +-# -L$(SSL)/lib -lssl -lcrypto ++_ssl _ssl.c \ ++ -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ ++ -L$(SSL)/lib -lssl -lcrypto + + # The crypt module is now disabled by default because it breaks builds + # on many systems (where -lcrypt is needed), e.g. Linux (I believe). + # + # First, look at Setup.config; configure may have set this for you. + +-#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems ++crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems + + + # Some more UNIX dependent modules -- off by default, since these + # are not supported by all UNIX systems: + +-#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere +-#termios termios.c # Steen Lumholt's termios module +-#resource resource.c # Jeremy Hylton's rlimit interface ++nis nismodule.c -lnsl # Sun yellow pages -- not everywhere ++termios termios.c # Steen Lumholt's termios module ++resource resource.c # Jeremy Hylton's rlimit interface + + + # Multimedia modules -- off by default. +@@ -238,8 +238,8 @@ GLHACK=-Dclear=__GLclear + # #993173 says audioop works on 64-bit platforms, though. + # These represent audio samples or images as strings: + +-#audioop audioop.c # Operations on audio samples +-#imageop imageop.c # Operations on images ++audioop audioop.c # Operations on audio samples ++imageop imageop.c # Operations on images + + + # Note that the _md5 and _sha modules are normally only built if the +@@ -249,14 +249,14 @@ GLHACK=-Dclear=__GLclear + # Message-Digest Algorithm, described in RFC 1321. The necessary files + # md5.c and md5.h are included here. + +-#_md5 md5module.c md5.c ++_md5 md5module.c md5.c + + + # The _sha module implements the SHA checksum algorithms. + # (NIST's Secure Hash Algorithms.) +-#_sha shamodule.c +-#_sha256 sha256module.c +-#_sha512 sha512module.c ++_sha shamodule.c ++_sha256 sha256module.c ++_sha512 sha512module.c + + + # SGI IRIX specific modules -- off by default. +@@ -303,12 +303,12 @@ GLHACK=-Dclear=__GLclear + # A Linux specific module -- off by default; this may also work on + # some *BSDs. + +-#linuxaudiodev linuxaudiodev.c ++linuxaudiodev linuxaudiodev.c + + + # George Neville-Neil's timing module: + +-#timing timingmodule.c ++timing timingmodule.c + + + # The _tkinter module. +@@ -323,7 +323,7 @@ GLHACK=-Dclear=__GLclear + # every system. + + # *** Always uncomment this (leave the leading underscore in!): +-# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ ++_tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ + # *** Uncomment and edit to reflect where your Tcl/Tk libraries are: + # -L/usr/local/lib \ + # *** Uncomment and edit to reflect where your Tcl/Tk headers are: +@@ -333,7 +333,7 @@ GLHACK=-Dclear=__GLclear + # *** Or uncomment this for Solaris: + # -I/usr/openwin/include \ + # *** Uncomment and edit for Tix extension only: +-# -DWITH_TIX -ltix8.1.8.2 \ ++ -DWITH_TIX -ltix \ + # *** Uncomment and edit for BLT extension only: + # -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \ + # *** Uncomment and edit for PIL (TkImaging) extension only: +@@ -342,7 +342,7 @@ GLHACK=-Dclear=__GLclear + # *** Uncomment and edit for TOGL extension only: + # -DWITH_TOGL togl.c \ + # *** Uncomment and edit to reflect your Tcl/Tk versions: +-# -ltk8.2 -ltcl8.2 \ ++ -ltk -ltcl \ + # *** Uncomment and edit to reflect where your X11 libraries are: + # -L/usr/X11R6/lib \ + # *** Or uncomment this for Solaris: +@@ -352,7 +352,7 @@ GLHACK=-Dclear=__GLclear + # *** Uncomment for AIX: + # -lld \ + # *** Always uncomment this; X11 libraries to link with: +-# -lX11 ++ -lX11 + + # Lance Ellinghaus's syslog module + #syslog syslogmodule.c # syslog daemon interface +@@ -374,7 +374,7 @@ GLHACK=-Dclear=__GLclear + # it is a highly experimental and dangerous device for calling + # *arbitrary* C functions in *arbitrary* shared libraries: + +-#dl dlmodule.c ++dl dlmodule.c + + + # Modules that provide persistent dictionary-like semantics. You will +@@ -397,7 +397,7 @@ GLHACK=-Dclear=__GLclear + # + # First, look at Setup.config; configure may have set this for you. + +-#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm ++gdbm gdbmmodule.c -lgdbm + + + # Sleepycat Berkeley DB interface. +@@ -412,11 +412,9 @@ GLHACK=-Dclear=__GLclear + # + # Edit the variables DB and DBLIBVERto point to the db top directory + # and the subdirectory of PORT where you built it. +-#DB=/usr/local/BerkeleyDB.4.0 +-#DBLIBVER=4.0 +-#DBINC=$(DB)/include +-#DBLIB=$(DB)/lib +-#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) ++DBINC=/usr/include/libdb ++DBLIB=/usr/lib ++_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb + + # Historical Berkeley DB 1.85 + # +@@ -431,14 +430,14 @@ GLHACK=-Dclear=__GLclear + + + # Helper module for various ascii-encoders +-#binascii binascii.c ++binascii binascii.c + + # Fred Drake's interface to the Python parser +-#parser parsermodule.c ++parser parsermodule.c + + # cStringIO and cPickle +-#cStringIO cStringIO.c +-#cPickle cPickle.c ++cStringIO cStringIO.c ++cPickle cPickle.c + + + # Lee Busby's SIGFPE modules. +@@ -461,7 +460,7 @@ GLHACK=-Dclear=__GLclear + # Andrew Kuchling's zlib module. + # This require zlib 1.1.3 (or later). + # See http://www.gzip.org/zlib/ +-#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz ++zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz + + # Interface to the Expat XML parser + # +@@ -480,14 +479,14 @@ GLHACK=-Dclear=__GLclear + # Hye-Shik Chang's CJKCodecs + + # multibytecodec is required for all the other CJK codec modules +-#_multibytecodec cjkcodecs/multibytecodec.c ++_multibytecodec cjkcodecs/multibytecodec.c + +-#_codecs_cn cjkcodecs/_codecs_cn.c +-#_codecs_hk cjkcodecs/_codecs_hk.c +-#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c +-#_codecs_jp cjkcodecs/_codecs_jp.c +-#_codecs_kr cjkcodecs/_codecs_kr.c +-#_codecs_tw cjkcodecs/_codecs_tw.c ++_codecs_cn cjkcodecs/_codecs_cn.c ++_codecs_hk cjkcodecs/_codecs_hk.c ++_codecs_iso2022 cjkcodecs/_codecs_iso2022.c ++_codecs_jp cjkcodecs/_codecs_jp.c ++_codecs_kr cjkcodecs/_codecs_kr.c ++_codecs_tw cjkcodecs/_codecs_tw.c + + # Example -- included for reference only: + # xx xxmodule.c diff --git a/SOURCES/python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch b/SOURCES/python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch new file mode 100644 index 00000000..bb382818 --- /dev/null +++ b/SOURCES/python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch @@ -0,0 +1,27 @@ +diff -up Python-2.7.1/Lib/test/test_abc.py.cache_leak Python-2.7.1/Lib/test/test_abc.py +--- Python-2.7.1/Lib/test/test_abc.py.cache_leak 2010-12-28 18:06:35.551938356 -0500 ++++ Python-2.7.1/Lib/test/test_abc.py 2010-12-28 18:09:09.021059202 -0500 +@@ -3,6 +3,8 @@ + + """Unit tests for abc.py.""" + ++import sys ++ + import unittest, weakref + from test import test_support + +@@ -229,8 +231,12 @@ class TestABC(unittest.TestCase): + # Trigger cache. + C().f() + del C +- test_support.gc_collect() +- self.assertEqual(r(), None) ++ # This doesn't work in our debug build, presumably due to its use ++ # of COUNT_ALLOCS, which makes heap-allocated types immortal (once ++ # they've ever had an instance): ++ if not hasattr(sys, 'getcounts'): ++ test_support.gc_collect() ++ self.assertEqual(r(), None) + + def test_main(): + test_support.run_unittest(TestABC) diff --git a/SOURCES/python-2.7.2-add-extension-suffix-to-python-config.patch b/SOURCES/python-2.7.2-add-extension-suffix-to-python-config.patch new file mode 100644 index 00000000..d1ff0528 --- /dev/null +++ b/SOURCES/python-2.7.2-add-extension-suffix-to-python-config.patch @@ -0,0 +1,18 @@ +diff -up Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config Python-2.7.2/Misc/python-config.in +--- Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config 2011-08-23 18:15:41.832497124 -0400 ++++ Python-2.7.2/Misc/python-config.in 2011-08-23 18:17:25.854490011 -0400 +@@ -6,7 +6,7 @@ import getopt + from distutils import sysconfig + + valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', +- 'ldflags', 'help'] ++ 'ldflags', 'extension-suffix', 'help'] + + def exit_with_usage(code=1): + print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0], +@@ -54,3 +54,5 @@ for opt in opt_flags: + libs.extend(getvar('LINKFORSHARED').split()) + print ' '.join(libs) + ++ elif opt == '--extension-suffix': ++ print (sys.pydebug and "_d" or "") + sysconfig.get_config_var('SO') diff --git a/SOURCES/python-2.7.3-debug-build.patch b/SOURCES/python-2.7.3-debug-build.patch new file mode 100644 index 00000000..5b6cda7a --- /dev/null +++ b/SOURCES/python-2.7.3-debug-build.patch @@ -0,0 +1,292 @@ +diff -up Python-2.7.3/configure.ac.debug-build Python-2.7.3/configure.ac +--- Python-2.7.3/configure.ac.debug-build 2012-04-18 19:46:22.066498521 -0400 ++++ Python-2.7.3/configure.ac 2012-04-18 19:46:22.078498372 -0400 +@@ -635,7 +635,7 @@ AC_SUBST(LIBRARY) + AC_MSG_CHECKING(LIBRARY) + if test -z "$LIBRARY" + then +- LIBRARY='libpython$(VERSION).a' ++ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a' + fi + AC_MSG_RESULT($LIBRARY) + +@@ -780,8 +780,8 @@ if test $enable_shared = "yes"; then + INSTSONAME="$LDLIBRARY".$SOVERSION + ;; + Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*) +- LDLIBRARY='libpython$(VERSION).so' +- BLDLIBRARY='-L. -lpython$(VERSION)' ++ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so' ++ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)' + RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} + case $ac_sys_system in + FreeBSD*) +@@ -905,6 +905,14 @@ else AC_MSG_RESULT(no); Py_DEBUG='false' + fi], + [AC_MSG_RESULT(no)]) + ++if test "$Py_DEBUG" = 'true' ++then ++ DEBUG_EXT=_d ++ DEBUG_SUFFIX=-debug ++fi ++AC_SUBST(DEBUG_EXT) ++AC_SUBST(DEBUG_SUFFIX) ++ + # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be + # merged with this chunk of code? + +diff -up Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build Python-2.7.3/Lib/distutils/command/build_ext.py +--- Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build 2012-04-09 19:07:29.000000000 -0400 ++++ Python-2.7.3/Lib/distutils/command/build_ext.py 2012-04-18 19:46:22.079498360 -0400 +@@ -676,7 +676,10 @@ class build_ext (Command): + so_ext = get_config_var('SO') + if os.name == 'nt' and self.debug: + return os.path.join(*ext_path) + '_d' + so_ext +- return os.path.join(*ext_path) + so_ext ++ ++ # Similarly, extensions in debug mode are named 'module_d.so', to ++ # avoid adding the _d to the SO config variable: ++ return os.path.join(*ext_path) + (sys.pydebug and "_d" or "") + so_ext + + def get_export_symbols (self, ext): + """Return the list of symbols that a shared extension has to +@@ -761,6 +764,8 @@ class build_ext (Command): + template = "python%d.%d" + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) ++ if sys.pydebug: ++ pythonlib += '_d' + return ext.libraries + [pythonlib] + else: + return ext.libraries +diff -up Python-2.7.3/Lib/distutils/sysconfig.py.debug-build Python-2.7.3/Lib/distutils/sysconfig.py +--- Python-2.7.3/Lib/distutils/sysconfig.py.debug-build 2012-04-18 19:46:21.988499499 -0400 ++++ Python-2.7.3/Lib/distutils/sysconfig.py 2012-04-18 19:46:22.080498348 -0400 +@@ -85,7 +85,8 @@ def get_python_inc(plat_specific=0, pref + # Include is located in the srcdir + inc_dir = os.path.join(srcdir, "Include") + return inc_dir +- return os.path.join(prefix, "include", "python" + get_python_version()) ++ return os.path.join(prefix, "include", ++ "python" + get_python_version() + (sys.pydebug and '-debug' or '')) + elif os.name == "nt": + return os.path.join(prefix, "include") + elif os.name == "os2": +@@ -250,7 +251,7 @@ def get_makefile_filename(): + if python_build: + return os.path.join(project_base, "Makefile") + lib_dir = get_python_lib(plat_specific=1, standard_lib=1) +- return os.path.join(lib_dir, "config", "Makefile") ++ return os.path.join(lib_dir, "config" + (sys.pydebug and "-debug" or ""), "Makefile") + + + def parse_config_h(fp, g=None): +diff -up Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build Python-2.7.3/Lib/distutils/tests/test_install.py +--- Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build 2012-04-18 19:46:21.997499385 -0400 ++++ Python-2.7.3/Lib/distutils/tests/test_install.py 2012-04-18 19:46:22.080498348 -0400 +@@ -20,8 +20,9 @@ from distutils.tests import support + + + def _make_ext_name(modname): +- if os.name == 'nt' and sys.executable.endswith('_d.exe'): ++ if sys.pydebug: + modname += '_d' ++ + return modname + sysconfig.get_config_var('SO') + + +diff -up Python-2.7.3/Makefile.pre.in.debug-build Python-2.7.3/Makefile.pre.in +--- Python-2.7.3/Makefile.pre.in.debug-build 2012-04-18 19:46:22.073498437 -0400 ++++ Python-2.7.3/Makefile.pre.in 2012-04-18 19:48:46.336694896 -0400 +@@ -102,8 +102,8 @@ SCRIPTDIR= $(prefix)/lib64 + # Detailed destination directories + BINLIBDEST= $(LIBDIR)/python$(VERSION) + LIBDEST= $(SCRIPTDIR)/python$(VERSION) +-INCLUDEPY= $(INCLUDEDIR)/python$(VERSION) +-CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION) ++INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX) ++CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX) + LIBP= $(LIBDIR)/python$(VERSION) + + # Symbols used for using shared libraries +@@ -117,6 +117,12 @@ DESTSHARED= $(BINLIBDEST)/lib-dynload + EXE= @EXEEXT@ + BUILDEXE= @BUILDEXEEXT@ + ++# DEBUG_EXT is used by ELF files (names and SONAMEs); it will be "_d" for a debug build ++# DEBUG_SUFFIX is used by filesystem paths; it will be "-debug" for a debug build ++# Both will be empty in an optimized build ++DEBUG_EXT= @DEBUG_EXT@ ++DEBUG_SUFFIX= @DEBUG_SUFFIX@ ++ + # Short name and location for Mac OS X Python framework + UNIVERSALSDK=@UNIVERSALSDK@ + PYTHONFRAMEWORK= @PYTHONFRAMEWORK@ +@@ -180,8 +186,8 @@ LIBOBJDIR= Python/ + LIBOBJS= @LIBOBJS@ + UNICODE_OBJS= @UNICODE_OBJS@ + +-PYTHON= python$(EXE) +-BUILDPYTHON= python$(BUILDEXE) ++PYTHON= python$(DEBUG_SUFFIX)$(EXE) ++BUILDPYTHON= python$(DEBUG_SUFFIX)$(BUILDEXE) + + PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@ + _PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@ +@@ -413,7 +419,7 @@ sharedmods: $(BUILDPYTHON) + $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ + $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build + +-libpython$(VERSION).so: $(LIBRARY_OBJS) ++libpython$(VERSION)$(DEBUG_EXT).so: $(LIBRARY_OBJS) + if test $(INSTSONAME) != $(LDLIBRARY); then \ + $(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ + $(LN) -f $(INSTSONAME) $@; \ +@@ -796,18 +802,18 @@ bininstall: altbininstall + then rm -f $(DESTDIR)$(BINDIR)/$(PYTHON); \ + else true; \ + fi +- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(EXE) $(PYTHON)) +- -rm -f $(DESTDIR)$(BINDIR)/python2$(EXE) +- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(EXE) python2$(EXE)) +- -rm -f $(DESTDIR)$(BINDIR)/python2-config +- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-config python2-config) +- -rm -f $(DESTDIR)$(BINDIR)/python-config +- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2-config python-config) ++ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)$(EXE) $(PYTHON)) ++ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)$(EXE) ++ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)$(EXE) python2$(DEBUG_SUFFIX)$(EXE)) ++ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)-config ++ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)-config python2$(DEBUG_SUFFIX)-config) ++ -rm -f $(DESTDIR)$(BINDIR)/python$(DEBUG_SUFFIX)-config ++ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)-config python$(DEBUG_SUFFIX)-config) + -test -d $(DESTDIR)$(LIBPC) || $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(LIBPC) +- -rm -f $(DESTDIR)$(LIBPC)/python2.pc +- (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION).pc python2.pc) +- -rm -f $(DESTDIR)$(LIBPC)/python.pc +- (cd $(DESTDIR)$(LIBPC); $(LN) -s python2.pc python.pc) ++ -rm -f $(DESTDIR)$(LIBPC)/python2$(DEBUG_SUFFIX).pc ++ (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION)$(DEBUG_SUFFIX).pc python2$(DEBUG_SUFFIX).pc) ++ -rm -f $(DESTDIR)$(LIBPC)/python$(DEBUG_SUFFIX).pc ++ (cd $(DESTDIR)$(LIBPC); $(LN) -s python2$(DEBUG_SUFFIX).pc python$(DEBUG_SUFFIX).pc) + + # Install the interpreter with $(VERSION) affixed + # This goes into $(exec_prefix) +@@ -820,7 +826,7 @@ altbininstall: $(BUILDPYTHON) + else true; \ + fi; \ + done +- $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(EXE) ++ $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE) + if test -f $(LDLIBRARY); then \ + if test -n "$(DLLLIBRARY)" ; then \ + $(INSTALL_SHARED) $(DLLLIBRARY) $(DESTDIR)$(BINDIR); \ +@@ -970,10 +976,11 @@ $(srcdir)/Lib/$(PLATDIR): + fi; \ + cd $(srcdir)/Lib/$(PLATDIR); $(RUNSHARED) ./regen + +-python-config: $(srcdir)/Misc/python-config.in ++python$(DEBUG_SUFFIX)-config: $(srcdir)/Misc/python-config.in + # Substitution happens here, as the completely-expanded BINDIR + # is not available in configure +- sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(EXE)," < $(srcdir)/Misc/python-config.in >python-config ++ sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE)," < $(srcdir)/Misc/python-config.in >python$(DEBUG_SUFFIX)-config ++ + + # Install the include files + INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY) +@@ -994,13 +1001,13 @@ inclinstall: + $(INSTALL_DATA) pyconfig.h $(DESTDIR)$(CONFINCLUDEPY)/pyconfig.h + + # Install the library and miscellaneous stuff needed for extending/embedding +-# This goes into $(exec_prefix) +-LIBPL= $(LIBP)/config ++# This goes into $(exec_prefix)$(DEBUG_SUFFIX) ++LIBPL= $(LIBP)/config$(DEBUG_SUFFIX) + + # pkgconfig directory + LIBPC= $(LIBDIR)/pkgconfig + +-libainstall: all python-config ++libainstall: all python$(DEBUG_SUFFIX)-config + @for i in $(LIBDIR) $(LIBP) $(LIBPL) $(LIBPC); \ + do \ + if test ! -d $(DESTDIR)$$i; then \ +@@ -1016,11 +1023,10 @@ libainstall: all python-config + $(INSTALL_DATA) Modules/Setup $(DESTDIR)$(LIBPL)/Setup + $(INSTALL_DATA) Modules/Setup.local $(DESTDIR)$(LIBPL)/Setup.local + $(INSTALL_DATA) Modules/Setup.config $(DESTDIR)$(LIBPL)/Setup.config +- $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION).pc ++ $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION)$(DEBUG_SUFFIX).pc + $(INSTALL_SCRIPT) $(srcdir)/Modules/makesetup $(DESTDIR)$(LIBPL)/makesetup + $(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh +- $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(VERSION)-config +- rm python-config ++ $(INSTALL_SCRIPT) python$(DEBUG_SUFFIX)-config $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)-config + @if [ -s Modules/python.exp -a \ + "`echo $(MACHDEP) | sed 's/^\(...\).*/\1/'`" = "aix" ]; then \ + echo; echo "Installing support files for building shared extension modules on AIX:"; \ +diff -up Python-2.7.3/Misc/python-config.in.debug-build Python-2.7.3/Misc/python-config.in +--- Python-2.7.3/Misc/python-config.in.debug-build 2012-04-09 19:07:33.000000000 -0400 ++++ Python-2.7.3/Misc/python-config.in 2012-04-18 19:46:22.082498324 -0400 +@@ -45,7 +45,7 @@ for opt in opt_flags: + + elif opt in ('--libs', '--ldflags'): + libs = getvar('LIBS').split() + getvar('SYSLIBS').split() +- libs.append('-lpython'+pyver) ++ libs.append('-lpython' + pyver + (sys.pydebug and "_d" or "")) + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags': +diff -up Python-2.7.3/Modules/makesetup.debug-build Python-2.7.3/Modules/makesetup +--- Python-2.7.3/Modules/makesetup.debug-build 2012-04-09 19:07:34.000000000 -0400 ++++ Python-2.7.3/Modules/makesetup 2012-04-18 19:46:22.083498312 -0400 +@@ -233,7 +233,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' | + *$mod.o*) base=$mod;; + *) base=${mod}module;; + esac +- file="$srcdir/$base\$(SO)" ++ file="$srcdir/$base\$(DEBUG_EXT)\$(SO)" + case $doconfig in + no) SHAREDMODS="$SHAREDMODS $file";; + esac +diff -up Python-2.7.3/Python/dynload_shlib.c.debug-build Python-2.7.3/Python/dynload_shlib.c +--- Python-2.7.3/Python/dynload_shlib.c.debug-build 2012-04-09 19:07:35.000000000 -0400 ++++ Python-2.7.3/Python/dynload_shlib.c 2012-04-18 19:46:22.083498312 -0400 +@@ -46,11 +46,16 @@ const struct filedescr _PyImport_DynLoad + {"module.exe", "rb", C_EXTENSION}, + {"MODULE.EXE", "rb", C_EXTENSION}, + #else ++#ifdef Py_DEBUG ++ {"_d.so", "rb", C_EXTENSION}, ++ {"module_d.so", "rb", C_EXTENSION}, ++#else + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, +-#endif +-#endif +-#endif ++#endif /* Py_DEBUG */ ++#endif /* __VMS */ ++#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */ ++#endif /* __CYGWIN__ */ + {0, 0} + }; + +diff -up Python-2.7.3/Python/sysmodule.c.debug-build Python-2.7.3/Python/sysmodule.c +--- Python-2.7.3/Python/sysmodule.c.debug-build 2012-04-09 19:07:35.000000000 -0400 ++++ Python-2.7.3/Python/sysmodule.c 2012-04-18 19:46:22.083498312 -0400 +@@ -1506,6 +1506,12 @@ _PySys_Init(void) + PyString_FromString("legacy")); + #endif + ++#ifdef Py_DEBUG ++ PyDict_SetItemString(sysdict, "pydebug", Py_True); ++#else ++ PyDict_SetItemString(sysdict, "pydebug", Py_False); ++#endif ++ + #undef SET_SYS_FROM_STRING + if (PyErr_Occurred()) + return NULL; diff --git a/SOURCES/python-2.7.3-lib64.patch b/SOURCES/python-2.7.3-lib64.patch new file mode 100644 index 00000000..71f32c52 --- /dev/null +++ b/SOURCES/python-2.7.3-lib64.patch @@ -0,0 +1,196 @@ +diff -up Python-2.7.3/Lib/distutils/command/install.py.lib64 Python-2.7.3/Lib/distutils/command/install.py +--- Python-2.7.3/Lib/distutils/command/install.py.lib64 2012-04-09 19:07:29.000000000 -0400 ++++ Python-2.7.3/Lib/distutils/command/install.py 2013-02-19 13:58:20.446015129 -0500 +@@ -42,14 +42,14 @@ else: + INSTALL_SCHEMES = { + 'unix_prefix': { + 'purelib': '$base/lib/python$py_version_short/site-packages', +- 'platlib': '$platbase/lib/python$py_version_short/site-packages', ++ 'platlib': '$platbase/lib64/python$py_version_short/site-packages', + 'headers': '$base/include/python$py_version_short/$dist_name', + 'scripts': '$base/bin', + 'data' : '$base', + }, + 'unix_home': { + 'purelib': '$base/lib/python', +- 'platlib': '$base/lib/python', ++ 'platlib': '$base/lib64/python', + 'headers': '$base/include/python/$dist_name', + 'scripts': '$base/bin', + 'data' : '$base', +diff -up Python-2.7.3/Lib/distutils/sysconfig.py.lib64 Python-2.7.3/Lib/distutils/sysconfig.py +--- Python-2.7.3/Lib/distutils/sysconfig.py.lib64 2012-04-09 19:07:29.000000000 -0400 ++++ Python-2.7.3/Lib/distutils/sysconfig.py 2013-02-19 13:58:20.446015129 -0500 +@@ -114,8 +114,12 @@ def get_python_lib(plat_specific=0, stan + prefix = plat_specific and EXEC_PREFIX or PREFIX + + if os.name == "posix": ++ if plat_specific or standard_lib: ++ lib = "lib64" ++ else: ++ lib = "lib" + libpython = os.path.join(prefix, +- "lib", "python" + get_python_version()) ++ lib, "python" + get_python_version()) + if standard_lib: + return libpython + else: +diff -up Python-2.7.3/Lib/site.py.lib64 Python-2.7.3/Lib/site.py +--- Python-2.7.3/Lib/site.py.lib64 2012-04-09 19:07:31.000000000 -0400 ++++ Python-2.7.3/Lib/site.py 2013-02-19 13:58:20.447015128 -0500 +@@ -300,12 +300,16 @@ def getsitepackages(): + if sys.platform in ('os2emx', 'riscos'): + sitepackages.append(os.path.join(prefix, "Lib", "site-packages")) + elif os.sep == '/': ++ sitepackages.append(os.path.join(prefix, "lib64", ++ "python" + sys.version[:3], ++ "site-packages")) + sitepackages.append(os.path.join(prefix, "lib", + "python" + sys.version[:3], + "site-packages")) + sitepackages.append(os.path.join(prefix, "lib", "site-python")) + else: + sitepackages.append(prefix) ++ sitepackages.append(os.path.join(prefix, "lib64", "site-packages")) + sitepackages.append(os.path.join(prefix, "lib", "site-packages")) + if sys.platform == "darwin": + # for framework builds *only* we add the standard Apple +diff -up Python-2.7.3/Lib/test/test_site.py.lib64 Python-2.7.3/Lib/test/test_site.py +--- Python-2.7.3/Lib/test/test_site.py.lib64 2012-04-09 19:07:32.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_site.py 2013-02-19 13:58:20.447015128 -0500 +@@ -241,17 +241,20 @@ class HelperFunctionsTests(unittest.Test + self.assertEqual(dirs[2], wanted) + elif os.sep == '/': + # OS X non-framwework builds, Linux, FreeBSD, etc +- self.assertEqual(len(dirs), 2) +- wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3], ++ self.assertEqual(len(dirs), 3) ++ wanted = os.path.join('xoxo', 'lib64', 'python' + sys.version[:3], + 'site-packages') + self.assertEqual(dirs[0], wanted) +- wanted = os.path.join('xoxo', 'lib', 'site-python') ++ wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3], ++ 'site-packages') + self.assertEqual(dirs[1], wanted) ++ wanted = os.path.join('xoxo', 'lib', 'site-python') ++ self.assertEqual(dirs[2], wanted) + else: + # other platforms + self.assertEqual(len(dirs), 2) + self.assertEqual(dirs[0], 'xoxo') +- wanted = os.path.join('xoxo', 'lib', 'site-packages') ++ wanted = os.path.join('xoxo', 'lib64', 'site-packages') + self.assertEqual(dirs[1], wanted) + + class PthFile(object): +diff -up Python-2.7.3/Makefile.pre.in.lib64 Python-2.7.3/Makefile.pre.in +--- Python-2.7.3/Makefile.pre.in.lib64 2013-02-19 13:58:20.435015131 -0500 ++++ Python-2.7.3/Makefile.pre.in 2013-02-19 13:58:20.447015128 -0500 +@@ -97,7 +97,7 @@ LIBDIR= @libdir@ + MANDIR= @mandir@ + INCLUDEDIR= @includedir@ + CONFINCLUDEDIR= $(exec_prefix)/include +-SCRIPTDIR= $(prefix)/lib ++SCRIPTDIR= $(prefix)/lib64 + + # Detailed destination directories + BINLIBDEST= $(LIBDIR)/python$(VERSION) +diff -up Python-2.7.3/Modules/getpath.c.lib64 Python-2.7.3/Modules/getpath.c +--- Python-2.7.3/Modules/getpath.c.lib64 2012-04-09 19:07:34.000000000 -0400 ++++ Python-2.7.3/Modules/getpath.c 2013-02-19 13:58:20.448015128 -0500 +@@ -117,8 +117,8 @@ + #endif + + #ifndef PYTHONPATH +-#define PYTHONPATH PREFIX "/lib/python" VERSION ":" \ +- EXEC_PREFIX "/lib/python" VERSION "/lib-dynload" ++#define PYTHONPATH PREFIX "/lib64/python" VERSION ":" \ ++ EXEC_PREFIX "/lib64/python" VERSION "/lib-dynload" + #endif + + #ifndef LANDMARK +@@ -129,7 +129,7 @@ static char prefix[MAXPATHLEN+1]; + static char exec_prefix[MAXPATHLEN+1]; + static char progpath[MAXPATHLEN+1]; + static char *module_search_path = NULL; +-static char lib_python[] = "lib/python" VERSION; ++static char lib_python[] = "lib64/python" VERSION; + + static void + reduce(char *dir) +@@ -528,7 +528,7 @@ calculate_path(void) + } + else + strncpy(zip_path, PREFIX, MAXPATHLEN); +- joinpath(zip_path, "lib/python00.zip"); ++ joinpath(zip_path, "lib64/python00.zip"); + bufsz = strlen(zip_path); /* Replace "00" with version */ + zip_path[bufsz - 6] = VERSION[0]; + zip_path[bufsz - 5] = VERSION[2]; +@@ -538,7 +538,7 @@ calculate_path(void) + fprintf(stderr, + "Could not find platform dependent libraries \n"); + strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); +- joinpath(exec_prefix, "lib/lib-dynload"); ++ joinpath(exec_prefix, "lib64/lib-dynload"); + } + /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ + +diff -up Python-2.7.3/Modules/Setup.dist.lib64 Python-2.7.3/Modules/Setup.dist +--- Python-2.7.3/Modules/Setup.dist.lib64 2013-02-19 13:58:20.442015131 -0500 ++++ Python-2.7.3/Modules/Setup.dist 2013-02-19 14:02:25.255998391 -0500 +@@ -413,7 +413,7 @@ gdbm gdbmmodule.c -lgdbm + # Edit the variables DB and DBLIBVERto point to the db top directory + # and the subdirectory of PORT where you built it. + DBINC=/usr/include/libdb +-DBLIB=/usr/lib ++DBLIB=/usr/lib64 + _bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb + + # Historical Berkeley DB 1.85 +@@ -459,7 +459,7 @@ cPickle cPickle.c + # Andrew Kuchling's zlib module. + # This require zlib 1.1.3 (or later). + # See http://www.gzip.org/zlib/ +-zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz ++zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib64 -lz + + # Interface to the Expat XML parser + # +diff -up Python-2.7.3/setup.py.lib64 Python-2.7.3/setup.py +--- Python-2.7.3/setup.py.lib64 2012-04-09 19:07:36.000000000 -0400 ++++ Python-2.7.3/setup.py 2013-02-19 13:58:20.449015129 -0500 +@@ -369,7 +369,7 @@ class PyBuildExt(build_ext): + + def detect_modules(self): + # Ensure that /usr/local is always used +- add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') ++ add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib64') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + self.add_gcc_paths() + self.add_multiarch_paths() +@@ -677,11 +677,11 @@ class PyBuildExt(build_ext): + elif curses_library: + readline_libs.append(curses_library) + elif self.compiler.find_library_file(lib_dirs + +- ['/usr/lib/termcap'], ++ ['/usr/lib64/termcap'], + 'termcap'): + readline_libs.append('termcap') + exts.append( Extension('readline', ['readline.c'], +- library_dirs=['/usr/lib/termcap'], ++ library_dirs=['/usr/lib64/termcap'], + extra_link_args=readline_extra_link_args, + libraries=readline_libs) ) + else: +@@ -715,8 +715,8 @@ class PyBuildExt(build_ext): + if krb5_h: + ssl_incs += krb5_h + ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs, +- ['/usr/local/ssl/lib', +- '/usr/contrib/ssl/lib/' ++ ['/usr/local/ssl/lib64', ++ '/usr/contrib/ssl/lib64/' + ] ) + + if (ssl_incs is not None and diff --git a/SOURCES/python-2.7rc1-binutils-no-dep.patch b/SOURCES/python-2.7rc1-binutils-no-dep.patch new file mode 100644 index 00000000..ee6157c2 --- /dev/null +++ b/SOURCES/python-2.7rc1-binutils-no-dep.patch @@ -0,0 +1,14 @@ +diff -up Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep Python-2.7rc1/Lib/ctypes/util.py +--- Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep 2010-03-15 09:42:23.000000000 -0400 ++++ Python-2.7rc1/Lib/ctypes/util.py 2010-06-06 05:03:02.155975210 -0400 +@@ -140,7 +140,9 @@ elif os.name == "posix": + dump = f.read() + rv = f.close() + if rv == 10: +- raise OSError, 'objdump command not found' ++ return os.path.basename(f) # This is good for GLibc, I think, ++ # and a dep on binutils is big (for ++ # live CDs). + f = os.popen(cmd) + try: + data = f.read() diff --git a/SOURCES/python-2.7rc1-socketmodule-constants.patch b/SOURCES/python-2.7rc1-socketmodule-constants.patch new file mode 100644 index 00000000..c32e1030 --- /dev/null +++ b/SOURCES/python-2.7rc1-socketmodule-constants.patch @@ -0,0 +1,64 @@ +--- Python-2.7rc1/Modules/socketmodule.c.socketmodule 2010-05-09 10:46:46.000000000 -0400 ++++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:04:19.374234780 -0400 +@@ -4783,6 +4783,61 @@ init_socket(void) + PyModule_AddIntConstant(m, "SO_SETFIB", SO_SETFIB); + #endif + ++#ifdef SO_SNDBUFFORCE ++ PyModule_AddIntConstant(m, "SO_SNDBUFFORCE", SO_SNDBUFFORCE); ++#endif ++#ifdef SO_RCVBUFFORCE ++ PyModule_AddIntConstant(m, "SO_RCVBUFFORCE", SO_RCVBUFFORCE); ++#endif ++#ifdef SO_NO_CHECK ++ PyModule_AddIntConstant(m, "SO_NO_CHECK", SO_NO_CHECK); ++#endif ++#ifdef SO_PRIORITY ++ PyModule_AddIntConstant(m, "SO_PRIORITY", SO_PRIORITY); ++#endif ++#ifdef SO_BSDCOMPAT ++ PyModule_AddIntConstant(m, "SO_BSDCOMPAT", SO_BSDCOMPAT); ++#endif ++#ifdef SO_PASSCRED ++ PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED); ++#endif ++#ifdef SO_PEERCRED ++ PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED); ++#endif ++#ifdef SO_SECURITY_AUTHENTICATION ++ PyModule_AddIntConstant(m, "SO_SECURITY_AUTHENTICATION", SO_SECURITY_AUTHENTICATION); ++#endif ++#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT ++ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_TRANSPORT", SO_SECURITY_ENCRYPTION_TRANSPORT); ++#endif ++#ifdef SO_SECURITY_ENCRYPTION_NETWORK ++ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_NETWORK", SO_SECURITY_ENCRYPTION_NETWORK); ++#endif ++#ifdef SO_BINDTODEVICE ++ PyModule_AddIntConstant(m, "SO_BINDTODEVICE", SO_BINDTODEVICE); ++#endif ++#ifdef SO_ATTACH_FILTER ++ PyModule_AddIntConstant(m, "SO_ATTACH_FILTER", SO_ATTACH_FILTER); ++#endif ++#ifdef SO_DETACH_FILTER ++ PyModule_AddIntConstant(m, "SO_DETACH_FILTER", SO_DETACH_FILTER); ++#endif ++#ifdef SO_PEERNAME ++ PyModule_AddIntConstant(m, "SO_PEERNAME", SO_PEERNAME); ++#endif ++#ifdef SO_TIMESTAMP ++ PyModule_AddIntConstant(m, "SO_TIMESTAMP", SO_TIMESTAMP); ++#endif ++#ifdef SO_PEERSEC ++ PyModule_AddIntConstant(m, "SO_PEERSEC", SO_PEERSEC); ++#endif ++#ifdef SO_PASSSEC ++ PyModule_AddIntConstant(m, "SO_PASSSEC", SO_PASSSEC); ++#endif ++#ifdef SO_TIMESTAMPNS ++ PyModule_AddIntConstant(m, "SO_TIMESTAMPNS", SO_TIMESTAMPNS); ++#endif ++ + /* Maximum number of connections for "listen" */ + #ifdef SOMAXCONN + PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN); diff --git a/SOURCES/python-2.7rc1-socketmodule-constants2.patch b/SOURCES/python-2.7rc1-socketmodule-constants2.patch new file mode 100644 index 00000000..896ac886 --- /dev/null +++ b/SOURCES/python-2.7rc1-socketmodule-constants2.patch @@ -0,0 +1,19 @@ +diff -up Python-2.7rc1/Modules/socketmodule.c.socketmodule2 Python-2.7rc1/Modules/socketmodule.c +--- Python-2.7rc1/Modules/socketmodule.c.socketmodule2 2010-06-07 23:06:59.133498087 -0400 ++++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:11:51.249520087 -0400 +@@ -5253,6 +5253,15 @@ init_socket(void) + #ifdef TCP_QUICKACK + PyModule_AddIntConstant(m, "TCP_QUICKACK", TCP_QUICKACK); + #endif ++#ifdef TCP_CONGESTION ++ PyModule_AddIntConstant(m, "TCP_CONGESTION", TCP_CONGESTION); ++#endif ++#ifdef TCP_MD5SIG ++ PyModule_AddIntConstant(m, "TCP_MD5SIG", TCP_MD5SIG); ++#endif ++#ifdef TCP_MD5SIG_MAXKEYLEN ++ PyModule_AddIntConstant(m, "TCP_MD5SIG_MAXKEYLEN", TCP_MD5SIG_MAXKEYLEN); ++#endif + + + /* IPX options */ diff --git a/SOURCES/python.conf b/SOURCES/python.conf new file mode 100644 index 00000000..9002b3bc --- /dev/null +++ b/SOURCES/python.conf @@ -0,0 +1 @@ +x /tmp/pymp-* diff --git a/SOURCES/pythondeps.sh b/SOURCES/pythondeps.sh new file mode 100755 index 00000000..10a060aa --- /dev/null +++ b/SOURCES/pythondeps.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +[ $# -ge 1 ] || { + cat > /dev/null + exit 0 +} + +case $1 in +-P|--provides) + shift + # Match buildroot/payload paths of the form + # /PATH/OF/BUILDROOT/usr/bin/pythonMAJOR.MINOR + # generating a line of the form + # python(abi) = MAJOR.MINOR + # (Don't match against -config tools e.g. /usr/bin/python2.6-config) + grep "/usr/bin/python.\..$" \ + | sed -e "s|.*/usr/bin/python\(.\..\)|python(abi) = \1|" + ;; +-R|--requires) + shift + # Match buildroot paths of the form + # /PATH/OF/BUILDROOT/usr/lib/pythonMAJOR.MINOR/ and + # /PATH/OF/BUILDROOT/usr/lib64/pythonMAJOR.MINOR/ + # generating (uniqely) lines of the form: + # python(abi) = MAJOR.MINOR + grep "/usr/lib[^/]*/python.\../.*" \ + | sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|python(abi) = \1|g" \ + | sort | uniq + ;; +esac + +exit 0 diff --git a/SPECS/python.spec b/SPECS/python.spec new file mode 100644 index 00000000..5277f37b --- /dev/null +++ b/SPECS/python.spec @@ -0,0 +1,4233 @@ + +# ====================================================== +# Conditionals and other variables controlling the build +# ====================================================== + +%{!?__python_ver:%global __python_ver EMPTY} +#global __python_ver 27 +%global unicode ucs4 + +%if "%{__python_ver}" != "EMPTY" +%global main_python 0 +%global python python%{__python_ver} +%global tkinter tkinter%{__python_ver} +%else +%global main_python 1 +%global python python +%global tkinter tkinter +%endif + +%global pybasever 2.7 +%global pylibdir %{_libdir}/python%{pybasever} +%global tools_dir %{pylibdir}/Tools +%global demo_dir %{pylibdir}/Demo +%global doc_tools_dir %{pylibdir}/Doc/tools +%global dynload_dir %{pylibdir}/lib-dynload +%global site_packages %{pylibdir}/site-packages + +# Python's configure script defines SOVERSION, and this is used in the Makefile +# to determine INSTSONAME, the name of the libpython DSO: +# LDLIBRARY='libpython$(VERSION).so' +# INSTSONAME="$LDLIBRARY".$SOVERSION +# We mirror this here in order to make it easier to add the -gdb.py hooks. +# (if these get out of sync, the payload of the libs subpackage will fail +# and halt the build) +%global py_SOVERSION 1.0 +%global py_INSTSONAME_optimized libpython%{pybasever}.so.%{py_SOVERSION} +%global py_INSTSONAME_debug libpython%{pybasever}_d.so.%{py_SOVERSION} + +%global with_debug_build 1 + +# Disabled for now: +%global with_huntrleaks 0 + +%global with_gdb_hooks 1 + +%global with_systemtap 1 + +# some arches don't have valgrind so we need to disable its support on them +%ifarch %{ix86} x86_64 ppc %{power64} s390x aarch64 +%global with_valgrind 1 +%else +%global with_valgrind 0 +%endif + +# Having more than 28 cores on a PPC machine will lead to race conditions +# during build so we have to set a limit. +# See: https://bugzilla.redhat.com/show_bug.cgi?id=1568974 +%ifarch ppc %{power64} && %_smp_ncpus_max > 28 +%global _smp_ncpus_max 28 +%endif + +%global with_gdbm 1 + +# Turn this to 0 to turn off the "check" phase: +%global run_selftest_suite 1 + +# Some of the files below /usr/lib/pythonMAJOR.MINOR/test (e.g. bad_coding.py) +# are deliberately invalid, leading to SyntaxError exceptions if they get +# byte-compiled. +# +# These errors are ignored by the normal python build, and aren't normally a +# problem in the buildroots since /usr/bin/python isn't present. +# +# However, for the case where we're rebuilding the python srpm on a machine +# that does have python installed we need to set this to avoid +# brp-python-bytecompile treating these as fatal errors: +# +%global _python_bytecompile_errors_terminate_build 0 + +# We need to get a newer configure generated out of configure.in for the following +# patches: +# patch 4 (CFLAGS) +# patch 52 (valgrind) +# patch 55 (systemtap) +# patch 145 (linux2) +# +# For patch 55 (systemtap), we need to get a new header for configure to use +# +# configure.in requires autoconf-2.65, but the version in Fedora is currently +# autoconf-2.66 +# +# For now, we'll generate a patch to the generated configure script and +# pyconfig.h.in on a machine that has a local copy of autoconf 2.65 +# +# Instructions on obtaining such a copy can be seen at +# http://bugs.python.org/issue7997 +# +# To make it easy to regenerate the patch, this specfile can be run in two +# ways: +# (i) regenerate_autotooling_patch 0 : the normal approach: prep the +# source tree using a pre-generated patch to the "configure" script, and do a +# full build +# (ii) regenerate_autotooling_patch 1 : intended to be run on a developer's +# workstation: prep the source tree without patching configure, then rerun a +# local copy of autoconf-2.65, regenerate the patch, then exit, without doing +# the rest of the build +%global regenerate_autotooling_patch 0 + + +# ================== +# Top-level metadata +# ================== +Summary: An interpreted, interactive, object-oriented programming language +Name: %{python} +# Remember to also rebase python-docs when changing this: +Version: 2.7.5 +Release: 76%{?dist} +License: Python +Group: Development/Languages +Requires: %{python}-libs%{?_isa} = %{version}-%{release} +Provides: python-abi = %{pybasever} +Provides: python(abi) = %{pybasever} + + +# ======================= +# Build-time requirements +# ======================= + +# (keep this list alphabetized) + +BuildRequires: autoconf +BuildRequires: bluez-libs-devel +BuildRequires: bzip2 +BuildRequires: bzip2-devel + +# expat 2.1.0 added the symbol XML_SetHashSalt without bumping SONAME. We use +# it (in pyexpat) in order to enable the fix in Python-2.7.3 for CVE-2012-0876: +BuildRequires: expat-devel >= 2.1.0 + +BuildRequires: findutils +BuildRequires: gcc-c++ +%if %{with_gdbm} +BuildRequires: gdbm-devel +%endif +BuildRequires: glibc-devel +BuildRequires: gmp-devel +BuildRequires: libdb-devel +BuildRequires: libffi-devel +BuildRequires: libGL-devel +BuildRequires: libX11-devel +BuildRequires: ncurses-devel +BuildRequires: openssl-devel +BuildRequires: pkgconfig +BuildRequires: readline-devel +BuildRequires: sqlite-devel + +%if 0%{?with_systemtap} +BuildRequires: systemtap-sdt-devel +# (this introduces a circular dependency, in that systemtap-sdt-devel's +# /usr/bin/dtrace is a python script) +%global tapsetdir /usr/share/systemtap/tapset +%endif # with_systemtap + +BuildRequires: tar +BuildRequires: tcl-devel +BuildRequires: tix-devel +BuildRequires: tk-devel + +%if 0%{?with_valgrind} +BuildRequires: valgrind-devel +%endif + +BuildRequires: zlib-devel + + + +# ======================= +# Source code and patches +# ======================= + +Source: http://www.python.org/ftp/python/%{version}/Python-%{version}.tar.xz + +# Work around bug 562906 until it's fixed in rpm-build by providing a fixed +# version of pythondeps.sh: +Source2: pythondeps.sh +%global __python_requires %{SOURCE2} + +# Systemtap tapset to make it easier to use the systemtap static probes +# (actually a template; LIBRARY_PATH will get fixed up during install) +# Written by dmalcolm; not yet sent upstream +Source3: libpython.stp + + +# Example systemtap script using the tapset +# Written by wcohen, mjw, dmalcolm; not yet sent upstream +Source4: systemtap-example.stp + +# Another example systemtap script that uses the tapset +# Written by dmalcolm; not yet sent upstream +Source5: pyfuntop.stp + +# Supply various useful macros for building Python 2 components: +Source6: macros.python2 + +Source7: pynche + +# Configuration file to change ssl verification settings globally +# Downstream only see Patch224 +Source8: cert-verification.cfg + +# configuration for systemd's tmpfiles +Source9: python.conf + +# Supply various useful macros for building Python components: +# NOTE: The %%python_provide macro is copied directly from Fedora/EPEL, but the +# %%{python3_pkgversion} and %%{python3_other_pkgversion} macros used within it +# are missing in RHEL. However, in their absence the lua code will run fine for +# Python 2 packages and will print an error only if invoked for Python 3 +# packages (unless the python-srpm-macros package from EPEL is installed). That +# is a desirable behaviour as RHEL without EPEL does not support building +# Python 3 packages. +Source10: macros.python + +# Modules/Setup.dist is ultimately used by the "makesetup" script to construct +# the Makefile and config.c +# +# Upstream leaves many things disabled by default, to try to make it easy as +# possible to build the code on as many platforms as possible. +# +# TODO: many modules can also now be built by setup.py after the python binary +# has been built; need to assess if we should instead build things there +# +# We patch it downstream as follows: +# - various modules are built by default by upstream as static libraries; +# we built them as shared libraries +# - build the "readline" module (appears to also be handled by setup.py now) +# - enable the build of the following modules: +# - array arraymodule.c # array objects +# - cmath cmathmodule.c # -lm # complex math library functions +# - math mathmodule.c # -lm # math library functions, e.g. sin() +# - _struct _struct.c # binary structure packing/unpacking +# - time timemodule.c # -lm # time operations and variables +# - operator operator.c # operator.add() and similar goodies +# - _weakref _weakref.c # basic weak reference support +# - _testcapi _testcapimodule.c # Python C API test module +# - _random _randommodule.c # Random number generator +# - _collections _collectionsmodule.c # Container types +# - itertools itertoolsmodule.c +# - strop stropmodule.c +# - _functools _functoolsmodule.c +# - _bisect _bisectmodule.c # Bisection algorithms +# - unicodedata unicodedata.c # static Unicode character database +# - _locale _localemodule.c +# - fcntl fcntlmodule.c # fcntl(2) and ioctl(2) +# - spwd spwdmodule.c # spwd(3) +# - grp grpmodule.c # grp(3) +# - select selectmodule.c # select(2); not on ancient System V +# - mmap mmapmodule.c # Memory-mapped files +# - _csv _csv.c # CSV file helper +# - _socket socketmodule.c # Socket module helper for socket(2) +# - _ssl _ssl.c +# - crypt cryptmodule.c -lcrypt # crypt(3) +# - nis nismodule.c -lnsl # Sun yellow pages -- not everywhere +# - termios termios.c # Steen Lumholt's termios module +# - resource resource.c # Jeremy Hylton's rlimit interface +# - audioop audioop.c # Operations on audio samples +# - imageop imageop.c # Operations on images +# - _md5 md5module.c md5.c +# - _sha shamodule.c +# - _sha256 sha256module.c +# - _sha512 sha512module.c +# - linuxaudiodev linuxaudiodev.c +# - timing timingmodule.c +# - _tkinter _tkinter.c tkappinit.c +# - dl dlmodule.c +# - gdbm gdbmmodule.c +# - _bsddb _bsddb.c +# - binascii binascii.c +# - parser parsermodule.c +# - cStringIO cStringIO.c +# - cPickle cPickle.c +# - zlib zlibmodule.c +# - _multibytecodec cjkcodecs/multibytecodec.c +# - _codecs_cn cjkcodecs/_codecs_cn.c +# - _codecs_hk cjkcodecs/_codecs_hk.c +# - _codecs_iso2022 cjkcodecs/_codecs_iso2022.c +# - _codecs_jp cjkcodecs/_codecs_jp.c +# - _codecs_kr cjkcodecs/_codecs_kr.c +# - _codecs_tw cjkcodecs/_codecs_tw.c +Patch0: python-2.7.1-config.patch + +# Removes the "-g" option from "pydoc", for some reason; I believe +# (dmalcolm 2010-01-29) that this was introduced in this change: +# - fix pydoc (#68082) +# in 2.2.1-12 as a response to the -g option needing TkInter installed +# (Red Hat Linux 8) +# Not upstream +Patch1: 00001-pydocnogui.patch + +# Add $(CFLAGS) to the linker arguments when linking the "python" binary +# since some architectures (sparc64) need this (rhbz:199373). +# Not yet filed upstream +Patch4: python-2.5-cflags.patch + +# Work around a bug in Python' gettext module relating to the "Plural-Forms" +# header (rhbz:252136) +# Related to upstream issues: +# http://bugs.python.org/issue1448060 and http://bugs.python.org/issue1475523 +# though the proposed upstream patches are, alas, different +Patch6: python-2.5.1-plural-fix.patch + +# This patch was listed in the changelog as: +# * Fri Sep 14 2007 Jeremy Katz - 2.5.1-11 +# - fix encoding of sqlite .py files to work around weird encoding problem +# in Turkish (#283331) +# A traceback attached to rhbz 244016 shows the problem most clearly: a +# traceback on attempting to import the sqlite module, with: +# "SyntaxError: encoding problem: with BOM (__init__.py, line 1)" +# This seems to come from Parser/tokenizer.c:check_coding_spec +# Our patch changes two source files within sqlite3, removing the +# "coding: ISO-8859-1" specs and character E4 = U+00E4 = +# LATIN SMALL LETTER A WITH DIAERESIS from in ghaering's surname. +# +# It may be that the conversion of "ISO-8859-1" to "iso-8859-1" is thwarted +# by the implementation of "tolower" in the Turkish locale; see: +# https://bugzilla.redhat.com/show_bug.cgi?id=191096#c9 +# +# TODO: Not yet sent upstream, and appears to me (dmalcolm 2010-01-29) that +# it may be papering over a symptom +Patch7: python-2.5.1-sqlite-encoding.patch + +# FIXME: Lib/ctypes/util.py posix implementation defines a function +# _get_soname(f). Upstreams's implementation of this uses objdump to read the +# SONAME from a library; we avoid this, apparently to minimize space +# requirements on the live CD: +# (rhbz:307221) +Patch10: python-2.7rc1-binutils-no-dep.patch + +# Upstream as of Python 2.7.3: +# Patch11: python-2.7rc1-codec-ascii-tolower.patch + +# Add various constants to the socketmodule (rhbz#436560): +# TODO: these patches were added in 2.5.1-22 and 2.5.1-24 but appear not to +# have been sent upstream yet: +Patch13: python-2.7rc1-socketmodule-constants.patch +Patch14: python-2.7rc1-socketmodule-constants2.patch + +# Remove an "-rpath $(LIBDIR)" argument from the linkage args in configure.in: +# FIXME: is this for OSF, not Linux? +Patch16: python-2.6-rpath.patch + +# Fixup distutils/unixccompiler.py to remove standard library path from rpath: +# Adapted from Patch0 in ivazquez' python3000 specfile, removing usage of +# super() as it's an old-style class +Patch17: python-2.6.4-distutils-rpath.patch + +# 00055 # +# Systemtap support: add statically-defined probe points +# Patch based on upstream bug: http://bugs.python.org/issue4111 +# fixed up by mjw and wcohen for 2.6.2, then fixed up by dmalcolm for 2.6.4 +# then rewritten by mjw (attachment 390110 of rhbz 545179), then reformatted +# for 2.7rc1 by dmalcolm: +Patch55: 00055-systemtap.patch + +# Upstream as of Python 2.7.4 +# Patch101: 00101-lib64-regex.patch + +# Only used when "%%{_lib}" == "lib64" +# Fixup various paths throughout the build and in distutils from "lib" to "lib64", +# and add the /usr/lib64/pythonMAJOR.MINOR/site-packages to sitedirs, in front of +# /usr/lib/pythonMAJOR.MINOR/site-packages +# Not upstream +Patch102: python-2.7.3-lib64.patch + +# Python 2.7 split out much of the path-handling from distutils/sysconfig.py to +# a new sysconfig.py (in r77704). +# We need to make equivalent changes to that new file to ensure that the stdlib +# and platform-specific code go to /usr/lib64 not /usr/lib, on 64-bit archs: +Patch103: python-2.7-lib64-sysconfig.patch + +# 00104 # +# Only used when "%%{_lib}" == "lib64" +# Another lib64 fix, for distutils/tests/test_install.py; not upstream: +Patch104: 00104-lib64-fix-for-test_install.patch + +# 00111 # +# Patch the Makefile.pre.in so that the generated Makefile doesn't try to build +# a libpythonMAJOR.MINOR.a (bug 550692): +# Downstream only: not appropriate for upstream +Patch111: 00111-no-static-lib.patch + +# 00112 # +# Patch to support building both optimized vs debug stacks DSO ABIs, sharing +# the same .py and .pyc files, using "_d.so" to signify a debug build of an +# extension module. +# +# Based on Debian's patch for the same, +# http://patch-tracker.debian.org/patch/series/view/python2.6/2.6.5-2/debug-build.dpatch +# +# (which was itself based on the upstream Windows build), but with some +# changes: +# +# * Debian's patch to dynload_shlib.c looks for module_d.so, then module.so, +# but this can potentially find a module built against the wrong DSO ABI. We +# instead search for just module_d.so in a debug build +# +# * We remove this change from configure.in's build of the Makefile: +# SO=$DEBUG_EXT.so +# so that sysconfig.py:customize_compiler stays with shared_lib_extension='.so' +# on debug builds, so that UnixCCompiler.find_library_file can find system +# libraries (otherwise "make sharedlibs" fails to find system libraries, +# erroneously looking e.g. for "libffi_d.so" rather than "libffi.so") +# +# * We change Lib/distutils/command/build_ext.py:build_ext.get_ext_filename +# to add the _d there, when building an extension. This way, "make sharedlibs" +# can build ctypes, by finding the sysmtem libffi.so (rather than failing to +# find "libffi_d.so"), and builds the module as _ctypes_d.so +# +# * Similarly, update build_ext:get_libraries handling of Py_ENABLE_SHARED by +# appending "_d" to the python library's name for the debug configuration +# +# * We modify Modules/makesetup to add the "_d" to the generated Makefile +# rules for the various Modules/*.so targets +# +# This may introduce issues when building an extension that links directly +# against another extension (e.g. users of NumPy?), but seems more robust when +# searching for external libraries +# +# * We don't change Lib/distutils/command/build.py: build.build_purelib to +# embed plat_specifier, leaving it as is, as pure python builds should be +# unaffected by these differences (we'll be sharing the .py and .pyc files) +# +# * We introduce DEBUG_SUFFIX as well as DEBUG_EXT: +# - DEBUG_EXT is used by ELF files (names and SONAMEs); it will be "_d" for +# a debug build +# - DEBUG_SUFFIX is used by filesystem paths; it will be "-debug" for a +# debug build +# +# Both will be empty in an optimized build. "_d" contains characters that +# are valid ELF metadata, but this leads to various ugly filesystem paths (such +# as the include path), and DEBUG_SUFFIX allows these paths to have more natural +# names. Changing this requires changes elsewhere in the distutils code. +# +# * We add DEBUG_SUFFIX to PYTHON in the Makefile, so that the two +# configurations build parallel-installable binaries with different names +# ("python-debug" vs "python"). +# +# * Similarly, we add DEBUG_SUFFIX within python-config and +# python$(VERSION)-config, so that the two configuration get different paths +# for these. +# +# See also patch 130 below +# +Patch112: python-2.7.3-debug-build.patch + + +# 00113 # +# Add configure-time support for the COUNT_ALLOCS and CALL_PROFILE options +# described at http://svn.python.org/projects/python/trunk/Misc/SpecialBuilds.txt +# so that if they are enabled, they will be in that build's pyconfig.h, so that +# extension modules will reliably use them +# Not yet sent upstream +Patch113: 00113-more-configuration-flags.patch + +# 00114 # +# Add flags for statvfs.f_flag to the constant list in posixmodule (i.e. "os") +# (rhbz:553020); partially upstream as http://bugs.python.org/issue7647 +# Not yet sent upstream +Patch114: 00114-statvfs-f_flag-constants.patch + +# Upstream as of Python 2.7.3: +# Patch115: make-pydoc-more-robust-001.patch + +# Upstream r79310 removed the "Modules" directory from sys.path when Python is +# running from the build directory on POSIX to fix a unit test (issue #8205). +# This seems to have broken the compileall.py done in "make install": it cannot +# find shared library extension modules at this point in the build (sys.path +# does not contain DESTDIR/usr/lib(64)/python-2.7/lib-dynload for some reason), +# leading to the build failing with: +# Traceback (most recent call last): +# File "/home/david/rpmbuild/BUILDROOT/python-2.7-0.1.rc2.fc14.x86_64/usr/lib64/python2.7/compileall.py", line 17, in +# import struct +# File "/home/david/rpmbuild/BUILDROOT/python-2.7-0.1.rc2.fc14.x86_64/usr/lib64/python2.7/struct.py", line 1, in +# from _struct import * +# ImportError: No module named _struct +# This patch adds the build Modules directory to build path. +Patch121: 00121-add-Modules-to-build-path.patch + +# 00125 # +# COUNT_ALLOCS is useful for debugging, but the upstream behaviour of always +# emitting debug info to stdout on exit is too verbose and makes it harder to +# use the debug build. Add a "PYTHONDUMPCOUNTS" environment variable which +# must be set to enable the output on exit +# Not yet sent upstream +Patch125: 00125-less-verbose-COUNT_ALLOCS.patch + +# Upstream as of Python 2.7.5 +# Patch126: fix-dbm_contains-on-64bit-bigendian.patch + +# Upstream as of Python 2.7.5 +# Patch127: fix-test_structmember-on-64bit-bigendian.patch + +# 2.7.1 (in r84230) added a test to test_abc which fails if python is +# configured with COUNT_ALLOCS, which is the case for our debug build +# (the COUNT_ALLOCS instrumentation keeps "C" alive). +# Not yet sent upstream +Patch128: python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch + +# 00130 # +# Add "--extension-suffix" option to python-config and python-debug-config +# (rhbz#732808) +# +# This is adapted from 3.2's PEP-3149 support. +# +# Fedora's debug build has some non-standard features (see also patch 112 +# above), though largely shared with Debian/Ubuntu and Windows +# +# In particular, SO in the Makefile is currently always just ".so" for our +# python 2 optimized builds, but for python 2 debug it should be '_d.so', to +# distinguish the debug vs optimized ABI, following the pattern in the above +# patch. +# +# Not yet sent upstream +Patch130: python-2.7.2-add-extension-suffix-to-python-config.patch + +# 00131 # +# The four tests in test_io built on top of check_interrupted_write_retry +# fail when built in Koji, for ppc and ppc64; for some reason, the SIGALRM +# handlers are never called, and the call to write runs to completion +# (rhbz#732998) +Patch131: 00131-disable-tests-in-test_io.patch + +# 00132 # +# Add non-standard hooks to unittest for use in the "check" phase below, when +# running selftests within the build: +# @unittest._skipInRpmBuild(reason) +# for tests that hang or fail intermittently within the build environment, and: +# @unittest._expectedFailureInRpmBuild +# for tests that always fail within the build environment +# +# The hooks only take effect if WITHIN_PYTHON_RPM_BUILD is set in the +# environment, which we set manually in the appropriate portion of the "check" +# phase below (and which potentially other python-* rpms could set, to reuse +# these unittest hooks in their own "check" phases) +Patch132: 00132-add-rpmbuild-hooks-to-unittest.patch + +# 00133 # +# "dl" is deprecated, and test_dl doesn't work on 64-bit builds: +Patch133: 00133-skip-test_dl.patch + +# 00134 # +# Fix a failure in test_sys.py when configured with COUNT_ALLOCS enabled +# Not yet sent upstream +Patch134: 00134-fix-COUNT_ALLOCS-failure-in-test_sys.patch + +# 00135 # +# Skip "test_callback_in_cycle_resurrection" in a debug build, where it fails: +# Not yet sent upstream +Patch135: 00135-skip-test-within-test_weakref-in-debug-build.patch + +# 00136 # +# Some tests try to seek on sys.stdin, but don't work as expected when run +# within Koji/mock; skip them within the rpm build: +Patch136: 00136-skip-tests-of-seeking-stdin-in-rpmbuild.patch + +# 00137 # +# Some tests within distutils fail when run in an rpmbuild: +Patch137: 00137-skip-distutils-tests-that-fail-in-rpmbuild.patch + +# 00138 # +# Fixup some tests within distutils to work with how debug builds are set up: +Patch138: 00138-fix-distutils-tests-in-debug-build.patch + +# 00139 # +# ARM-specific: skip known failure in test_float: +# http://bugs.python.org/issue8265 (rhbz#706253) +Patch139: 00139-skip-test_float-known-failure-on-arm.patch + +# 00140 # +# Sparc-specific: skip known failure in test_ctypes: +# http://bugs.python.org/issue8314 (rhbz#711584) +# which appears to be a libffi bug +Patch140: 00140-skip-test_ctypes-known-failure-on-sparc.patch + +# 00141 # +# Fix test_gc's test_newinstance case when configured with COUNT_ALLOCS: +# Not yet sent upstream +Patch141: 00141-fix-test_gc_with_COUNT_ALLOCS.patch + +# 00142 # +# Some pty tests fail when run in mock (rhbz#714627): +Patch142: 00142-skip-failing-pty-tests-in-rpmbuild.patch + +# 00143 # +# Fix the --with-tsc option on ppc64, and rework it on 32-bit ppc to avoid +# aliasing violations (rhbz#698726) +# Sent upstream as http://bugs.python.org/issue12872 +Patch143: 00143-tsc-on-ppc.patch + +# 00144 # +# (Optionally) disable the gdbm module: +Patch144: 00144-no-gdbm.patch + +# 00145 # +# Upstream as of Python 2.7.3: +# Patch145: 00145-force-sys-platform-to-be-linux2.patch + +# 00146 # +# Support OpenSSL FIPS mode (e.g. when OPENSSL_FORCE_FIPS_MODE=1 is set) +# - handle failures from OpenSSL (e.g. on attempts to use MD5 in a +# FIPS-enforcing environment) +# - add a new "usedforsecurity" keyword argument to the various digest +# algorithms in hashlib so that you can whitelist a callsite with +# "usedforsecurity=False" +# (sent upstream for python 3 as http://bugs.python.org/issue9216; this is a +# backport to python 2.7; see RHEL6 patch 119) +# - enforce usage of the _hashlib implementation: don't fall back to the _md5 +# and _sha* modules (leading to clearer error messages if fips selftests +# fail) +# - don't build the _md5 and _sha* modules; rely on the _hashlib implementation +# of hashlib (for example, md5.py will use _hashlib's implementation of MD5, +# if permitted by the FIPS setting) +# (rhbz#563986) +Patch146: 00146-hashlib-fips.patch + +# 00147 # +# Add a sys._debugmallocstats() function +# Based on patch 202 from RHEL 5's python.spec, with updates from rhbz#737198 +# Sent upstream as http://bugs.python.org/issue14785 +Patch147: 00147-add-debug-malloc-stats.patch + +# 00148 # +# Upstream as of Python 2.7.3: +# Patch148: 00148-gdbm-1.9-magic-values.patch + +# 00149 # +# python3.spec's +# Patch149: 00149-backport-issue11254-pycache-bytecompilation-fix.patch +# is not relevant for Python 2 + +# 00150 # +# python3.spec has: +# Patch150: 00150-disable-rAssertAlmostEqual-cmath-on-ppc.patch +# as a workaround for a glibc bug on PPC (bz #750811) + +# 00151 # +# Upstream as of Python 2.7.3: +# Patch151: 00151-fork-deadlock.patch + +# 00152 # +# python3.spec has: +# Patch152: 00152-fix-test-gdb-regex.patch + +# 00153 # +# Strip out lines of the form "warning: Unable to open ..." from gdb's stderr +# when running test_gdb.py; also cope with change to gdb in F17 onwards in +# which values are printed as "v@entry" rather than just "v": +# Not yet sent upstream +Patch153: 00153-fix-test_gdb-noise.patch + +# 00154 # +# python3.spec on f15 has: +# Patch154: 00154-skip-urllib-test-requiring-working-DNS.patch + +# 00155 # +# Avoid allocating thunks in ctypes unless absolutely necessary, to avoid +# generating SELinux denials on "import ctypes" and "import uuid" when +# embedding Python within httpd (rhbz#814391) +Patch155: 00155-avoid-ctypes-thunks.patch + +# 00156 # +# Recent builds of gdb will only auto-load scripts from certain safe +# locations. Turn off this protection when running test_gdb in the selftest +# suite to ensure that it can load our -gdb.py script (rhbz#817072): +# Not yet sent upstream +Patch156: 00156-gdb-autoload-safepath.patch + +# 00157 # +# Update uid/gid handling throughout the standard library: uid_t and gid_t are +# unsigned 32-bit values, but existing code often passed them through C long +# values, which are signed 32-bit values on 32-bit architectures, leading to +# negative int objects for uid/gid values >= 2^31 on 32-bit architectures. +# +# Introduce _PyObject_FromUid/Gid to convert uid_t/gid_t values to python +# objects, using int objects where the value will fit (long objects otherwise), +# and _PyArg_ParseUid/Gid to convert int/long to uid_t/gid_t, with -1 allowed +# as a special case (since this is given special meaning by the chown syscall) +# +# Update standard library to use this throughout for uid/gid values, so that +# very large uid/gid values are round-trippable, and -1 remains usable. +# (rhbz#697470) +Patch157: 00157-uid-gid-overflows.patch + +# Upstream as of Python 2.7.4 +# Patch158: 00158-fix-hashlib-leak.patch + +# 00160 # +# python3.spec's +# Patch160: 00160-disable-test_fs_holes-in-rpm-build.patch +# is not relevant for Python 2 + +# 00161 # +# python3.spec has: +# Patch161: 00161-fix-test_tools-directory.patch +# which will likely become relevant for Python 2 next time we rebase + +# 00162 # +# python3.spec has: +# Patch162: 00162-distutils-sysconfig-fix-CC-options.patch + +# 00163 # +# python3.spec has: +# Patch163: 00163-disable-parts-of-test_socket-in-rpm-build.patch + +# 00164 # +# python3.spec has: +# Patch164: 00164-disable-interrupted_write-tests-on-ppc.patch + +# 00165 # +# Backport to Python 2 from Python 3.3 of improvements to the "crypt" module +# adding precanned ways of salting a password (rhbz#835021) +# Based on r88500 patch to py3k from Python 3.3 +# plus 6482dd1c11ed, 0586c699d467, 62994662676a, 74a1110a3b50, plus edits +# to docstrings to note that this additional functionality is not standard +# within 2.7 +Patch165: 00165-crypt-module-salt-backport.patch + +# 00166 # +# Bulletproof the gdb debugging hooks against the case where co_filename for +# a frame can't be read from the inferior process (rhbz#912025) +# +# Not yet sent upstream +Patch166: 00166-fix-fake-repr-in-gdb-hooks.patch + +# 00167 # +# Don't run any of the stack navigation tests in test_gdb when Python is +# optimized, since there appear to be many different ways in which gdb can +# fail to read the PyFrameObject* for arbitrary places in the callstack, +# presumably due to compiler optimization (rhbz#912025) +# +# Not yet sent upstream +Patch167: 00167-disable-stack-navigation-tests-when-optimized-in-test_gdb.patch + +# 00168 # +# Update distutils.sysconfig so that if CFLAGS is defined in the environment, +# when building extension modules, it is appended to the full compilation +# flags from Python's Makefile, rather than instead reducing the compilation +# flags to the subset within OPT and adding it to those. +# +# In particular, this should ensure that "-fno-strict-aliasing" is used by +# "python setup.py build" even when CFLAGS is defined in the environment. +# +# (rhbz#849994) +Patch168: 00168-distutils-cflags.patch + +# 00169 # +# Use SHA-256 rather than implicitly using MD5 within the challenge handling +# in multiprocessing.connection +# +# Sent upstream as http://bugs.python.org/issue17258 +# (rhbz#879695) +Patch169: 00169-avoid-implicit-usage-of-md5-in-multiprocessing.patch + +# 00170 # +# In debug builds, try to print repr() when a C-level assert fails in the +# garbage collector (typically indicating a reference-counting error +# somewhere else e.g in an extension module) +# Backported to 2.7 from a patch I sent upstream for py3k +# http://bugs.python.org/issue9263 (rhbz#614680) +# hiding the proposed new macros/functions within gcmodule.c to avoid exposing +# them within the extension API. +# (rhbz#850013) +Patch170: 00170-gc-assertions.patch + +# Upstream as of Python 2.7.4 +# Patch171: 00171-raise-correct-exception-when-dev-urandom-is-missing.patch + +# Upstream as of Python 2.7.4 +# Patch172: 00172-use-poll-for-multiprocessing-socket-connection.patch + +# 00173 # +# Workaround for ENOPROTOOPT seen in Koji within +# test.test_support.bind_port() +# (rhbz#913732) +Patch173: 00173-workaround-ENOPROTOOPT-in-bind_port.patch + +# 00174 # +# Workaround for failure to set up prefix/exec_prefix when running +# an embededed libpython that sets Py_SetProgramName() to a name not +# on $PATH when run from the root directory due to +# https://fedoraproject.org/wiki/Features/UsrMove +# e.g. cmpi-bindings under systemd (rhbz#817554): +Patch174: 00174-fix-for-usr-move.patch + +# 00175 # +# Upstream as of Python 2.7.5 +# Patch175: 00175-fix-configure-Wformat.patch + +# 00176 # +# python3.spec had: +# Patch176: 00176-upstream-issue16754-so-extension.patch +# doesn't affect python2 + +# 00177 # +# python3.spec has +# Patch177: 00177-platform-unicode.patch +# Does not affect python2 + +# 00178 # +# python3.spec has +# Patch178: 00178-dont-duplicate-flags-in-sysconfig.patch +# Does not affect python2 AFAICS (different sysconfig values initialization) + +# 00179 # +# python3.spec has +# Patch179: 00179-dont-raise-error-on-gdb-corrupted-frames-in-backtrace.patch +# Doesn't seem to affect python2 + +# 00180 # +# Enable building on ppc64p7 +# Not appropriate for upstream, Fedora-specific naming +Patch180: 00180-python-add-support-for-ppc64p7.patch + +# 00181 # +# Allow arbitrary timeout for Condition.wait, as reported in +# https://bugzilla.redhat.com/show_bug.cgi?id=917709 +# Upstream doesn't want this: http://bugs.python.org/issue17748 +# But we have no better solution downstream yet, and since there is +# no API breakage, we apply this patch. +# Doesn't apply to Python 3, where this is fixed otherwise and works. +Patch181: 00181-allow-arbitrary-timeout-in-condition-wait.patch + +# 00182 # +# python3.spec had +# Patch182: 00182-fix-test_gdb-test_threads.patch + +# 00183 # +# python3.spec has +# Patch183: 00183-cve-2013-2099-fix-ssl-match_hostname-dos.patch + +# 00184 # +# Fix for https://bugzilla.redhat.com/show_bug.cgi?id=979696 +# Fixes build of ctypes against libffi with multilib wrapper +# Python recognizes ffi.h only if it contains "#define LIBFFI_H", +# but the wrapper doesn't contain that, which makes the build fail +# We patch this by also accepting "#define ffi_wrapper_h" +Patch184: 00184-ctypes-should-build-with-libffi-multilib-wrapper.patch + +# 00185 # +# Makes urllib2 honor "no_proxy" enviroment variable for "ftp:" URLs +# when ftp_proxy is set +# Resolves rhbz#971267 +Patch185: 00185-urllib2-honors-noproxy-for-ftp.patch + +# 00186 # +# Fix memory leak of variable utf8 in marshal.c +# (rhbz#990554) +Patch186: 00186-memory-leak-marshalc.patch + +# 00187 # +# Add an explicit RPATH to pyexpat.so pointing at the directory +# containing the system expat (which has the extra XML_SetHashSalt +# symbol), to avoid an ImportError with a link error if there's an +# LD_LIBRARY_PATH containing a "vanilla" build of expat (without the +# symbol) (originally rhbz#833271, for rhel 7 rhbz#996665): +Patch187: 00187-add-RPATH-to-pyexpat.patch + +# 00188 # +# Fix for CVE-2013-4238 -- +# SSL module fails to handle NULL bytes inside subjectAltNames general names +# http://bugs.python.org/issue18709 +# rhbz#998781 +Patch188: 00188-CVE-2013-4238-hostname-check-bypass-in-SSL-module.patch + +# 00189 # +# Fixes gdb py-bt command not to raise exception while processing +# statements from eval +# rhbz#1008154 (patch by Attila Fazekas) +Patch189: 00189-gdb-py-bt-dont-raise-exception-from-eval.patch + +# 190 # +# Don't fail various gdb tests on ppc64 if glibc debug +# symbols are installed +Patch190: 00190-gdb-fix-ppc64-failures.patch + +# 00191 # +# Add explicit RPATH to _elementtree.so +# rhbz#1019345 +Patch191: 00191-add-RPATH-to-elementtree.patch + +# 00192 # +# Fix missing documentation for some keywords +# rhbz#1032116 +Patch192: 00192-Fix-missing-documentation-for-some-keywords.patch + +# 00193 # +# Fix buffer overflow (upstream patch, http://bugs.python.org/issue20246) +# rhbz#1062376 +Patch193: 00193-buffer-overflow.patch + +# 00194 # +# Make GDB test pass even if GDB prints program counter for +# the first trace frame +Patch194: 00194-gdb-dont-fail-on-frame-with-address.patch + +# 0195 # +# Make multiprocessing ignore EINTR +# rhbz#1181624 +Patch195: 00195-make-multiproc-ignore-EINTR.patch + +# 00196 # +# Avoid double close of subprocess pipes when the child process +# fails starting +# rhbz#110345p +Patch196: 00196-avoid-double-close-of-pipes.patch + +# 00197 # +# Add missing import in bdist_rpm +# rhbz#1177613 +Patch197: 00197-add-missing-import-in-bdist_rpm.patch + +# 00198 # +# Fix importing readline producing erroneous output +Patch198: 00198-fix-readline-erroneous-output.patch + +# 00199 # +# Fix for CVE-2013-1753 +# rhbz#1046170 +Patch199: 00199-CVE-2013-1753.patch + +# 00200 # +# Fix for CVE-2014-4616 +# rhbz#1112285 +Patch200: 00200-CVE-2014-4616.patch + +# 00201 # +# Fix for CVE-2014-4650 +# rhbz#1113527 +Patch201: 00201-CVE-2014-4650.patch + +# 00202 # +# Fix for CVE-2014-7185 +# rhbz#1146026 +Patch202: 00202-CVE-2014-7185.patch + +# Fixes for CVE-2013-1752 +# rhbz#1046174 +Patch203: 00203-CVE-2013-1752-nntplib.patch +Patch204: 00204-CVE-2013-1752-ftplib.patch +Patch205: 00205-CVE-2013-1752-httplib-headers.patch +Patch206: 00206-CVE-2013-1752-poplib.patch +Patch207: 00207-CVE-2013-1752-smtplib.patch +Patch208: 00208-CVE-2013-1752-imaplib.patch + +# ================== PEP466=========================== +# Massive backport of PEP466 and relevant other fixes +# ================rhbz#1111461======================== +# 00209 # +# backport hmac.compare_digest +# http://bugs.python.org/issue21306 +Patch209: 00209-pep466-backport-hmac.compare_digest.patch +# 00210 # +# backport hashlib.pbkdf2_hmac +# http://bugs.python.org/issue21304 +Patch210: 00210-pep466-backport-hashlib.pbkdf2_hmac.patch +# 00211 # +# UTF-7 decoder can produce inconsistent Unicode string +# http://bugs.python.org/issue19279 +Patch211: 00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch +# 00212 # +# Add range check for %c in PyUnicode_FromFormat +# http://bugs.python.org/issue18184 +Patch212: 00212-pep466-pyunicode_fromformat-raise-overflow.patch +# 00213 # +# Fix %S, %R and %V formats of PyUnicode_FromFormat(). +# http://bugs.python.org/issue122023 +Patch213: 00213-pep466-pyunicode_fromformat-fix-formats.patch +# 00214 # +# Backport SSL module from Python3 +# http://bugs.python.org/issue21308 +Patch214: 00214-pep466-backport-py3-ssl-changes.patch +# 00215 # +# OpenSSL disabled various ciphers and protocols +# we have to reflect it in tests +Patch215: 00215-pep466-reflect-openssl-settings-ssltests.patch +# 00216 # +# fix load_verify_locations on unicode paths +# http://bugs.python.org/issue22244 +Patch216: 00216-pep466-fix-load-verify-locs-unicode.patch +# 00217 # +# backport hashlib changes +# http://bugs.python.org/issue21307 +Patch217: 00217-pep466-backport-hashlib-algorithm-consts.patch +# 00218 # +# update os.urandom +# http://bugs.python.org/issue21305 +Patch218: 00218-pep466-backport-urandom-pers-fd.patch +# 00219 # +# Lib/ssl.py still references _ssl.sslwrap +# http://bugs.python.org/issue22523 +Patch219: 00219-pep466-fix-referenced-sslwrap.patch +# 00220 # +# allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection +Patch220: 00220-pep466-allow-passing-ssl-urrlib-httplib.patch +# 00221 # +# Patch214 remove sslwrap from _ssl.c this so we have to reimplement it +#Patch221: 00221-pep466-backport-sslwrap-c-ssl.patch +# Backporting sslwrap introduces regressions so patch 221 was dropped (rhbz#1331425) +# 00222 # +# test_ssl: fails on recent libressl version with BAD_DH_P_LENGTH +# https://bugs.python.org/issue23844 +Patch222: 00222-add-2014-bit-dh-key.patch +# 00223 # +# PEP 476: verify HTTPS certificates by default +# http://bugs.python.org/issue22417 +# Resolves:rhbz#1219110 +Patch223: 00223-pep476-verify-certs-by-default.patch +# 00224 # +# Add switch to toggle global verification on and off +# Resolves:rhbz#1219108 +# For more information see PEP493 +Patch224: 00224-pep476-add-toggle-for-cert-verify.patch + +# 00225 # +# Add list of choices to sort option of cProfile +# Resolves:rhbz#1237107 +Patch225: 00225-cprofile-sort-option.patch + +# 00227 # +# Make load_cert_chain function of SSLContext accept a +# keyfile argument set to None +# Upstream issue: http://bugs.python.org/issue22787 +# Resolves: rhbz#1250611 +Patch227: 00227-accept-none-keyfile-loadcertchain.patch + +# 00228 # +# Backport SSLSocket.version function +# Resolves: rhbz#1259421 +Patch228: 00228-backport-ssl-version.patch + +# 00229 # +# Adjusted tests to acknowledge lack of SSLv2 support +# Resolves: rhbz#1315310 +Patch229: 00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch + +# 00230 # +# Force all child threads to terminate in TestForkInThread, so no zombie +# processes get left behind with stalled threads which hang Python builds +# https://bugs.python.org/issue26456 +# Resolves: rhbz#1313259 +Patch230: 00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch + +# 00231 # +# Fix hashlib algorithms breaking by initializing OpenSSL_add_all_digests +# function in _hashlib library of _hashopenssl.c module +# Resolves: rhbz#1295459 +Patch231: 00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch + +# 00232 # +# Removal of the '$Date$' placeholder on the python(1) man page footer, +# which does not expand during build +# http://bugs.python.org/issue17167 +# Resolves: rhbz#1268310 +Patch232: 00232-man-page-date-macro-removal.patch + +# 00233 # +# Backport of Computed Goto dispatch +# http://bugs.python.org/issue4753 +# https://lwn.net/Articles/646888/ +# Resolves: rhbz#1289277 +Patch233: 00233-Computed-Goto-dispatch.patch + +# 00234 # +# Updated implementation of PEP493 +# The following features were backported: +# https://www.python.org/dev/peps/pep-0493/#feature-configuration-api +# https://www.python.org/dev/peps/pep-0493/#feature-environment-based-configuration +# Combined usage explained: +# https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports +# Resolves: rhbz#1315758 +# Patch was modified to enable the certificate verification globally as the platform default +# See also patch224 +# Resolves: rhbz#1219110 +Patch234: 00234-PEP493-updated-implementation.patch + +# 0235 # +# JSON decoder lone surrogates fix. +# https://bugs.python.org/issue11489 +# Resolves: rhbz#1301017 +Patch235: 00235-JSON-decoder-lone-surrogates-fix.patch + +# 0236 # +# Fix for iteration over files vith very long lines +# http://bugs.python.org/issue22526 +# Resolves: rhbz#1271760 +Patch236: 00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch + +# 00237 # +# CVE-2016-0772 python: smtplib StartTLS stripping attack +# https://bugzilla.redhat.com/show_bug.cgi?id=1303647 +# FIXED UPSTREAM: https://hg.python.org/cpython/rev/b3ce713fb9be +# Raise an error when STARTTLS fails +# Resolves: rhbz#1346357 +Patch237: 00237-CVE-2016-0772-smtplib.patch + +# 00238 # +# CVE-2016-5699 python: http protocol steam injection attack +# https://bugzilla.redhat.com/show_bug.cgi?id=1303699 +# FIXED UPSTREAM: https://hg.python.org/cpython/rev/1c45047c5102 +# Disabled HTTP header injections in httplib +# Resolves: rhbz#1346357 +Patch238: 00238-CVE-2016-5699-httplib.patch + +# 00240 # +# Increase the timeouts of test_smtplib +# as there are failures on various powerpc architectures. +# FIXED UPSTREAM: https://github.com/python/cpython/commit/1122236c89770466c629aa0f0b0de2b2731b82ee +# Resolves: rhbz#1497795 +Patch240: 00240-increase-smtplib-tests-timeouts.patch + +# 00241 # +# CVE-2016-5636: http://seclists.org/oss-sec/2016/q2/560 +# https://hg.python.org/cpython/rev/985fc64c60d6/ +# https://hg.python.org/cpython/rev/2edbdb79cd6d +# Fix possible integer overflow and heap corruption in zipimporter.get_data() +# FIXED UPSTREAM: https://bugs.python.org/issue26171 +# Resolves: rhbz#1356364 +Patch241: 00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch + +# 00242 # +# HTTPoxy attack (CVE-2016-1000110) +# https://httpoxy.org/ +# FIXED UPSTREAM: http://bugs.python.org/issue27568 +# Based on a patch by Rémi Rampin +# Resolves: rhbz#1359164 +Patch242: 00242-CVE-2016-1000110-httpoxy.patch + +# 00255 # +# Fix Python's failure to decode X.509 certificates +# with a GEN_RID general name in subject alternative names. +# FIXED UPSTREAM: http://bugs.python.org/issue27691 +# Resolves: rhbz#1364444 +Patch255: 00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch + +# 00256 # +# Fix Python's incorrect parsing of certain regular expressions +# FIXED UPSTREAM: http://bugs.python.org/issue18647 +# Resolves: rhbz#1373363 +Patch256: 00256-fix-incorrect-parsing-of-regular-expressions.patch + +# 00257 # +# Python's threading library doesn't use the monotonic clock when handling wait timeouts, +# so when the system clock is set backwards, the wait doesn't return after the timeout, +# causing deadlocks. +# This patch works around the issue. +# Resolves: rhbz#1368076 +# DOWNSTREAM ONLY PATCH +Patch257: 00257-threading-wait-clamp-remaining-time.patch + +# 00263 # +# Fix reference leaks of certfile_bytes and keyfile_bytes at _ssl.c +# FIXED UPSTREAM: http://bugs.python.org/issue27267 +# https://github.com/python/cpython/commit/b3e073cbb3af2999e6e589f55ec2fc8a109fdc14 +# https://github.com/python/cpython/commit/3b91de5a76aad471476f5bc5943e44bf386c0e6d +# Resolves: rhbz#1272562 +Patch263: 00263-fix-ssl-reference-leaks.patch + +# 00265 # +# Protect the key list during fork() in order for the forked process to not inherit an inconsistent key list. +# Reported upstream: http://bugs.python.org/issue29640 +# Resolves: rhbz#1268226 +Patch265: 00265-protect-key-list-during-fork.patch + +# 00266 # +# Make shutil.make_archive() to not ingore empty directories when creating a zip file. +# Also refactor and extend the shutil test suite. +# FIXED UPSTREAM: https://bugs.python.org/issue24982 +# https://github.com/python/cpython/commit/04861dc82f595e3e2f0ab4b1a62de2f812c8fa37 +# Resolves: rhbz#1439734 +Patch266: 00266-fix-shutil.make_archive-ignoring-empty-dirs.patch + +# 00268 # +# Set stream to None in case an _open() fails. +# FIXED UPSTREAM: https://bugs.python.org/issue21742 +# Resolves: rhbz#1432003 +Patch268: 00268-set-stream-name-to-None.patch + +# 00275 # +# Fixe fcntl() with integer argument on 64-bit big-endian platforms. +# FIXED UPSTREAM: https://bugs.python.org/issue22821 +# Resolves: rhbz#1489858 +Patch275: 00275-fix-fnctl-with-integer-on-big-endian.patch + +# 00276 # +# Increase imaplib's MAXLINE to accommodate modern mailbox sizes. +# FIXED UPSTREAM: https://bugs.python.org/issue23647 +# Resolves: rhbz#1485808 +Patch276: 00276-increase-imaplib-MAXLINE.patch + +# 00281 # +# Add context parameter to xmlrpclib.ServerProxy +# FIXED UPSTREAM: https://bugs.python.org/issue22960 +# Resolves: rhbz#1490392 +Patch281: 00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch + +# 00282 # +# Make it more likely for the system allocator to release free()d memory arenas +# - Use mmap for arena allocation +# - Increase SMALL_REQUEST_THRESHOLD so that small dictionaries use +# pre-allocated arena pools +# FIXED UPSTREAM: https://bugs.python.org/issue20494 +# Resolves: rhbz#1468410 +Patch282: 00282-obmalloc-mmap-threshold.patch + +# 00285 # +# Fix nondeterministic read in test_pty which fails randomly in brew. +# FIXED UPSTREAM: https://bugs.python.org/issue31158 +# Resolves: rhbz#1512160 +Patch285: 00285-fix-non-deterministic-read-in-test_pty.patch + +# 00287 # +# On the creation of io.FileIO() and builtin file() objects the GIL is now released +# when checking the file descriptor. io.FileIO.readall(), io.FileIO.read(), and +# file.read() also now release the GIL when getting the file size, which fixes hanging +# of all threads when trying to access an inaccessible NFS server. +# FIXED UPSTREAM: https://bugs.python.org/issue32186 +# Resolves: rhbz#1520068 +Patch287: 00287-fix-thread-hanging-on-inaccessible-nfs-server.patch + +# 00295 # +# Fix http.client.HTTPConnection tunneling and HTTPConnection.set_tunnel with default port, +# which was breaking https connections behind a proxy. +# FIXED UPSTREAM: https://bugs.python.org/issue7776 +# https://bugs.python.org/issue22095 +# https://bugs.python.org/issue23300 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1483438 +Patch295: 00295-fix-https-behind-proxy.patch + +# 00296 # +# Re-add the private `_set_hostport` api to httplib +# DOWNSTREAM ONLY: backwards compatibility backport +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1546351 +Patch296: 00296-Readd-the-private-_set_hostport-api-to-httplib.patch + +# 00298 # +# The SSL module no longer sends IP addresses in SNI TLS extension on +# platforms with OpenSSL 1.0.2+ or inet_pton. +# FIXED UPSTREAM: https://bugs.python.org/issue32185 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1555314 +Patch298: 00298-do-not-send-IP-in-SNI-TLS-extension.patch + +# 00299 # +# Fix ssl module, Python 2.7 doesn't have Py_MAX +# The previous patch 298 broke python2. This is a fixup. +# FIXED UPSTREAM: https://github.com/python/cpython/pull/5878 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1555314 +Patch299: 00299-fix-ssl-module-pymax.patch + +# 00303 # +# Fix CVE-2018-1060 and CVE-2018-1061 +# FIXED UPSTREAM: https://bugs.python.org/issue32981 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1563454 +# and https://bugzilla.redhat.com/show_bug.cgi?id=1549192 +Patch303: 00303-CVE-2018-1060-1.patch + +# 00305 # +# Remove 3DES from the cipher list to mitigate CVE-2016-2183 (sweet32). +# FIXED UPSTREAM: https://bugs.python.org/issue27850 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1581901 +Patch305: 00305-CVE-2016-2183.patch + +# 00306 # +# Fix OSERROR 17 due to _multiprocessing/semaphore.c +# assuming a one-to-one Pid -> process mapping +# FIXED UPSTREAM: https://bugs.python.org/issue24303 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1579432 +Patch306: 00306-fix-oserror-17-upon-semaphores-creation.patch + +# (New patches go here ^^^) +# +# When adding new patches to "python" and "python3" in Fedora 17 onwards, +# please try to keep the patch numbers in-sync between the two specfiles: +# +# - use the same patch number across both specfiles for conceptually-equivalent +# fixes, ideally with the same name +# +# - when a patch is relevant to both specfiles, use the same introductory +# comment in both specfiles where possible (to improve "diff" output when +# comparing them) +# +# - when a patch is only relevant for one of the two specfiles, leave a gap +# in the patch numbering in the other specfile, adding a comment when +# omitting a patch, both in the manifest section here, and in the "prep" +# phase below +# +# Hopefully this will make it easier to ensure that all relevant fixes are +# applied to both versions. + +# This is the generated patch to "configure"; see the description of +# %%{regenerate_autotooling_patch} +# above: +Patch5000: 05000-autotool-intermediates.patch + +# ====================================================== +# Additional metadata, and subpackages +# ====================================================== + +%if %{main_python} +Obsoletes: Distutils +Provides: Distutils +Provides: python2 = %{version} +Obsoletes: python-elementtree <= 1.2.6 +Obsoletes: python-sqlite < 2.3.2 +Provides: python-sqlite = 2.3.2 +Obsoletes: python-ctypes < 1.0.1 +Provides: python-ctypes = 1.0.1 +Obsoletes: python-hashlib < 20081120 +Provides: python-hashlib = 20081120 +Obsoletes: python-uuid < 1.31 +Provides: python-uuid = 1.31 + +# python-sqlite2-2.3.5-5.fc18 was retired. Obsolete the old package here +# so it gets uninstalled on updates +%if 0%{?fedora} >= 17 +Obsoletes: python-sqlite2 <= 2.3.5-6 +%endif + +# python-argparse is part of python as of version 2.7 +# drop this Provides in F17 +# (having Obsoletes here caused problems with multilib; see rhbz#667984) +Provides: python-argparse = %{version}-%{release} +%endif + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +URL: http://www.python.org/ + +%description +Python is an interpreted, interactive, object-oriented programming +language often compared to Tcl, Perl, Scheme or Java. Python includes +modules, classes, exceptions, very high level dynamic data types and +dynamic typing. Python supports interfaces to many system calls and +libraries, as well as to various windowing systems (X11, Motif, Tk, +Mac and MFC). + +Programmers can write new built-in modules for Python in C or C++. +Python can be used as an extension language for applications that need +a programmable interface. + +Note that documentation for Python is provided in the python-docs +package. + +This package provides the "python" executable; most of the actual +implementation is within the "python-libs" package. + +%package libs +Summary: Runtime libraries for Python +Group: Applications/System + +# New behaviour of httplib (patch 295) doesn't play well with really old pip +# version (1.4.1) bundled in the old virtualenv package. This new version of +# virtualenv updated bundled pip to 9.0.1 which works fine. +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1483438 +Conflicts: python-virtualenv < 15.1.0-1 + +# Needed for ctypes, to load libraries, worked around for Live CDs size +# Requires: binutils + +# expat 2.1.0 added the symbol XML_SetHashSalt without bumping SONAME. We use +# this symbol (in pyexpat), so we must explicitly state this dependency to +# prevent "import pyexpat" from failing with a linker error if someone hasn't +# yet upgraded expat: +Requires: expat >= 2.1.0 + +Provides: python2-libs = %{version}-%{release} +Provides: python2-libs%{?_isa} = %{version}-%{release} + +%description libs +This package contains runtime libraries for use by Python: +- the libpython dynamic library, for use by applications that embed Python as +a scripting language, and by the main "python" executable +- the Python standard library + +%package devel +Summary: The libraries and header files needed for Python development +Group: Development/Libraries +Requires: %{python}%{?_isa} = %{version}-%{release} +Requires: pkgconfig +# Needed here because of the migration of Makefile from -devel to the main +# package +Conflicts: %{python} < %{version}-%{release} +%if %{main_python} +Obsoletes: python2-devel +Provides: python2-devel = %{version}-%{release} +%endif + +%description devel +The Python programming language's interpreter can be extended with +dynamically loaded extensions and can be embedded in other programs. +This package contains the header files and libraries needed to do +these types of tasks. + +Install python-devel if you want to develop Python extensions. The +python package will also need to be installed. You'll probably also +want to install the python-docs package, which contains Python +documentation. + +%package tools +Summary: A collection of development tools included with Python +Group: Development/Tools +Requires: %{name} = %{version}-%{release} +Requires: %{tkinter} = %{version}-%{release} +%if %{main_python} +Obsoletes: python2-tools +Provides: python2-tools = %{version} +%endif + +%description tools +This package includes several tools to help with the development of Python +programs, including IDLE (an IDE with editing and debugging facilities), a +color editor (pynche), and a python gettext program (pygettext.py). + +%package -n %{tkinter} +Summary: A graphical user interface for the Python scripting language +Group: Development/Languages +Requires: %{name} = %{version}-%{release} +%if %{main_python} +Obsoletes: tkinter2 +Provides: tkinter2 = %{version} +%endif + +%description -n %{tkinter} + +The Tkinter (Tk interface) program is an graphical user interface for +the Python scripting language. + +You should install the tkinter package if you'd like to use a graphical +user interface for Python programming. + +%package test +Summary: The test modules from the main python package +Group: Development/Languages +Requires: %{name} = %{version}-%{release} + +%description test + +The test modules from the main python package: %{name} +These have been removed to save space, as they are never or almost +never used in production. + +You might want to install the python-test package if you're developing python +code that uses more than just unittest and/or test_support.py. + +%if 0%{?with_debug_build} +%package debug +Summary: Debug version of the Python runtime +Group: Applications/System + +# The debug build is an all-in-one package version of the regular build, and +# shares the same .py/.pyc files and directories as the regular build. Hence +# we depend on all of the subpackages of the regular build: +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-devel%{?_isa} = %{version}-%{release} +Requires: %{name}-test%{?_isa} = %{version}-%{release} +Requires: tkinter%{?_isa} = %{version}-%{release} +Requires: %{name}-tools%{?_isa} = %{version}-%{release} + +%description debug +python-debug provides a version of the Python runtime with numerous debugging +features enabled, aimed at advanced Python users, such as developers of Python +extension modules. + +This version uses more memory and will be slower than the regular Python build, +but is useful for tracking down reference-counting issues, and other bugs. + +The bytecodes are unchanged, so that .pyc files are compatible between the two +version of Python, but the debugging features mean that C/C++ extension modules +are ABI-incompatible with those built for the standard runtime. + +It shares installation directories with the standard Python runtime, so that +.py and .pyc files can be shared. All compiled extension modules gain a "_d" +suffix ("foo_d.so" rather than "foo.so") so that each Python implementation can +load its own extensions. +%endif # with_debug_build + + +# ====================================================== +# The prep phase of the build: +# ====================================================== + +%prep +%setup -q -n Python-%{version} + +%if 0%{?with_systemtap} +# Provide an example of usage of the tapset: +cp -a %{SOURCE4} . +cp -a %{SOURCE5} . +%endif # with_systemtap + +# Ensure that we're using the system copy of various libraries, rather than +# copies shipped by upstream in the tarball: +# Remove embedded copy of expat: +rm -r Modules/expat || exit 1 + +# Remove embedded copy of libffi: +for SUBDIR in darwin libffi libffi_arm_wince libffi_msvc libffi_osx ; do + rm -r Modules/_ctypes/$SUBDIR || exit 1 ; +done + +# Remove embedded copy of zlib: +rm -r Modules/zlib || exit 1 + +# Don't build upstream Python's implementation of these crypto algorithms; +# instead rely on _hashlib and OpenSSL. +# +# For example, in our builds md5.py uses always uses hashlib.md5 (rather than +# falling back to _md5 when hashlib.md5 is not available); hashlib.md5 is +# implemented within _hashlib via OpenSSL (and thus respects FIPS mode) +for f in md5module.c md5.c shamodule.c sha256module.c sha512module.c; do + rm Modules/$f +done + +# +# Apply patches: +# +%patch0 -p1 -b .rhconfig +%patch1 -p1 -b .no_gui +%patch4 -p1 -b .cflags +%patch6 -p1 -b .plural +%patch7 -p1 + +# Try not disabling egg-infos, bz#414711 +#patch50 -p1 -b .egginfo + +# patch101: upstream as of Python 2.7.4 +%if "%{_lib}" == "lib64" +%patch102 -p1 -b .lib64 +%patch103 -p1 -b .lib64-sysconfig +%patch104 -p1 +%endif + +%patch10 -p1 -b .binutils-no-dep +# patch11: upstream as of Python 2.7.3 +%patch13 -p1 -b .socketmodule +%patch14 -p1 -b .socketmodule2 +%patch16 -p1 -b .rpath +%patch17 -p1 -b .distutils-rpath + +%if 0%{?with_systemtap} +%patch55 -p1 -b .systemtap +%endif + +%patch111 -p1 -b .no-static-lib + +%patch112 -p1 -b .debug-build + +%patch113 -p1 -b .more-configuration-flags + +%patch114 -p1 -b .statvfs-f-flag-constants + +# patch115: upstream as of Python 2.7.3 + +%patch121 -p1 +%patch125 -p1 -b .less-verbose-COUNT_ALLOCS +# 00126: upstream as of Python 2.7.5 +# 00127: upstream as of Python 2.7.5 +%patch128 -p1 + +%patch130 -p1 + +%ifarch ppc %{power64} +%patch131 -p1 +%endif + +%patch132 -p1 +%patch133 -p1 +%patch134 -p1 +%patch135 -p1 +%patch136 -p1 +%patch137 -p1 +%patch138 -p1 +%ifarch %{arm} +%patch139 -p1 +%endif +%ifarch %{sparc} +%patch140 -p1 +%endif +%patch141 -p1 +%patch142 -p1 +%patch143 -p1 -b .tsc-on-ppc +%if !%{with_gdbm} +%patch144 -p1 +%endif +# 00145: upstream as of Python 2.7.3 +%patch146 -p1 +%patch147 -p1 +# 00148: upstream as of Python 2.7.3 +# 00149: not for python 2 +# 00150: not for python 2 +# 00151: upstream as of Python 2.7.3 +# 00152: not for python 2 +%patch153 -p0 +# 00154: not for python 2 +%patch155 -p1 +%patch156 -p1 +%patch157 -p1 +# 00158: upstream as of Python 2.7.4 +# 00160: not for python 2 +# 00161: not for python 2 yet +# 00162: not for python 2 yet +# 00163: not for python 2 yet +# 00164: not for python 2 yet +%patch165 -p1 +mv Modules/cryptmodule.c Modules/_cryptmodule.c +%patch166 -p1 +%patch167 -p1 +%patch168 -p1 +%patch169 -p1 +%patch170 -p1 +# 00171: upstream as of Python 2.7.4 +# 00171: upstream as of Python 2.7.4 +%patch173 -p1 +%patch174 -p1 -b .fix-for-usr-move +# 00175: upstream as of Python 2.7.5 +# 00176: not for python 2 +# 00177: not for python 2 +# 00178: not for python 2 +# 00179: not for python 2 +%patch180 -p1 +%patch181 -p1 +# 00182: not for python2 +# 00183: not for python2 +%patch184 -p1 +%patch185 -p1 +%patch186 -p1 +%patch187 -p1 +%patch188 -p1 +%patch189 -p1 +%patch190 -p0 +%patch191 -p1 +%patch192 -p1 +%patch193 -p1 +%patch194 -p0 +%patch195 -p1 +%patch196 -p1 +%patch197 -p1 +%patch198 -p1 +%patch199 -p1 +%patch200 -p1 +%patch201 -p1 +%patch202 -p1 +%patch203 -p1 +%patch204 -p1 +%patch205 -p1 +%patch206 -p1 +%patch207 -p1 +%patch208 -p1 +%patch209 -p1 +%patch210 -p1 +%patch211 -p1 +%patch212 -p1 +%patch213 -p1 +%patch214 -p1 +%patch215 -p1 +%patch216 -p1 +%patch217 -p1 +%patch218 -p1 +%patch219 -p1 +%patch220 -p1 +# 00221: Dropped because of regressions +%patch222 -p1 +%patch223 -p1 +%patch224 -p1 +%patch225 -p1 +%patch227 -p1 +%patch228 -p1 +%patch229 -p1 +%patch230 -p1 +%patch231 -p1 +%patch232 -p1 +%patch233 -p1 +%patch234 -p1 +%patch235 -p1 +%patch236 -p1 +%patch237 -p1 +%patch238 -p1 +%patch240 -p1 +%patch241 -p1 +%patch242 -p1 +%patch255 -p1 +%patch256 -p1 +%patch257 -p1 +%patch263 -p1 +%patch265 -p1 +%patch266 -p1 +%patch268 -p1 +%patch275 -p1 +%patch276 -p1 +%patch281 -p1 +%patch282 -p1 +%patch285 -p1 +%patch287 -p1 +%patch295 -p1 +%patch296 -p1 +%patch298 -p1 +%patch299 -p1 +%patch303 -p1 +%patch305 -p1 +%patch306 -p1 + + +# This shouldn't be necesarry, but is right now (2.2a3) +find -name "*~" |xargs rm -f + +%if ! 0%{regenerate_autotooling_patch} +# Normally we apply the patch to "configure" +# We don't apply the patch if we're working towards regenerating it +%patch5000 -p0 -b .autotool-intermediates +%endif + + +# ====================================================== +# Configuring and building the code: +# ====================================================== + +%build +topdir=$(pwd) +export CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE -fPIC -fwrapv" +export CXXFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE -fPIC -fwrapv" +export CPPFLAGS="$(pkg-config --cflags-only-I libffi)" +export OPT="$RPM_OPT_FLAGS -D_GNU_SOURCE -fPIC -fwrapv" +export LINKCC="gcc" +export LDFLAGS="$RPM_LD_FLAGS" +if pkg-config openssl ; then + export CFLAGS="$CFLAGS $(pkg-config --cflags openssl)" + export LDFLAGS="$LDFLAGS $(pkg-config --libs-only-L openssl)" +fi +# compile with -O3 for ppc64 as requested in +# https://bugzilla.redhat.com/show_bug.cgi?id=1051076 +%ifarch %{power64} +export CFLAGS="$CFLAGS -O3" +export CXXFLAGS="$CXXFLAGS -O3" +export OPT="$OPT -O3" +%endif +# Force CC +export CC=gcc + +%if 0%{regenerate_autotooling_patch} +# If enabled, this code regenerates the patch to "configure", using a +# local copy of autoconf-2.65, then exits the build +# +# The following assumes that the copy is installed to ~/autoconf-2.65/bin +# as per these instructions: +# http://bugs.python.org/issue7997 + +for f in pyconfig.h.in configure ; do + cp $f $f.autotool-intermediates ; +done + +# Rerun the autotools: +PATH=~/autoconf-2.65/bin:$PATH autoconf +autoheader + +# Regenerate the patch: +gendiff . .autotool-intermediates > %{PATCH5000} + + +# Exit the build +exit 1 +%endif + +# Define a function, for how to perform a "build" of python for a given +# configuration: +BuildPython() { + ConfName=$1 + BinaryName=$2 + SymlinkName=$3 + ExtraConfigArgs=$4 + PathFixWithThisBinary=$5 + + ConfDir=build/$ConfName + + echo STARTING: BUILD OF PYTHON FOR CONFIGURATION: $ConfName - %{_bindir}/$BinaryName + mkdir -p $ConfDir + + pushd $ConfDir + + # Use the freshly created "configure" script, but in the directory two above: + %global _configure $topdir/configure + +%configure \ + --enable-ipv6 \ + --enable-shared \ + --enable-unicode=%{unicode} \ + --with-dbmliborder=gdbm:ndbm:bdb \ + --with-system-expat \ + --with-system-ffi \ +%if 0%{?with_systemtap} + --with-dtrace \ + --with-tapset-install-dir=%{tapsetdir} \ +%endif +%if 0%{?with_valgrind} + --with-valgrind \ +%endif + $ExtraConfigArgs \ + %{nil} + +make EXTRA_CFLAGS="$CFLAGS" %{?_smp_mflags} + +# We need to fix shebang lines across the full source tree. +# +# We do this using the pathfix.py script, which requires one of the +# freshly-built Python binaries. +# +# We use the optimized python binary, and make the shebangs point at that same +# optimized python binary: +if $PathFixWithThisBinary +then + LD_LIBRARY_PATH="$topdir/$ConfDir" ./$BinaryName \ + $topdir/Tools/scripts/pathfix.py \ + -i "%{_bindir}/env $BinaryName" \ + $topdir +fi + +# Rebuild with new python +# We need a link to a versioned python in the build directory +ln -s $BinaryName $SymlinkName +LD_LIBRARY_PATH="$topdir/$ConfDir" PATH=$PATH:$topdir/$ConfDir make -s EXTRA_CFLAGS="$CFLAGS" %{?_smp_mflags} + + popd + echo FINISHED: BUILD OF PYTHON FOR CONFIGURATION: $ConfDir +} + +# Use "BuildPython" to support building with different configurations: + +%if 0%{?with_debug_build} +BuildPython debug \ + python-debug \ + python%{pybasever}-debug \ +%ifarch %{ix86} x86_64 ppc %{power64} + "--with-pydebug --with-tsc --with-count-allocs --with-call-profile" \ +%else + "--with-pydebug --with-count-allocs --with-call-profile" \ +%endif + false +%endif # with_debug_build + +BuildPython optimized \ + python \ + python%{pybasever} \ + "" \ + true + + +# ====================================================== +# Installing the built code: +# ====================================================== + +%install +topdir=$(pwd) +rm -rf %{buildroot} +mkdir -p %{buildroot}%{_prefix} %{buildroot}%{_mandir} + +# Clean up patched .py files that are saved as .lib64 +for f in distutils/command/install distutils/sysconfig; do + rm -f Lib/$f.py.lib64 +done + +InstallPython() { + + ConfName=$1 + BinaryName=$2 + PyInstSoName=$3 + + ConfDir=build/$ConfName + + echo STARTING: INSTALL OF PYTHON FOR CONFIGURATION: $ConfName - %{_bindir}/$BinaryName + mkdir -p $ConfDir + + pushd $ConfDir + +make install DESTDIR=%{buildroot} + +# We install a collection of hooks for gdb that make it easier to debug +# executables linked against libpython (such as /usr/lib/python itself) +# +# These hooks are implemented in Python itself +# +# gdb-archer looks for them in the same path as the ELF file, with a -gdb.py suffix. +# We put them in the debuginfo package by installing them to e.g.: +# /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py +# (note that the debug path is /usr/lib/debug for both 32/64 bit) +# +# See https://fedoraproject.org/wiki/Features/EasierPythonDebugging for more +# information +# +# Initially I tried: +# /usr/lib/libpython2.6.so.1.0-gdb.py +# but doing so generated noise when ldconfig was rerun (rhbz:562980) +# + +%if 0%{?with_gdb_hooks} +DirHoldingGdbPy=%{_prefix}/lib/debug/%{_libdir} +PathOfGdbPy=$DirHoldingGdbPy/$PyInstSoName.debug-gdb.py + +mkdir -p %{buildroot}$DirHoldingGdbPy +cp $topdir/Tools/gdb/libpython.py %{buildroot}$PathOfGdbPy + +# Manually byte-compile the file, in case find-debuginfo.sh is run before +# brp-python-bytecompile, so that the .pyc/.pyo files are properly listed in +# the debuginfo manifest: +LD_LIBRARY_PATH="$topdir/$ConfDir" $topdir/$ConfDir/$BinaryName \ + -c "import compileall; import sys; compileall.compile_dir('%{buildroot}$DirHoldingGdbPy', ddir='$DirHoldingGdbPy')" + +LD_LIBRARY_PATH="$topdir/$ConfDir" $topdir/$ConfDir/$BinaryName -O \ + -c "import compileall; import sys; compileall.compile_dir('%{buildroot}$DirHoldingGdbPy', ddir='$DirHoldingGdbPy')" +%endif # with_gdb_hooks + + popd + + echo FINISHED: INSTALL OF PYTHON FOR CONFIGURATION: $ConfName +} + +# Use "InstallPython" to support building with different configurations: + +# Install the "debug" build first, so that we can move some files aside +%if 0%{?with_debug_build} +InstallPython debug \ + python%{pybasever}-debug \ + %{py_INSTSONAME_debug} +%endif # with_debug_build + +# Now the optimized build: +InstallPython optimized \ + python%{pybasever} \ + %{py_INSTSONAME_optimized} + + +# Fix the interpreter path in binaries installed by distutils +# (which changes them by itself) +# Make sure we preserve the file permissions +for fixed in %{buildroot}%{_bindir}/pydoc; do + sed 's,#!.*/python$,#!%{_bindir}/env python%{pybasever},' $fixed > $fixed- \ + && cat $fixed- > $fixed && rm -f $fixed- +done + +# Junk, no point in putting in -test sub-pkg +rm -f %{buildroot}/%{pylibdir}/idlelib/testcode.py* + +# don't include tests that are run at build time in the package +# This is documented, and used: rhbz#387401 +if /bin/false; then + # Move this to -test subpackage. +mkdir save_bits_of_test +for i in test_support.py __init__.py; do + cp -a %{buildroot}/%{pylibdir}/test/$i save_bits_of_test +done +rm -rf %{buildroot}/%{pylibdir}/test +mkdir %{buildroot}/%{pylibdir}/test +cp -a save_bits_of_test/* %{buildroot}/%{pylibdir}/test +fi + +%if %{main_python} +%else +mv %{buildroot}%{_bindir}/python %{buildroot}%{_bindir}/%{python} +%if 0%{?with_debug_build} +mv %{buildroot}%{_bindir}/python-debug %{buildroot}%{_bindir}/%{python}-debug +%endif # with_debug_build +mv %{buildroot}/%{_mandir}/man1/python.1 %{buildroot}/%{_mandir}/man1/python%{pybasever}.1 +%endif + +# tools + +mkdir -p ${RPM_BUILD_ROOT}%{site_packages} + +#pynche +install -p -m755 %{SOURCE7} ${RPM_BUILD_ROOT}%{_bindir}/pynche +chmod 755 ${RPM_BUILD_ROOT}%{_bindir}/pynche +rm -f Tools/pynche/*.pyw +cp -rp Tools/pynche \ + ${RPM_BUILD_ROOT}%{site_packages}/ + +mv Tools/pynche/README Tools/pynche/README.pynche + +#gettext +install -m755 Tools/i18n/pygettext.py %{buildroot}%{_bindir}/ +install -m755 Tools/i18n/msgfmt.py %{buildroot}%{_bindir}/ + +# Useful development tools +install -m755 -d %{buildroot}%{tools_dir}/scripts +install Tools/README %{buildroot}%{tools_dir}/ +install Tools/scripts/*py %{buildroot}%{tools_dir}/scripts/ + +# Documentation tools +install -m755 -d %{buildroot}%{doc_tools_dir} +#install -m755 Doc/tools/mkhowto %{buildroot}%{doc_tools_dir} + +# Useful demo scripts +install -m755 -d %{buildroot}%{demo_dir} +cp -ar Demo/* %{buildroot}%{demo_dir} + +# Get rid of crap +find %{buildroot}/ -name "*~"|xargs rm -f +find %{buildroot}/ -name ".cvsignore"|xargs rm -f +find %{buildroot}/ -name "*.bat"|xargs rm -f +find . -name "*~"|xargs rm -f +find . -name ".cvsignore"|xargs rm -f +#zero length +rm -f %{buildroot}%{pylibdir}/LICENSE.txt + + +#make the binaries install side by side with the main python +%if !%{main_python} +pushd %{buildroot}%{_bindir} +mv idle idle%{__python_ver} +mv pynche pynche%{__python_ver} +mv pygettext.py pygettext%{__python_ver}.py +mv msgfmt.py msgfmt%{__python_ver}.py +mv smtpd.py smtpd%{__python_ver}.py +mv pydoc pydoc%{__python_ver} +popd +%endif + +# Fix for bug #136654 +rm -f %{buildroot}%{pylibdir}/email/test/data/audiotest.au %{buildroot}%{pylibdir}/test/audiotest.au + +# Fix bug #143667: python should own /usr/lib/python2.x on 64-bit machines +%if "%{_lib}" == "lib64" +install -d %{buildroot}/usr/lib/python%{pybasever}/site-packages +%endif + +# Make python-devel multilib-ready (bug #192747, #139911) +%global _pyconfig32_h pyconfig-32.h +%global _pyconfig64_h pyconfig-64.h + +%ifarch %{power64} s390x x86_64 ia64 alpha sparc64 aarch64 +%global _pyconfig_h %{_pyconfig64_h} +%else +%global _pyconfig_h %{_pyconfig32_h} +%endif + +%if 0%{?with_debug_build} +%global PyIncludeDirs python%{pybasever} python%{pybasever}-debug +%else +%global PyIncludeDirs python%{pybasever} +%endif + +for PyIncludeDir in %{PyIncludeDirs} ; do + mv %{buildroot}%{_includedir}/$PyIncludeDir/pyconfig.h \ + %{buildroot}%{_includedir}/$PyIncludeDir/%{_pyconfig_h} + cat > %{buildroot}%{_includedir}/$PyIncludeDir/pyconfig.h << EOF +#include + +#if __WORDSIZE == 32 +#include "%{_pyconfig32_h}" +#elif __WORDSIZE == 64 +#include "%{_pyconfig64_h}" +#else +#error "Unknown word size" +#endif +EOF +done +ln -s ../../libpython%{pybasever}.so %{buildroot}%{pylibdir}/config/libpython%{pybasever}.so + +# Fix for bug 201434: make sure distutils looks at the right pyconfig.h file +# Similar for sysconfig: sysconfig.get_config_h_filename tries to locate +# pyconfig.h so it can be parsed, and needs to do this at runtime in site.py +# when python starts up. +# +# Split this out so it goes directly to the pyconfig-32.h/pyconfig-64.h +# variants: +sed -i -e "s/'pyconfig.h'/'%{_pyconfig_h}'/" \ + %{buildroot}%{pylibdir}/distutils/sysconfig.py \ + %{buildroot}%{pylibdir}/sysconfig.py + +# Install macros for rpm: +mkdir -p %{buildroot}/%{_sysconfdir}/rpm +install -m 644 %{SOURCE6} %{buildroot}/%{_sysconfdir}/rpm +install -m 644 %{SOURCE10} %{buildroot}/%{_sysconfdir}/rpm + +# Make python folder for config files under /etc +mkdir -p %{buildroot}/%{_sysconfdir}/python +install -m 644 %{SOURCE8} %{buildroot}/%{_sysconfdir}/python + +# Ensure that the curses module was linked against libncursesw.so, rather than +# libncurses.so (bug 539917) +ldd %{buildroot}/%{dynload_dir}/_curses*.so \ + | grep curses \ + | grep libncurses.so && (echo "_curses.so linked against libncurses.so" ; exit 1) + +# Ensure that the debug modules are linked against the debug libpython, and +# likewise for the optimized modules and libpython: +for Module in %{buildroot}/%{dynload_dir}/*.so ; do + case $Module in + *_d.so) + ldd $Module | grep %{py_INSTSONAME_optimized} && + (echo Debug module $Module linked against optimized %{py_INSTSONAME_optimized} ; exit 1) + + ;; + *) + ldd $Module | grep %{py_INSTSONAME_debug} && + (echo Optimized module $Module linked against debug %{py_INSTSONAME_optimized} ; exit 1) + ;; + esac +done + +# +# Systemtap hooks: +# +%if 0%{?with_systemtap} +# Install a tapset for this libpython into tapsetdir, fixing up the path to the +# library: +mkdir -p %{buildroot}%{tapsetdir} +%ifarch %{power64} s390x x86_64 ia64 alpha sparc64 aarch64 +%global libpython_stp_optimized libpython%{pybasever}-64.stp +%global libpython_stp_debug libpython%{pybasever}-debug-64.stp +%else +%global libpython_stp_optimized libpython%{pybasever}-32.stp +%global libpython_stp_debug libpython%{pybasever}-debug-32.stp +%endif + +sed \ + -e "s|LIBRARY_PATH|%{_libdir}/%{py_INSTSONAME_optimized}|" \ + %{SOURCE3} \ + > %{buildroot}%{tapsetdir}/%{libpython_stp_optimized} + +%if 0%{?with_debug_build} +sed \ + -e "s|LIBRARY_PATH|%{_libdir}/%{py_INSTSONAME_debug}|" \ + %{SOURCE3} \ + > %{buildroot}%{tapsetdir}/%{libpython_stp_debug} +%endif # with_debug_build +%endif # with_systemtap + +# Replace scripts shebangs in usr/bin of subpackage tools +#(rhbz#987038) +sed -i "s|^#\!.\?/usr/bin.*$|#\! %{__python}|" \ + %{buildroot}%{_bindir}/pygettext.py \ + %{buildroot}%{_bindir}/msgfmt.py \ + %{buildroot}%{_bindir}/smtpd.py \ + %{buildroot}%{demo_dir}/scripts/find-uname.py \ + %{buildroot}%{demo_dir}/pdist/rcvs \ + %{buildroot}%{demo_dir}/pdist/rcsbump \ + %{buildroot}%{demo_dir}/pdist/rrcs \ + %{buildroot}%{site_packages}/pynche/pynche + +# Make library-files user writable +# rhbz#1046276 +/usr/bin/chmod 755 %{buildroot}%{dynload_dir}/*.so +/usr/bin/chmod 755 %{buildroot}%{_libdir}/libpython%{pybasever}.so.1.0 +%if 0%{?with_debug_build} +/usr/bin/chmod 755 %{buildroot}%{_libdir}/libpython%{pybasever}_d.so.1.0 +%endif # with_debug_build + +mkdir %{buildroot}%{_tmpfilesdir} +cp %{SOURCE9} %{buildroot}%{_tmpfilesdir}/python.conf + +# Create the platform-python symlink pointing to usr/bin/python2.7 +mkdir -p %{buildroot}%{_libexecdir} +ln -s %{_bindir}/python%{pybasever} %{buildroot}%{_libexecdir}/platform-python + +# ====================================================== +# Running the upstream test suite +# ====================================================== + +%check +topdir=$(pwd) +CheckPython() { + ConfName=$1 + BinaryName=$2 + ConfDir=$(pwd)/build/$ConfName + + echo STARTING: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName + + # Note that we're running the tests using the version of the code in the + # builddir, not in the buildroot. + + pushd $ConfDir + + EXTRATESTOPTS="--verbose" + # skipping test_gdb on ppc64le until rhbz1260558 gets resolved + %ifarch ppc64le + EXTRATESTOPTS="$EXTRATESTOPTS -x test_gdb " + %endif + + +%if 0%{?with_huntrleaks} + # Try to detect reference leaks on debug builds. By default this means + # running every test 10 times (6 to stabilize, then 4 to watch): + if [ "$ConfName" = "debug" ] ; then + EXTRATESTOPTS="$EXTRATESTOPTS --huntrleaks : " + fi +%endif + + # Run the upstream test suite, setting "WITHIN_PYTHON_RPM_BUILD" so that the + # our non-standard decorators take effect on the relevant tests: + # @unittest._skipInRpmBuild(reason) + # @unittest._expectedFailureInRpmBuild + WITHIN_PYTHON_RPM_BUILD= EXTRATESTOPTS="$EXTRATESTOPTS" make test + + popd + + echo FINISHED: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName + +} + +%if 0%{run_selftest_suite} + +# Check each of the configurations: +%if 0%{?with_debug_build} +CheckPython \ + debug \ + python%{pybasever}-debug +%endif # with_debug_build +CheckPython \ + optimized \ + python%{pybasever} + +%endif # run_selftest_suite + + +# ====================================================== +# Cleaning up +# ====================================================== + +%clean +rm -fr %{buildroot} + + +# ====================================================== +# Scriptlets +# ====================================================== + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + + + +%files +%defattr(-, root, root, -) +%doc LICENSE README +%{_bindir}/pydoc* +%{_bindir}/%{python} +%if %{main_python} +%{_bindir}/python2 +%endif +%{_bindir}/python%{pybasever} + +%{_libexecdir}/platform-python + +%{_mandir}/*/* + +%files libs +%defattr(-,root,root,-) +%doc LICENSE README +%dir %{pylibdir} +%dir %{dynload_dir} +%dir %{_sysconfdir}/python +%{_tmpfilesdir}/python.conf +%config(noreplace) %{_sysconfdir}/python/cert-verification.cfg +%{dynload_dir}/Python-%{version}-py%{pybasever}.egg-info +%{dynload_dir}/_bisectmodule.so +%{dynload_dir}/_bsddb.so +%{dynload_dir}/_codecs_cn.so +%{dynload_dir}/_codecs_hk.so +%{dynload_dir}/_codecs_iso2022.so +%{dynload_dir}/_codecs_jp.so +%{dynload_dir}/_codecs_kr.so +%{dynload_dir}/_codecs_tw.so +%{dynload_dir}/_collectionsmodule.so +%{dynload_dir}/_csv.so +%{dynload_dir}/_ctypes.so +%{dynload_dir}/_curses.so +%{dynload_dir}/_curses_panel.so +%{dynload_dir}/_elementtree.so +%{dynload_dir}/_functoolsmodule.so +%{dynload_dir}/_hashlib.so +%{dynload_dir}/_heapq.so +%{dynload_dir}/_hotshot.so +%{dynload_dir}/_io.so +%{dynload_dir}/_json.so +%{dynload_dir}/_localemodule.so +%{dynload_dir}/_lsprof.so +%{dynload_dir}/_multibytecodecmodule.so +%{dynload_dir}/_multiprocessing.so +%{dynload_dir}/_randommodule.so +%{dynload_dir}/_socketmodule.so +%{dynload_dir}/_sqlite3.so +%{dynload_dir}/_ssl.so +%{dynload_dir}/_struct.so +%{dynload_dir}/arraymodule.so +%{dynload_dir}/audioop.so +%{dynload_dir}/binascii.so +%{dynload_dir}/bz2.so +%{dynload_dir}/cPickle.so +%{dynload_dir}/cStringIO.so +%{dynload_dir}/cmathmodule.so +%{dynload_dir}/_cryptmodule.so +%{dynload_dir}/datetime.so +%{dynload_dir}/dbm.so +%{dynload_dir}/dlmodule.so +%{dynload_dir}/fcntlmodule.so +%{dynload_dir}/future_builtins.so +%if %{with_gdbm} +%{dynload_dir}/gdbmmodule.so +%endif +%{dynload_dir}/grpmodule.so +%{dynload_dir}/imageop.so +%{dynload_dir}/itertoolsmodule.so +%{dynload_dir}/linuxaudiodev.so +%{dynload_dir}/math.so +%{dynload_dir}/mmapmodule.so +%{dynload_dir}/nismodule.so +%{dynload_dir}/operator.so +%{dynload_dir}/ossaudiodev.so +%{dynload_dir}/parsermodule.so +%{dynload_dir}/pyexpat.so +%{dynload_dir}/readline.so +%{dynload_dir}/resource.so +%{dynload_dir}/selectmodule.so +%{dynload_dir}/spwdmodule.so +%{dynload_dir}/stropmodule.so +%{dynload_dir}/syslog.so +%{dynload_dir}/termios.so +%{dynload_dir}/timemodule.so +%{dynload_dir}/timingmodule.so +%{dynload_dir}/unicodedata.so +%{dynload_dir}/xxsubtype.so +%{dynload_dir}/zlibmodule.so + +%dir %{site_packages} +%{site_packages}/README +%{pylibdir}/*.py* +%{pylibdir}/*.doc +%{pylibdir}/wsgiref.egg-info +%dir %{pylibdir}/bsddb +%{pylibdir}/bsddb/*.py* +%{pylibdir}/compiler +%dir %{pylibdir}/ctypes +%{pylibdir}/ctypes/*.py* +%{pylibdir}/ctypes/macholib +%{pylibdir}/curses +%dir %{pylibdir}/distutils +%{pylibdir}/distutils/*.py* +%{pylibdir}/distutils/README +%{pylibdir}/distutils/command +%exclude %{pylibdir}/distutils/command/wininst-*.exe +%dir %{pylibdir}/email +%{pylibdir}/email/*.py* +%{pylibdir}/email/mime +%{pylibdir}/encodings +%{pylibdir}/hotshot +%{pylibdir}/idlelib +%{pylibdir}/importlib +%dir %{pylibdir}/json +%{pylibdir}/json/*.py* +%{pylibdir}/lib2to3 +%exclude %{pylibdir}/lib2to3/tests +%{pylibdir}/logging +%{pylibdir}/multiprocessing +%{pylibdir}/plat-linux2 +%{pylibdir}/pydoc_data +%dir %{pylibdir}/sqlite3 +%{pylibdir}/sqlite3/*.py* +%dir %{pylibdir}/test +%{pylibdir}/test/test_support.py* +%{pylibdir}/test/__init__.py* +%{pylibdir}/unittest +%{pylibdir}/wsgiref +%{pylibdir}/xml +%if "%{_lib}" == "lib64" +%attr(0755,root,root) %dir %{_prefix}/lib/python%{pybasever} +%attr(0755,root,root) %dir %{_prefix}/lib/python%{pybasever}/site-packages +%endif + +# "Makefile" and the config-32/64.h file are needed by +# distutils/sysconfig.py:_init_posix(), so we include them in the libs +# package, along with their parent directories (bug 531901): +%dir %{pylibdir}/config +%{pylibdir}/config/Makefile +%dir %{_includedir}/python%{pybasever} +%{_includedir}/python%{pybasever}/%{_pyconfig_h} + +%{_libdir}/%{py_INSTSONAME_optimized} +%if 0%{?with_systemtap} +%{tapsetdir}/%{libpython_stp_optimized} +%doc systemtap-example.stp pyfuntop.stp +%endif + +%files devel +%defattr(-,root,root,-) +%{_libdir}/pkgconfig/python-%{pybasever}.pc +%{_libdir}/pkgconfig/python.pc +%{_libdir}/pkgconfig/python2.pc +%{pylibdir}/config/* +%exclude %{pylibdir}/config/Makefile +%{pylibdir}/distutils/command/wininst-*.exe +%{_includedir}/python%{pybasever}/*.h +%exclude %{_includedir}/python%{pybasever}/%{_pyconfig_h} +%doc Misc/README.valgrind Misc/valgrind-python.supp Misc/gdbinit +%if %{main_python} +%{_bindir}/python-config +%{_bindir}/python2-config +%endif +%{_bindir}/python%{pybasever}-config +%{_libdir}/libpython%{pybasever}.so +%{_sysconfdir}/rpm/macros.python +%{_sysconfdir}/rpm/macros.python2 + +%files tools +%defattr(-,root,root,755) +%doc Tools/pynche/README.pynche +%{site_packages}/pynche +%{_bindir}/smtpd*.py* +%{_bindir}/2to3* +%{_bindir}/idle* +%{_bindir}/pynche* +%{_bindir}/pygettext*.py* +%{_bindir}/msgfmt*.py* +%{tools_dir} +%{demo_dir} +%{pylibdir}/Doc + +%files -n %{tkinter} +%defattr(-,root,root,755) +%{pylibdir}/lib-tk +%{dynload_dir}/_tkinter.so + +%files test +%defattr(-, root, root, -) +%{pylibdir}/bsddb/test +%{pylibdir}/ctypes/test +%{pylibdir}/distutils/tests +%{pylibdir}/email/test +%{pylibdir}/json/tests +%{pylibdir}/lib2to3/tests +%{pylibdir}/sqlite3/test +%{pylibdir}/test/* +# These two are shipped in the main subpackage: +%exclude %{pylibdir}/test/test_support.py* +%exclude %{pylibdir}/test/__init__.py* +%{dynload_dir}/_ctypes_test.so +%{dynload_dir}/_testcapimodule.so + + +# We don't bother splitting the debug build out into further subpackages: +# if you need it, you're probably a developer. + +# Hence the manifest is the combination of analogous files in the manifests of +# all of the other subpackages + +%if 0%{?with_debug_build} +%files debug +%defattr(-,root,root,-) + +# Analog of the core subpackage's files: +%{_bindir}/%{python}-debug +%if %{main_python} +%{_bindir}/python2-debug +%endif +%{_bindir}/python%{pybasever}-debug + +# Analog of the -libs subpackage's files, with debug builds of the built-in +# "extension" modules: +%{dynload_dir}/_bisectmodule_d.so +%{dynload_dir}/_bsddb_d.so +%{dynload_dir}/_codecs_cn_d.so +%{dynload_dir}/_codecs_hk_d.so +%{dynload_dir}/_codecs_iso2022_d.so +%{dynload_dir}/_codecs_jp_d.so +%{dynload_dir}/_codecs_kr_d.so +%{dynload_dir}/_codecs_tw_d.so +%{dynload_dir}/_collectionsmodule_d.so +%{dynload_dir}/_csv_d.so +%{dynload_dir}/_ctypes_d.so +%{dynload_dir}/_curses_d.so +%{dynload_dir}/_curses_panel_d.so +%{dynload_dir}/_elementtree_d.so +%{dynload_dir}/_functoolsmodule_d.so +%{dynload_dir}/_hashlib_d.so +%{dynload_dir}/_heapq_d.so +%{dynload_dir}/_hotshot_d.so +%{dynload_dir}/_io_d.so +%{dynload_dir}/_json_d.so +%{dynload_dir}/_localemodule_d.so +%{dynload_dir}/_lsprof_d.so +%{dynload_dir}/_multibytecodecmodule_d.so +%{dynload_dir}/_multiprocessing_d.so +%{dynload_dir}/_randommodule_d.so +%{dynload_dir}/_socketmodule_d.so +%{dynload_dir}/_sqlite3_d.so +%{dynload_dir}/_ssl_d.so +%{dynload_dir}/_struct_d.so +%{dynload_dir}/arraymodule_d.so +%{dynload_dir}/audioop_d.so +%{dynload_dir}/binascii_d.so +%{dynload_dir}/bz2_d.so +%{dynload_dir}/cPickle_d.so +%{dynload_dir}/cStringIO_d.so +%{dynload_dir}/cmathmodule_d.so +%{dynload_dir}/_cryptmodule_d.so +%{dynload_dir}/datetime_d.so +%{dynload_dir}/dbm_d.so +%{dynload_dir}/dlmodule_d.so +%{dynload_dir}/fcntlmodule_d.so +%{dynload_dir}/future_builtins_d.so +%if %{with_gdbm} +%{dynload_dir}/gdbmmodule_d.so +%endif +%{dynload_dir}/grpmodule_d.so +%{dynload_dir}/imageop_d.so +%{dynload_dir}/itertoolsmodule_d.so +%{dynload_dir}/linuxaudiodev_d.so +%{dynload_dir}/math_d.so +%{dynload_dir}/mmapmodule_d.so +%{dynload_dir}/nismodule_d.so +%{dynload_dir}/operator_d.so +%{dynload_dir}/ossaudiodev_d.so +%{dynload_dir}/parsermodule_d.so +%{dynload_dir}/pyexpat_d.so +%{dynload_dir}/readline_d.so +%{dynload_dir}/resource_d.so +%{dynload_dir}/selectmodule_d.so +%{dynload_dir}/spwdmodule_d.so +%{dynload_dir}/stropmodule_d.so +%{dynload_dir}/syslog_d.so +%{dynload_dir}/termios_d.so +%{dynload_dir}/timemodule_d.so +%{dynload_dir}/timingmodule_d.so +%{dynload_dir}/unicodedata_d.so +%{dynload_dir}/xxsubtype_d.so +%{dynload_dir}/zlibmodule_d.so + +# No need to split things out the "Makefile" and the config-32/64.h file as we +# do for the regular build above (bug 531901), since they're all in one package +# now; they're listed below, under "-devel": + +%{_libdir}/%{py_INSTSONAME_debug} +%if 0%{?with_systemtap} +%{tapsetdir}/%{libpython_stp_debug} +%endif + +# Analog of the -devel subpackage's files: +%dir %{pylibdir}/config-debug +%{_libdir}/pkgconfig/python-%{pybasever}-debug.pc +%{_libdir}/pkgconfig/python-debug.pc +%{_libdir}/pkgconfig/python2-debug.pc +%{pylibdir}/config-debug/* +%{_includedir}/python%{pybasever}-debug/*.h +%if %{main_python} +%{_bindir}/python-debug-config +%{_bindir}/python2-debug-config +%endif +%{_bindir}/python%{pybasever}-debug-config +%{_libdir}/libpython%{pybasever}_d.so + +# Analog of the -tools subpackage's files: +# None for now; we could build precanned versions that have the appropriate +# shebang if needed + +# Analog of the tkinter subpackage's files: +%{dynload_dir}/_tkinter_d.so + +# Analog of the -test subpackage's files: +%{dynload_dir}/_ctypes_test_d.so +%{dynload_dir}/_testcapimodule_d.so + +%endif # with_debug_build + +# We put the debug-gdb.py file inside /usr/lib/debug to avoid noise from +# ldconfig (rhbz:562980). +# +# The /usr/lib/rpm/redhat/macros defines the __debug_package macro to use +# debugfiles.list, and it appears that everything below /usr/lib/debug and +# (/usr/src/debug) gets added to this file (via LISTFILES) in +# /usr/lib/rpm/find-debuginfo.sh +# +# Hence by installing it below /usr/lib/debug we ensure it is added to the +# -debuginfo subpackage +# (if it doesn't, then the rpmbuild ought to fail since the debug-gdb.py +# payload file would be unpackaged) + + +# ====================================================== +# Finally, the changelog: +# ====================================================== + +%changelog +* Mon Sep 10 2018 Charalampos Stratakis - 2.7.5-76 +- Remove an unversioned obsoletes tag +Resolves: rhbz#1627059 + +* Mon Jul 16 2018 Charalampos Stratakis - 2.7.5-75 +- Provide the /usr/libexec/platform-python symlink to the main binary +Resolves: rhbz#1599159 + +* Tue Jun 12 2018 Charalampos Stratakis - 2.7.5-74 +- Fix OSERROR 17 due to _multiprocessing/semaphore.c assuming + a one-to-one Pid -> process mapping +Resolves: rhbz#1579432 + +* Wed May 30 2018 Charalampos Stratakis - 2.7.5-73 +- Remove 3DS cipher to mitigate CVE-2016-2183 (sweet32). +Resolves: rhbz#1581901 + +* Thu May 03 2018 Charalampos Stratakis - 2.7.5-72 +- Fix CVE-2018-1060 and CVE-2018-1061 +Resolves: rhbz#1563454 and rhbz#1549192 +- Provide python2-libs from the python-libs subpackage +Resolves: rhbz#1557460 + +* Wed Apr 18 2018 Charalampos Stratakis - 2.7.5-71 +- Limit the number of CPU cores when building the package on power architectures +Resolves: rhbz#1568974 + +* Tue Apr 17 2018 Charalampos Stratakis - 2.7.5-70 +- Do not send IP addresses in SNI TLS extension +Resolves: rhbz#1555314 + +* Tue Apr 17 2018 Charalampos Stratakis - 2.7.5-69 +- Fix nondeterministic read in test_pty +Resolves: rhbz#1512160 + +* Mon Feb 19 2018 Tomas Orsava - 2.7.5-68 +- Add Conflicts tag with old virtualenv versions due to new behaviour of + httplib (patch 295) +Resolves: rhbz#1483438 + +* Mon Feb 19 2018 Tomas Orsava - 2.7.5-67 +- Re-add the private `_set_hostport` api to httplib (Patch 296) +Resolves: rhbz#1546351 + +* Fri Feb 09 2018 Charalampos Stratakis - 2.7.5-66 +- Fix https connections behind a proxy. +Resolves: rhbz#1483438 + +* Fri Dec 08 2017 Charalampos Stratakis - 2.7.5-65 +- Fix hanging of all threads when trying to access an inaccessible NFS server. +Resolves: rhbz#1520068 + +* Tue Oct 17 2017 Charalampos Stratakis - 2.7.5-64 +- Fix an issue with the context parameter addition to xmlrpclib.ServerProxy +Resolves: rhbz#1490392 + +* Fri Oct 13 2017 Petr Viktorin - 2.7.5-63 +- Make it more likely for the system allocator to release free()d memory arenas +Resolves: rhbz#1468410 + +* Wed Oct 11 2017 Charalampos Stratakis - 2.7.5-62 +- Add context parameter to xmlrpclib.ServerProxy +Resolves: rhbz#1490392 + +* Tue Oct 03 2017 Charalampos Stratakis - 2.7.5-61 +- Increase imaplib's MAXLINE to accommodate modern mailbox sizes. +Resolves: rhbz#1489858 + +* Tue Oct 03 2017 Charalampos Stratakis - 2.7.5-60 +- Fix fcntl() with integer argument on 64-bit big-endian platforms. +Resolves: rhbz#1489858 + +* Tue Oct 03 2017 Charalampos Stratakis - 2.7.5-59 +- Increase timeouts in test_smtplib. +Resolves: rhbz#1497795 + +* Wed May 03 2017 Charalampos Stratakis - 2.7.5-58 +- Set stream to None in case an _open() fails. +Resolves: rhbz#1432003 + +* Tue Apr 11 2017 Charalampos Stratakis - 2.7.5-57 +- Fix implicit declaration warnings of functions added by patches 147 and 265 +Resolves: rhbz#1441237 + +* Mon Apr 10 2017 Charalampos Stratakis - 2.7.5-56 +- Fix shutil.make_archive ignoring empty directories when creating zip files +Resolves: rhbz#1439734 + +* Thu Mar 23 2017 Tomas Orsava - 2.7.5-55 +- Update Python RPM macros with new ones from EPEL7 to simplify packaging +Resolves: rhbz#1297522 + +* Wed Mar 22 2017 Charalampos Stratakis - 2.7.5-54 +- Protect key list during fork() +Resolves: rhbz#1268226 + +* Mon Mar 13 2017 Charalampos Stratakis - 2.7.5-53 +- Fix _ssl.c reference leaks +Resolves: rhbz#1272562 + +* Mon Feb 27 2017 Charalampos Stratakis - 2.7.5-52 +- Workaround Python's threading library issue with non returning wait, for signals with timeout +Resolves: rhbz#1368076 + +* Mon Jan 23 2017 Charalampos Stratakis - 2.7.5-51 +- Enable certificate verification by default +Resolves: rhbz#1219110 + +* Wed Jan 18 2017 Charalampos Stratakis - 2.7.5-50 +- Fix incorrect parsing of certain regular expressions +Resolves: rhbz#1373363 + +* Tue Jan 17 2017 Charalampos Stratakis - 2.7.5-49 +- Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs +Resolves: rhbz#1364444 + +* Mon Aug 01 2016 Charalampos Stratakis - 2.7.5-48 +- Fix for CVE-2016-1000110 HTTPoxy attack +Resolves: rhbz#1359164 + +* Mon Jul 11 2016 Charalampos Stratakis - 2.7.5-47 +- Fix for CVE-2016-5636: possible integer overflow and heap corruption in zipimporter.get_data() +Resolves: rhbz#1356364 + +* Mon Jul 11 2016 Charalampos Stratakis - 2.7.5-46 +- Drop patch 221 that backported sslwrap function since it was introducing regressions +- Refactor patch 227 +Resolves: rhbz#1331425 + +* Tue Jun 21 2016 Tomas Orsava - 2.7.5-45 +- Fix for CVE-2016-0772 python: smtplib StartTLS stripping attack (rhbz#1303647) + Raise an error when STARTTLS fails (upstream patch) +- Fix for CVE-2016-5699 python: http protocol steam injection attack (rhbz#1303699) + Disabled HTTP header injections in httplib (upstream patch) +Resolves: rhbz#1346357 + +* Wed May 4 2016 Charalampos Stratakis - 2.7.5-44 +- Fix iteration over files with very long lines +Resolves: rhbz#1271760 + +* Tue May 3 2016 Charalampos Stratakis - 2.7.5-43 +- Move python.conf from /etc/tmpfiles.d/ to /usr/lib/tmpfiles.d/ +Resolves: rhbz#1288426 + +* Mon Apr 4 2016 Charalampos Stratakis - 2.7.5-42 +- JSON decoder lone surrogates fix +Resolves: rhbz#1301017 + +* Mon Apr 4 2016 Charalampos Stratakis - 2.7.5-41 +- Updated PEP493 implementation +Resolves: rhbz#1315758 + +* Thu Mar 31 2016 Charalampos Stratakis - 2.7.5-40 +- Backport of Computed Goto dispatch +Resolves: rhbz#1289277 + +* Mon Mar 21 2016 Charalampos Stratakis - 2.7.5-39 +- Removal of the '$Date$' placeholder on the python(1) man page footer, +which does not expand during build +Resolves: rhbz#1268310 + +* Thu Mar 17 2016 Charalampos Stratakis - 2.7.5-38 +- Fix hashlib algorithms breaking by initializing OpenSSL_add_all_digests +function in _hashlib library +Resolves: rhbz#1295459 + +* Thu Mar 17 2016 Charalampos Stratakis - 2.7.5-37 +- Change HTTPS certificate verification to platform_default +Resolves: rhbz#1278429 + +* Wed Mar 16 2016 Charalampos Stratakis - 2.7.5-36 +- Force all child threads to terminate in TestForkInThread +Resolves: rhbz#1313259 + +* Thu Mar 10 2016 Charalampos Stratakis - 2.7.5-35 +- Adjusted tests to acknowledge lack of SSLv2 support +Resolves: rhbz#1315310 + +* Fri Oct 09 2015 Matej Stuchlik - 2.7.5-34 +- Revert fix for rhbz#1117751 as it leads to regressions +Resolves: rhbz#1117751 + +* Tue Sep 15 2015 Matej Stuchlik - 2.7.5-33 +- Only restore SIG_PIPE when Popen called with restore_sigpipe +Resolves: rhbz#1117751 + +* Fri Sep 04 2015 Robert Kuska - 2.7.5-32 +- Backport SSLSocket.version function +- Temporary disable test_gdb on ppc64le rhbz#1260558 +Resolves: rhbz#1259421 + +* Thu Aug 06 2015 Robert Kuska - 2.7.5-31 +- Update load_cert_chain function to accept None keyfile +Resolves: rhbz#1250611 + +* Tue Jul 07 2015 Robert Kuska - 2.7.5-30 +- Change Patch224 according to latest update in PEP493 +Resolves:rhbz#1219108 + +* Tue Jul 07 2015 Matej Stuchlik - 2.7.5-29 +- Popen shouldn't ignore SIG_PIPE +Resolves: rhbz#1117751 + +* Tue Jul 07 2015 Matej Stuchlik - 2.7.5-28 +- Exclude python subprocess temp files from cleaning +Resolves: rhbz#1058482 + +* Wed Jul 01 2015 Robert Kuska - 2.7.5-27 +- Add list for cprofile sort option +Resolves:rhbz#1237107 + +* Mon Jun 29 2015 Robert Kuska - 2.7.5-26 +- Add switch to toggle cert verification on or off globally +Resolves:rhbz#1219108 + +* Mon Jun 29 2015 Robert Kuska - 2.7.5-25 +- PEP476 enable cert verifications by default +Resolves:rhbz#1219110 + +* Mon Jun 29 2015 Robert Kuska - 2.7.5-24 +- Massive backport of ssl module from python3 aka PEP466 +Resolves: rhbz#1111461 + +* Tue Jun 23 2015 Matej Stuchlik - 2.7.5-23 +- Fixed CVE-2013-1753, CVE-2013-1752, CVE-2014-4616, CVE-2014-4650, CVE-2014-7185 +Resolves: rhbz#1206574 + +* Mon Jun 22 2015 Matej Stuchlik - 2.7.5-22 +- Fix importing readline producing erroneous output +Resolves: rhbz#1189301 + +* Mon Jun 22 2015 Matej Stuchlik - 2.7.5-21 +- Add missing import in bdist_rpm +Resolves: rhbz#1177613 + +* Mon Jun 22 2015 Matej Stuchlik - 2.7.5-20 +- Avoid double close of subprocess pipes +Resolves: rhbz#1103452 + +* Thu Apr 09 2015 Robert Kuska - 2.7.5-19 +- make multiprocessing ignore EINTR +Resolves: rhbz#1181624 + +* Wed Sep 3 2014 Peter Robinson 2.7.5-18 +- valgrind is now supported on aarch64/ppc64le +Resolves: rhbz#1137039 + +* Thu Aug 07 2014 Slavek Kabrda - 2.7.5-17 +- Fix building on ppc64le (fix test_gdb, disable valgrind support). +Resolves: rhbz#1125657 + +* Mon Feb 10 2014 Tomas Radej - 2.7.5-16 +- Fix buffer overflow (upstream patch) +Resolves: rhbz#1062376 + +* Tue Jan 28 2014 Daniel Mach - 2.7.5-15 +- Mass rebuild 2014-01-24 + +* Tue Jan 14 2014 Matej Stuchlik - 2.7.5-14 +- Fix missing documentation for some keywords +Resolves: rhbz#1032116 + +* Mon Jan 13 2014 Matej Stuchlik - 2.7.5-13 +- Make library-files user writable +Resolves: rhbz#1046276 + +* Fri Jan 10 2014 Bohuslav Kabrda - 2.7.5-12 +- Use -O3 when building on ppc64. +Resolves: rhbz#1051076 + +* Fri Dec 27 2013 Daniel Mach - 2.7.5-11 +- Mass rebuild 2013-12-27 + +* Thu Nov 07 2013 Matej Stuchlik - 2.7.5-10 +- Added an explicit RPATH to _elementtree.so +Resolves: rhbz#1019345 + +* Thu Nov 07 2013 Matej Stuchlik - 2.7.5-9 +- Fixed instances of #!/usr/bin/env python +Resolves: rhbz#1019336 + +* Wed Oct 09 2013 Bohuslav Kabrda - 2.7.5-8 +- Fix gdb bindings on ppc64. +Resolves: rhbz#835053 + +* Tue Aug 20 2013 Matej Stuchlik - 2.7.5-7 +- Added fix for CVE-2013-4238 +Resolves: rhbz#998781 + +* Tue Aug 20 2013 Bohuslav Kabrda - 2.7.5-6 +- Add explicit RPATH to pyexpat pointing at system libexpat (rhbz#996665). + +* Mon Aug 05 2013 Bohuslav Kabrda - 2.7.5-5 +- Fix memory leak in marshal.c, fixes rhbz#990554. + +* Wed Jul 24 2013 Robert Kuska - 2.7.5-4 +- Change shebangs of scripts in tools subpackage +(rhbz#987038) + +* Wed Jul 17 2013 Matej Stuchlik - 2.7.5-3 +- Added patch that makes urllib2 honor no_proxy variable for ftp URLs + (rhbz#971267) + +* Wed Jul 17 2013 Matej Stuchlik - 2.7.5-2 +- Pulled patch fixing build with libffi containing multilib wrapper for ffi.h + from Fedora (rhbz#979696) + +* Thu May 16 2013 Bohuslav Kabrda - 2.7.5-1 +- Updated to Python 2.7.5. +- Refreshed patches: 0 (config), 102 (lib64), 121 (add Modules to build path), +153 (gdb test noise) +- Dropped patches: 126, 127 (big endian issues, both fixed upstream), +175 (configure -Wformat, fixed upstream) +- Synced patch numbers with python3.spec. + +* Tue May 14 2013 David Malcolm - 2.7.4-5 +- fix multilib issue in python-tools due to /usr/bin/pynche (source 7; +rhbz#831437) + +* Thu May 02 2013 Bohuslav Kabrda - 2.7.4-4 +- Add patch that enables building on ppc64p7. + +* Mon Apr 22 2013 Bohuslav Kabrda - 2.7.4-3 +- Allow arbitrary timeout in Condition.wait (rhbz#917709). + +* Thu Apr 11 2013 Kalev Lember - 2.7.4-2 +- Build with libdb 5.3 instead of libdb4 +- Refreshed patches: 0 (config), 102 (lib64) +- Dropped patches: 54 (db4 version), 159 (db4 include path adjustment) + +* Mon Apr 08 2013 Bohuslav Kabrda - 2.7.4-1 +- Updated to Python 2.7.4. +- Refreshed patches: 0 (config), 7 (sqlite encoding), 16 (rpath in config), +55 (systemtap), 111 (no static lib), 112 (debug build), 113 (more +configuration flags), 130 (add extension to python config), 134 (fix +COUNT_ALLOCS in test_sys), 146 (haslib FIPS), 147 (add debug malloc stats), +153 (fix gdb test noise), 157 (uid, gid overflow - fixed upstream, just +keeping few more downstream tests), 165 (crypt module salt backport), +175 (fix configure Wformat), 5000 (regenerated autotooling patch) +- Dropped patches: 101 (lib64 regex; merged upstream), 171 (exception on +missing /dev/urandom; merged upstream), 172 (poll for multiprocessing socket +connection; merged upstream) + +* Mon Mar 25 2013 David Malcolm - 2.7.3-35 +- fix gcc 4.8 incompatibility (rhbz#927358); regenerate autotool intermediates + +* Wed Mar 6 2013 David Malcolm - 2.7.3-34 +- restrict scope of workaround for cmpi-bindings issue to avoid breaking +in-tree running of test_sys and test_subprocess (rhbz#817554) + +* Wed Mar 6 2013 David Malcolm - 2.7.3-33 +- add workaround for cmpi-bindings issue (rhbz#817554) + +* Mon Mar 4 2013 David Malcolm - 2.7.3-32 +- add workaround for ENOPROTOOPT seen running selftests in Koji +(rhbz#913732) + +* Mon Mar 4 2013 David Malcolm - 2.7.3-31 +- remove config flag from /etc/rpm/macros.python2 + +* Fri Feb 22 2013 David Malcolm - 2.7.3-30 +- remove __debug_package macro from comment + +* Fri Feb 22 2013 David Malcolm - 2.7.3-29 +- drop -b from application of patch 157 (uid/gid overflows) + +* Fri Feb 22 2013 David Malcolm - 2.7.3-28 +- fix bogus dates in changelog + +* Thu Feb 21 2013 David Malcolm - 2.7.3-27 +- port _multiprocessing.Connection.poll() to use the "poll" syscall, rather +than "select", allowing large numbers of subprocesses (patch 172; +rhbz#849992) + +* Thu Feb 21 2013 David Malcolm - 2.7.3-26 +- raise correct exception in os.urandom() when /dev/urandom is missing +(patch 171; rhbz#907383) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-25 +- in debug builds, try to print repr() when a C-level assert fails in the +garbage collector (typically indicating a reference-counting error somewhere +else e.g in an extension module) (patch 170; rhbz#850013) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-24 +- move lib2to3/tests from python-libs to python-test (rhbz#850056) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-23 +- use SHA-256 rather than implicitly using MD5 within the challenge handling +in multiprocessing.connection (patch 169; rhbz#879695) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-22 +- fix a problem with distutils.sysconfig when CFLAGS is defined in the +environment (patch 168; rhbz#849994) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-21 +- don't run any stack navigation tests in test_gdb for optimized builds +(patch 167; rhbz#912025) + +* Wed Feb 20 2013 David Malcolm - 2.7.3-20 +- s/cryptmodule/_cryptmodule/ in package payload (rhbz#835021) + +* Tue Feb 19 2013 David Malcolm - 2.7.3-19 +- bulletproof the gdb debugging hooks against a failure seen in ARM builds +(patch 166; rhbz#912025) +- re-enable make check on ARM (rhbz#912025) + +* Tue Feb 19 2013 David Malcolm - 2.7.3-18 +- backport pre-canned ways of salting a password to the "crypt" module from 3.3 +(rhbz#835021) + +* Tue Feb 19 2013 David Malcolm - 2.7.3-17 +- remove "_default_patch_fuzz" directive to avoid patches being silently +misapplied (refresh patch 1, patch 101, patch 102, patch 111, patch 121, +patch 158; rename patch 1, patch 101, patch 121; apply patch 54 before the +lib64 patches to avoid fuzz problems caused by the conditional application +of the lib64 patches) + +* Mon Feb 18 2013 Peter Robinson 2.7.3-16 +- disable make check on ARM for the moment until 912025 is fixed + +* Mon Feb 11 2013 David Malcolm - 2.7.3-15 +- add aarch64 (rhbz#909783) + +* Thu Nov 29 2012 David Malcolm - 2.7.3-14 +- add BR on bluez-libs-devel (rhbz#879720) + +* Thu Aug 9 2012 David Malcolm - 2.7.3-13 +- remove f18 conditional from patch 159 + +* Fri Jul 27 2012 Fedora Release Engineering - 2.7.3-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jul 17 2012 Bohuslav Kabrda - 2.7.3-11 +- fix memory leak in module _hashlib (patch 158, rhbz#836285) +- fix db4 include path for libdb4 package (f18 and above) (patch 159) + +* Tue Jun 26 2012 David Malcolm - 2.7.3-10 +- fix missing include in uid/gid handling patch (patch 157; rhbz#830405) + +* Fri Jun 22 2012 David Malcolm - 2.7.3-9 +- use rpm macro for power64 (rhbz#834653) + +* Tue May 15 2012 David Malcolm - 2.7.3-8 +- update uid/gid handling to avoid int overflows seen with uid/gid +values >= 2^31 on 32-bit architectures (patch 157; rhbz#697470) + +* Fri May 4 2012 David Malcolm - 2.7.3-7 +- renumber autotools patch from 300 to 5000 +- specfile cleanups + +* Mon Apr 30 2012 David Malcolm - 2.7.3-6 +- try again to fix test_gdb.py (patch 156; rhbz#817072) + +* Mon Apr 30 2012 David Malcolm - 2.7.3-5 +- fix test_gdb.py (patch 156; rhbz#817072) + +* Fri Apr 20 2012 David Malcolm - 2.7.3-4 +- avoid allocating thunks in ctypes unless absolutely necessary, to avoid +generating SELinux denials on "import ctypes" and "import uuid" when embedding +Python within httpd (patch 155; rhbz#814391) + +* Thu Apr 19 2012 David Malcolm - 2.7.3-3 +- add explicit version requirements on expat to avoid linkage problems with +XML_SetHashSalt + +* Wed Apr 18 2012 David Malcolm - 2.7.3-2 +- fix -config symlinks (patch 112; rhbz#813836) + +* Wed Apr 11 2012 David Malcolm - 2.7.3-1 +- 2.7.3: refresh patch 102 (lib64); drop upstream patches 11 (ascii-to-lower), +115 (pydoc robustness), 145 (linux2), 148 (gdbm magic values), 151 (deadlock +in fork); refresh patch 112 (debug build); revise patch 127 +(test_structmember); fix test_gdb (patch 153); refresh patch 137 (distutils +tests); add python2.pc to python-devel; regenerate the autotool intermediates +patch (patch 300) + +* Sat Feb 25 2012 Thomas Spura - 2.7.2-20 +- fix deadlock issue (#787712) + +* Fri Feb 17 2012 Toshio Kuratomi - 2.7.2-19 +- Obsolete python-sqlite2 + +* Thu Nov 24 2011 Ville Skyttä - 2.7.2-18 +- Build with $RPM_LD_FLAGS (#756862). +- Use xz-compressed source tarball. + +* Wed Oct 26 2011 Fedora Release Engineering - 2.7.2-17 +- Rebuilt for glibc bug#747377 + +* Fri Sep 30 2011 David Malcolm - 2.7.2-16 +- re-enable gdbm (patch 148; rhbz#742242) + +* Fri Sep 16 2011 David Malcolm - 2.7.2-15 +- add a sys._debugmallocstats() function (patch 147) + +* Wed Sep 14 2011 David Malcolm - 2.7.2-14 +- support OpenSSL FIPS mode in _hashlib and hashlib; don't build the _md5 and +_sha* modules, relying on _hashlib in hashlib, and thus within md5 etc +(rhbz#563986; patch 146) + +* Wed Sep 14 2011 David Malcolm - 2.7.2-13 +- force sys.platform to be "linux2" (patch 145) + +* Tue Sep 13 2011 David Malcolm - 2.7.2-12 +- disable gdbm module to prepare for gdbm soname bump + +* Mon Sep 12 2011 David Malcolm - 2.7.2-11 +- rename and renumber patches for consistency with python3.spec (55, 111, 113, +114, 125, 131, 129 to 143) + +* Sat Sep 10 2011 David Malcolm - 2.7.2-10 +- rewrite of "check", introducing downstream-only hooks for skipping specific +cases in an rpmbuild (patch 132), and fixing/skipping failing tests in a more +fine-grained manner than before (patches 104, 133-142) + +* Thu Sep 1 2011 David Malcolm - 2.7.2-9 +- run selftests with "--verbose" +- disable parts of test_io on ppc (rhbz#732998) + +* Tue Aug 23 2011 David Malcolm - 2.7.2-8 +- add --extension-suffix option to python-config (patch 130; rhbz#732808) + +* Tue Aug 23 2011 David Malcolm - 2.7.2-7 +- re-enable and fix the --with-tsc option on ppc64, and rework it on 32-bit +ppc to avoid aliasing violations (patch 129; rhbz#698726) + +* Tue Aug 23 2011 David Malcolm - 2.7.2-6 +- don't use --with-tsc on ppc64 debug builds (rhbz#698726) + +* Thu Aug 18 2011 David Malcolm - 2.7.2-5 +- add rpm macros file (rhbz#731800) + +* Fri Jul 8 2011 David Malcolm - 2.7.2-4 +- cleanup of BuildRequires; add comment headings to specfile sections + +* Wed Jun 22 2011 David Malcolm - 2.7.2-3 +- reorganize test exclusions (test_openpty and test_pty seem to be failing on +every arch, not just the explicitly-listed ones) + +* Mon Jun 13 2011 Dan Horák - 2.7.2-2 +- add s390(x) excluded tests + +* Mon Jun 13 2011 David Malcolm - 2.7.2-1 +- 2.7.2; drop upstreamed patches: patch 122 (parallel make fix), patch 124 +(test_commands and SELinux), patch 130 (ppc preprocessor macro in debug +build); patch 131 (decimal in Turkish locale); regenerate the autotool +intermediates patch (patch 300) + +* Tue Jun 07 2011 Dennis Gilmore - 2.7.1-9 +- fix sparc building by excluding failing tests RHBZ#711584 + +* Mon May 23 2011 Peter Robinson - 2.7.1-8 +- fix compile on ARM by excluding failing tests on arm - RHBZ #706253 + +* Tue Apr 12 2011 David Malcolm - 2.7.1-7 +- fix "import decimal" in the Turkish locale (patch 131; rhbz#694928) + +* Wed Feb 09 2011 Fedora Release Engineering - 2.7.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Fri Jan 21 2011 Toshio Kuratomi - 2.7.1-5 +- Switch from setting OPT to setting EXTRA_CFLAGS so we don't overwrite the + DNDEBUG flag + +* Fri Jan 7 2011 David Malcolm - 2.7.1-4 +- for now, drop "obsoletes" of python-argparse, since it interracts badly with +multilib (rhbz#667984) + +* Fri Jan 7 2011 Thomas Spura - 2.7.1-3 +- obsolete/provide python-argparse (new in 2.7) + +* Thu Jan 6 2011 David Malcolm - 2.7.1-2 +- fix the ppc build of the debug configuration (patch 130; rhbz#661510) + +* Thu Dec 23 2010 David Malcolm - 2.7.1-1 +- 2.7.1, reworking patch 0 (config), patch 102 (lib64); drop upstream +patch 56 (cfgparse), patch 110 (ctypes/SELinux/noexecmem), patch 119 (expat +compat), patch 123 (2to3 on "from itertools import *") +- fix test_abc's test_cache_leak in the debug build (patch 128) +- drop _weakref.so from manifest (_weakref became a core module in r84230) + +* Wed Sep 29 2010 jkeating - 2.7-13 +- Rebuilt for gcc bug 634757 + +* Mon Sep 27 2010 David Malcolm - 2.7-12 +- fix test_structmember on 64bit-bigendian (patch 127) + +* Fri Sep 24 2010 David Malcolm - 2.7-11 +- fix dbm_contains on 64bit-bigendian (patch 126; rhbz#626756) + +* Thu Sep 16 2010 Toshio Kuratomi - 2.7-10 +- backport a patch to fix a change in behaviour in configparse. + +* Thu Sep 9 2010 David Malcolm - 2.7-9 +- move most of the payload of the core package to the libs subpackage, given +that the libs aren't meaningfully usable without the standard libraries + +* Wed Aug 18 2010 David Malcolm - 2.7-8 +- add %%check section +- update lib64 patch (patch 102) to fix expected output in test_site.py on +64-bit systems +- patch test_commands.py to work with SELinux (patch 124) +- patch the debug build's usage of COUNT_ALLOCS to be less verbose (patch 125) + +* Mon Jul 26 2010 David Malcolm - 2.7-7 +- fixup missing -lcrypt to "crypt" module in config patch (patch 0) + +* Mon Jul 26 2010 David Malcolm - 2.7-6 +- re-enable systemtap +- cherrypick upstream patch to 2to3 for "from itertools import *" +traceback (patch 123) + +* Thu Jul 22 2010 David Malcolm - 2.7-5 +- disable systemtap for now (dtrace is failing on startup due to the bug +mentioned in 2.7-4) +- provide relative path to python binary when running pathfix.py +- fix parallel make (patch 122) + +* Thu Jul 22 2010 David Malcolm - 2.7-4 +- fix reference to pyconfig.h in sysconfig that led to failure on startup if +python-devel was not installed + +* Thu Jul 8 2010 David Malcolm - 2.7-3 +- add patch to fixup the new sysconfig.py for our multilib support on +64-bit (patch 103) + +* Thu Jul 8 2010 David Malcolm - 2.7-2 +- add machinery for regenerating the "configure" script in the face of +mismatching autoconf versions (patch 300) + +* Tue Jul 6 2010 David Malcolm - 2.7-1 +- 2.7 final; drop alphatag +- drop patch 117 (upstream), patch 120 (upstreamed) +- fix the commented-out __python_ver from 26 to 27 + +* Tue Jun 22 2010 David Malcolm - 2.7-0.1.rc2 +- 2.7rc2 +- revert r79310 (patch 121) +- remove modulator: upstream removed it in r78338 +- rename mathmodule(_d).so to math(_d).so in manifests (appears to be changed +by r76861) +- _bytesio(_d).so and _filesio(_d).so were consolidated into _io(_d).so in +r73394 (upstream issue 6215) +- use the gdb hooks from the upstream tarball, rather than keeping our own +copy. The upstream version has some whitespace changes, a new write_repr for +unicode objects, and various bulletproofings for being run on older gdbs + +* Tue Jun 22 2010 David Malcolm - 2.7-0.1.rc1 +- 2.7rc1: + - rework patches to apply against 2.7 (which among other changes has had a +whitespace cleanup of the .c code): .rhconfig (patch0), .binutils-no-dep +(patch10), .ascii-tolower (patch11), .socketmodule (patch13), .socketmodule2 +(patch14), .systemtap (patch55), .lib64 (patch102), .selinux (patch110), +.no-static-lib (patch111), .debug-build (patch112), .statvfs-f-flag-constants +(patch114), ..CVE-2010-2089 (patch117) + - drop upstream patches: .expat (patch3), .brprpm (patch51), .valgrind +(patch52), .db48 (patch53), .CVE-2010-1634 (patch 116), .CVE-2008-5983 (patch +118) + +* Tue Jun 22 2010 David Malcolm - 2.6.5-17 +- Stop python bailing out with an assertion failure when UnicodeDecodeErrors +occur on very large buffers (patch 120, upstream issue 9058) + +* Mon Jun 21 2010 David Malcolm - 2.6.5-16 +- Fix an incompatibility between pyexpat and the system expat-2.0.1 that led to +a segfault running test_pyexpat.py (patch 119; upstream issue 9054) + +* Tue Jun 8 2010 David Malcolm - 2.6.5-15 +- add a flag to make it easy to turn off the debug build when troubleshooting +the rpm build + +* Sat Jun 5 2010 Dan Horák - 2.6.5-14 +- reading the timestamp counter is available only on some arches (see Python/ceval.c) +- disable --with-valgrind on s390(x) arches + +* Fri Jun 4 2010 David Malcolm - 2.6.5-13 +- ensure that the compiler is invoked with "-fwrapv" (rhbz#594819) +- CVE-2010-1634: fix various integer overflow checks in the audioop +module (patch 116) +- CVE-2010-2089: further checks within the audioop module (patch 117) +- CVE-2008-5983: the new PySys_SetArgvEx entry point from r81399 (patch 118) + +* Thu May 27 2010 David Malcolm - 2.6.5-12 +- make "pydoc -k" more robust in the face of broken modules (rhbz:461419, patch115) + +* Wed May 26 2010 David Malcolm - 2.6.5-11 +- add flags for statvfs.f_flag to the constant list in posixmodule (i.e. "os") +(patch 114) + +* Tue May 25 2010 David Malcolm - 2.6.5-10 +- add configure-time support for COUNT_ALLOCS and CALL_PROFILE debug options +(patch 113); enable them and the WITH_TSC option within the debug build + +* Tue May 18 2010 David Malcolm - 2.6.5-9 +- build and install two different configurations of Python: debug and standard, +packaging the debug build in a new "python-debug" subpackage (patch 112) + +* Tue May 4 2010 David Malcolm - 2.6.5-8 +- don't delete wsgiref.egg-info (rhbz:588426) + +* Mon Apr 26 2010 David Malcolm - 2.6.5-7 +- disable --with-valgrind on sparc arches + +* Mon Apr 12 2010 David Malcolm - 2.6.5-6 +- move the "bdist_wininst" command's template .exe files from the core package +to the devel subpackage, to save space (rhbz:525469) +- fix stray doublelisting of config directory wildcard in devel subpackage + +* Wed Mar 31 2010 David Malcolm - 2.6.5-5 +- update python-gdb.py from v4 to v5 (improving performance and stability, +adding commands) + +* Thu Mar 25 2010 David Malcolm - 2.6.5-4 +- update python-gdb.py from v3 to v4 (fixing infinite recursion on reference +cycles and tracebacks on bytes 0x80-0xff in strings, adding handlers for sets +and exceptions) + +* Wed Mar 24 2010 David Malcolm - 2.6.5-3 +- refresh gdb hooks to v3 (reworking how they are packaged) + +* Mon Mar 22 2010 David Malcolm - 2.6.5-2 +- remove unnecessary arch-conditionality for patch 101 + +* Fri Mar 19 2010 David Malcolm - 2.6.5-1 +- update to 2.6.5: http://www.python.org/download/releases/2.6.5/ +- replace our patch to compile against db4.8 with a patch from +upstream (patch 53, from r78974); update patch 54 since part of it is now in +that upstream patch +- update patch 110 so that it still applies in the face of upstream r78380 + +* Tue Mar 16 2010 David Malcolm - 2.6.4-23 +- fixup distutils/unixccompiler.py to remove standard library path from +rpath (patch 17) +- delete DOS batch files + +* Fri Mar 12 2010 David Malcolm - 2.6.4-22 +- add pyfuntop.stp; allow systemtap support to be disabled +- remove trailing period from tkinter summary +- don't own /usr/bin/python-config if you're not the main python + +* Thu Mar 11 2010 Marcela Mašláňová - 2.6.4-21 +- rebuild with new gdbm + +* Thu Feb 11 2010 David Malcolm - 2.6.4-20 +- avoid having the "test" subdirectory and the files within it that are in the +core subpackage also be owned by the test subpackage (rhbz:467588) + +* Wed Feb 10 2010 David Malcolm - 2.6.4-19 +- revise the systemtap patch (patch 55:python-2.6.4-dtrace.patch) to the +new version by mjw in attachment 390110 of rhbz:545179, as this should +eliminate the performance penalty for the case where the probes aren't in +use, and eliminate all architecture-specific code (rhbz:563541; except on +sparc) + +* Tue Feb 9 2010 David Malcolm - 2.6.4-18 +- add a systemtap tapset defining "python.function.entry" and +"python.function.return" to make it easy to use the static probepoint within +Python; add an example of using the tapset to the docs + +* Tue Feb 9 2010 David Malcolm - 2.6.4-17 +- add systemtap static probes (wcohen; patch 55; rh bug #545179) +- update some comments in specfile relating to gdb work +- manually byte-compile the gdb.py file with the freshly-built python to ensure +that .pyx and .pyo files make it into the debuginfo manifest if they are later +byte-compiled after find-debuginfo.sh is run + +* Mon Feb 8 2010 David Malcolm - 2.6.4-16 +- move the -gdb.py file from %%{_libdir}/INSTSONAME-gdb.py to +%%{_prefix}/lib/debug/%%{_libdir}/INSTSONAME.debug-gdb.py to avoid noise from +ldconfig (bug 562980), and which should also ensure it becomes part of the +debuginfo subpackage, rather than the libs subpackage +- introduce %%{py_SOVERSION} and %%{py_INSTSONAME} to reflect the upstream +configure script, and to avoid fragile scripts that try to figure this out +dynamically (e.g. for the -gdb.py change) + +* Mon Feb 8 2010 David Malcolm - 2.6.4-15 +- work around bug 562906 by supplying a fixed version of pythondeps.sh +- set %%{_python_bytecompile_errors_terminate_build} to 0 to prevent the broken +test files from killing the build on buildroots where python is installed + +* Fri Feb 5 2010 David Malcolm - 2.6.4-14 +- add gdb hooks for easier debugging + +* Fri Jan 29 2010 David Malcolm - 2.6.4-13 +- document all patches, and remove the commented-out ones + +* Tue Jan 26 2010 David Malcolm - 2.6.4-12 +- Address some of the issues identified in package review (bug 226342): + - update libs requirement on base package to use %%{name} for consistency's +sake + - convert from backticks to $() syntax throughout + - wrap value of LD_LIBRARY_PATH in quotes + - convert "/usr/bin/find" requirement to "findutils" + - remove trailing periods from summaries of -devel and -tools subpackages + - fix spelling mistake in description of -test subpackage + - convert usage of $$RPM_BUILD_ROOT to %%{buildroot} throughout, for +stylistic consistency + - supply dirmode arguments to defattr directives + +* Mon Jan 25 2010 David Malcolm - 2.6.4-11 +- update python-2.6.2-config.patch to remove downstream customization of build +of pyexpat and elementtree modules +- add patch adapted from upstream (patch 3) to add support for building against +system expat; add --with-system-expat to "configure" invocation +- remove embedded copy of expat from source tree during "prep" + +* Mon Jan 25 2010 David Malcolm - 2.6.4-10 +- introduce macros for 3 directories, replacing expanded references throughout: +%%{pylibdir}, %%{dynload_dir}, %%{site_packages} +- explicitly list all lib-dynload files, rather than dynamically gathering the +payload into a temporary text file, so that we can be sure what we are +shipping; remove now-redundant testing for presence of certain .so files +- remove embedded copy of zlib from source tree before building + +* Mon Jan 25 2010 David Malcolm - 2.6.4-9 +- change python-2.6.2-config.patch to remove our downstream change to curses +configuration in Modules/Setup.dist, so that the curses modules are built using +setup.py with the downstream default (linking against libncursesw.so, rather +than libncurses.so), rather than within the Makefile; add a test to %%install +to verify the dso files that the curses module is linked against the correct +DSO (bug 539917; changes _cursesmodule.so -> _curses.so) + +* Fri Jan 22 2010 David Malcolm - 2.6.4-8 +- rebuild (bug 556975) + +* Wed Jan 20 2010 David Malcolm - 2.6.4-7 +- move lib2to3 from -tools subpackage to main package (bug 556667) + +* Mon Jan 18 2010 David Malcolm - 2.6.4-6 +- patch Makefile.pre.in to avoid building static library (patch111, bug 556092) +- split up the "configure" invocation flags onto individual lines + +* Fri Jan 15 2010 David Malcolm - 2.6.4-5 +- replace usage of %%define with %%global +- use the %%{_isa} macro to ensure that the python-devel dependency on python +is for the correct multilib arch (#555943) +- delete bundled copy of libffi to make sure we use the system one +- replace references to /usr with %%{_prefix}; replace references to +/usr/include with %%{_includedir} + +* Wed Dec 16 2009 David Malcolm - 2.6.4-4 +- automatically disable arena allocator when run under valgrind (upstream +issue 2422; patch 52) +- add patch from Josh Boyer containing diff against upstream PyBSDDB to make +the bsddb module compile against db-4.8 (patch 53, #544275); bump the necessary +version of db4-devel to 4.8 +- patch setup.py so that it searches for db-4.8, and enable debug output for +said search; make Setup.dist use db-4.8 (patch 54) + +* Thu Nov 12 2009 David Malcolm - 2.6.4-3 +- fixup the build when __python_ver is set (Zach Sadecki; bug 533989); use +pybasever in the files section + +* Thu Oct 29 2009 David Malcolm - 2.6.4-2 +- "Makefile" and the config-32/64.h file are needed by distutils/sysconfig.py +_init_posix(), so we include them in the core package, along with their parent +directories (bug 531901) + +* Mon Oct 26 2009 David Malcolm - 2.6.4-1 +- Update to 2.6.4 + +* Fri Aug 21 2009 Tomas Mraz - 2.6.2-2 +- rebuilt with new openssl + +* Mon Jul 27 2009 James Antill - 2.6.2-1 +- Update to 2.6.2 + +* Sun Jul 26 2009 Fedora Release Engineering - 2.6-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Sat Jul 4 2009 Jonathan Steffan - 2.6-10 +- Move python-config to devel subpackage (#506153) +- Update BuildRoot for new standard + +* Sun Jun 28 2009 Jonathan Steffan - 2.6-9 +- Update python-tools description (#448940) + +* Wed Apr 15 2009 Ignacio Vazquez-Abrams 2.6-8 +- Replace python-hashlib and python-uuid (#484715) + +* Tue Mar 17 2009 James Antill - 2.6-7 +- Use system libffi +- Resolves: bug#490573 +- Fix SELinux execmem problems +- Resolves: bug#488396 + +* Thu Feb 26 2009 Fedora Release Engineering - 2.6-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Jan 16 2009 Tomas Mraz - 2.6-4 +- rebuild with new openssl + +* Tue Jan 6 2009 James Antill - 2.6-3 +- Fix distutils generated rpms. +- Resolves: bug#236535 + +* Wed Dec 10 2008 Ignacio Vazquez-Abrams - 2.6-2 +- Enable -lcrypt for cryptmodule + +* Fri Nov 28 2008 Ignacio Vazquez-Abrams - 2.6-1 +- Update to 2.6 + +* Tue Sep 30 2008 James Antill - 2.5.2-1 +- Move to 2.5.2 +- Fix CVE-2008-2316 hashlib overflow. + +* Thu Jul 17 2008 Jeremy Katz - 2.5.1-30 +- Fix up the build for new rpm +- And actually build against db4-4.7 (#455170) + +* Thu Jul 10 2008 Tom "spot" Callaway - 2.5.1-27 +- fix license tag +- enable support for db4-4.7 + +* Sun Jun 15 2008 James Antill - 2.5.1-26 +- Fix sporadic listdir problem +- Resolves: bug#451494 + +* Mon Apr 7 2008 James Antill - 2.5.1-25 +- Rebuild to re-gen autoconf file due to glibc change. +- Resolves: bug#441003 + +* Tue Mar 25 2008 James Antill - 2.5.1-24 +- Add more constants to socketmodule + +* Sat Mar 8 2008 James Antill - 2.5.1-22 +- Add constants to socketmodule +- Resolves: bug#436560 + +* Tue Feb 19 2008 Fedora Release Engineering - 2.5.1-22 +- Autorebuild for GCC 4.3 + +* Sun Jan 13 2008 Tom "spot" Callaway - 2.5.1-21 +- rebuild for new tk in rawhide + +* Mon Jan 7 2008 James Antill - 2.5.1-20 +- Add valgrind support files, as doc, to python-devel +- Relates: rhbz#418621 +- Add new API from 2.6, set_wakeup_fd ... use at own risk, presumably won't +- change but I have no control to guarantee that. +- Resolves: rhbz#427794 +- Add gdbinit support file, as doc, to python-devel + +* Fri Jan 4 2008 Tom "spot" Callaway - 2.5.1-19 +- rebuild for new tcl/tk in rawhide + +* Fri Dec 7 2007 James Antill - 2.5.1-18 +- Create a python-test sub-module, over 3MB of stuff noone wants. +- Don't remove egginfo files, try this see what happens ... may revert. +- Resolves: rhbz#414711 + +* Mon Dec 3 2007 Jeremy Katz - 2.5.1-17 +- rebuild for new libssl + +* Fri Nov 30 2007 James Antill - 2.5.1-16 +- Fix pyconfig.h comment typo. +- Add back test_support.py and the __init__.py file. +- Resolves: rhbz#387401 + +* Tue Oct 30 2007 James Antill - 2.5.1-15 +- Do codec lowercase in C Locale. +- Resolves: 207134 191096 +- Fix stupid namespacing in pysqlite, minimal upgrade to 2.3.3 pysqlite +- Resolves: 263221 + +* Wed Oct 24 2007 James Antill - 2.5.1-14 +- Remove bintuils dep. for live CD ... add work around for ctypes + +* Mon Oct 22 2007 James Antill - 2.5.1-13 +- Add tix buildprereq +- Add tkinter patch +- Resolves: #281751 +- Fix ctypes loading of libraries, add requires on binutils +- Resolves: #307221 +- Possible fix for CVE-2007-4965 possible exploitable integer overflow +- Resolves: #295971 + +* Tue Oct 16 2007 Mike Bonnet - 2.5.1-12 +- fix marshalling of objects in xmlrpclib (python bug #1739842) + +* Fri Sep 14 2007 Jeremy Katz - 2.5.1-11 +- fix encoding of sqlite .py files to work around weird encoding problem + in Turkish (#283331) + +* Mon Sep 10 2007 Jeremy Katz - 2.5.1-10 +- work around problems with multi-line plural specification (#252136) + +* Tue Aug 28 2007 Jeremy Katz - 2.5.1-9 +- rebuild against new expat + +* Tue Aug 14 2007 Jeremy Katz - 2.5.1-8 +- build against db4.6 + +* Tue Aug 14 2007 Dennis Gilmore - 2.5.1-7 +- add sparc64 to the list of archs for _pyconfig64_h + +* Fri Aug 10 2007 Jeremy Katz - 2.5.1-6 +- fix ctypes again on some arches (Hans de Goede, #251637) + +* Fri Jul 6 2007 Jeremy Katz - 2.5.1-5 +- link curses modules with ncursesw (#246385) + +* Wed Jun 27 2007 Jeremy Katz - 2.5.1-4 +- fix _elementtree.so build (#245703) +- ensure that extension modules we expect are actually built rather than + having them silently fall out of the package + +* Tue Jun 26 2007 Jeremy Katz - 2.5.1-3 +- link with system expat (#245703) + +* Thu Jun 21 2007 Jeremy Katz - 2.5.1-2 +- rebuild to take advantage of hardlinking between identical pyc/pyo files + +* Thu May 31 2007 Jeremy Katz - 2.5.1-1 +- update to python 2.5.1 + +* Mon Mar 19 2007 Jeremy Katz - 2.5.3-12 +- fix alpha build (#231961) + +* Tue Feb 13 2007 Jeremy Katz - 2.5.3-11 +- tcl/tk was reverted; rebuild again + +* Thu Feb 1 2007 Jeremy Katz - 2.5.3-10 +- rebuild for new tcl/tk + +* Tue Jan 16 2007 Miroslav Lichvar - 2.5.3-9 +- link with ncurses + +* Sat Jan 6 2007 Jeremy Katz - 2.5.3-8 +- fix extensions to use shared libpython (#219564) +- all 64bit platforms need the regex fix (#122304) + +* Wed Jan 3 2007 Jeremy Katz - 2.5.3-7 +- fix ctypes to not require execstack (#220669) + +* Fri Dec 15 2006 Jeremy Katz - 2.5.3-6 +- don't link against compat-db (Robert Scheck) + +* Wed Dec 13 2006 Jarod Wilson - 2.5.3-5 +- fix invalid assert in debug mode (upstream changeset 52622) + +* Tue Dec 12 2006 Jeremy Katz - 2.5.3-4 +- obsolete/provide python-ctypes (#219256) + +* Mon Dec 11 2006 Jeremy Katz - 2.5.3-3 +- fix atexit traceback with failed syslog logger (#218214) +- split libpython into python-libs subpackage for multilib apps + embedding python interpreters + +* Wed Dec 6 2006 Jeremy Katz - 2.5.3-2 +- disable installation of .egg-info files for now + +* Tue Dec 5 2006 Jeremy Katz +- support db 4.5 +- obsolete python-elementtree; since it requires some code tweaks, don't + provide it +- obsolete old python-sqlite; provide the version that's actually included + +* Mon Oct 30 2006 Jeremy Katz +- fix _md5 and _sha modules (Robert Sheck) +- no longer provide optik compat; it's been a couple of years now +- no longer provide the old shm module; if this is still needed, let's + build it separately +- no longer provide japanese codecs; should be a separate package + +* Mon Oct 23 2006 Jeremy Katz - 2.5-0 +- update to 2.5.0 final + +* Fri Aug 18 2006 Mihai Ibanescu - 2.4.99.c1 +- Updated to 2.5c1. Merged fixes from FC6 too: +- Fixed bug #199373 (on some platforms CFLAGS is needed when linking) +- Fixed bug #198971 (case conversion not locale safe in logging library) +- Verified bug #201434 (distutils.sysconfig is confused by the change to make + python-devel multilib friendly) is fixed upstream + +* Sun Jul 16 2006 Mihai Ibanescu - 2.4.99.b2 +- Updated to 2.5b2 (which for comparison reasons is re-labeled 2.4.99.b2) + +* Fri Jun 23 2006 Mihai Ibanescu - 2.4.99.b1 +- Updated to 2.5b1 (which for comparison reasons is re-labeled 2.4.99.b1) + +* Tue Jun 13 2006 Jeremy Katz - 2.4.3-11.FC6 +- and fix it for real + +* Tue Jun 13 2006 Jeremy Katz - 2.4.3-10.FC6 +- fix python-devel on ia64 + +* Tue Jun 13 2006 Mihai Ibanescu - 2.4.3-9 +- Fixed python-devel to be multilib friendly (bug #192747, #139911) + +* Tue Jun 13 2006 Mihai Ibanescu - 2.4.3-8 +- Only copying mkhowto from the Docs - we don't need perl dependencies from + python-tools. + +* Mon Jun 12 2006 Mihai Ibanescu - 2.4.3-7 +- Fixed bug #121198 (webbrowser.py should use the user's preferences first) + +* Mon Jun 12 2006 Mihai Ibanescu - 2.4.3-6 +- Fixed bug #192592 (too aggressive assertion fails) - SF#1257960 +- Fixed bug #167468 (Doc/tools not included) - added in the python-tools package + +* Thu Jun 8 2006 Mihai Ibanescu - 2.4.3-5 +- Fixed bug #193484 (added pydoc in the main package) + +* Mon Jun 5 2006 Mihai Ibanescu - 2.4.3-4 +- Added dist in the release + +* Mon May 15 2006 Mihai Ibanescu - 2.4.3-3 +- rebuilt to fix broken libX11 dependency + +* Wed Apr 12 2006 Jeremy Katz - 2.4.3-2 +- rebuild with new gcc to fix #188649 + +* Thu Apr 6 2006 Mihai Ibanescu - 2.4.3-1 +- Updated to 2.4.3 + +* Fri Feb 10 2006 Jesse Keating - 2.4.2-3.2.1 +- bump again for double-long bug on ppc(64) + +* Fri Feb 10 2006 Mihai Ibanescu - 2.4.3-3.2 +- rebuilt for newer tix + +* Tue Feb 07 2006 Jesse Keating - 2.4.2-3.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Jan 20 2006 Mihai Ibanescu 2.4.2-3 +- fixed #136654 for another instance of audiotest.au + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Sat Nov 19 2005 Bill Nottingham 2.4.2-2 +- fix build for modular X, remove X11R6 path references + +* Tue Nov 15 2005 Mihai Ibanescu 2.4.2-1 +- Upgraded to 2.4.2 +- BuildRequires autoconf + +* Wed Nov 9 2005 Mihai Ibanescu 2.4.1-16 +- Rebuilding against newer openssl. +- XFree86-devel no longer exists + +* Mon Sep 26 2005 Peter Jones 2.4.1-14 +- Once more -- this time, to fix -EPERM when you run it in a directory + you can't read from. + +* Mon Sep 26 2005 Peter Jones 2.4.1-13 +- So, 5 or 6 people have said it works for them with this patch... + +* Sun Sep 25 2005 Peter Jones 2.4.1-12 +- Fixed bug #169159 (check for argc>0 and argv[0] == NULL, not just + argv[0][0]='\0') + Reworked the patch from -8 a bit more. + +* Fri Sep 23 2005 Mihai Ibanescu 2.4.1-10 +- Fixed bug #169159 (don't let python core dump if no arguments are passed in) + Reworked the patch from -8 a bit more. + +* Thu Sep 22 2005 Peter Jones 2.4.1-8 +- Fix bug #169046 more correctly. + +* Thu Sep 22 2005 Mihai Ibanescu 2.4.1-7 +- Fixed bug #169046 (realpath is unsafe); thanks to + Peter Jones and Arjan van de Ven for + diagnosing and the patch. + +* Tue Sep 20 2005 Mihai Ibanescu 2.4.1-4 +- Fixed bug #168655 (fixes for building as python24) + +* Tue Jul 26 2005 Mihai Ibanescu 2.4.1-3 +- Fixed bug #163435 (pynche doesn't start)) + +* Wed Apr 20 2005 Mihai Ibanescu 2.4.1-2 +- Fixed bug #143667 (python should own /usr/lib/python* on 64-bit systems, for + noarch packages) +- Fixed bug #143419 (BuildRequires db4 is not versioned) + +* Wed Apr 6 2005 Mihai Ibanescu 2.4.1-1 +- updated to 2.4.1 + +* Mon Mar 14 2005 Mihai Ibanescu 2.4-6 +- building the docs from a different source rpm, to decouple bootstrapping + python from having tetex installed + +* Fri Mar 11 2005 Dan Williams 2.4-5 +- Rebuild to pick up new libssl.so.5 + +* Wed Feb 2 2005 Mihai Ibanescu 2.4-4 +- Fixed security issue in SimpleXMLRPCServer.py (#146647) + +* Wed Jan 12 2005 Tim Waugh 2.4-3 +- Rebuilt for new readline. + +* Mon Dec 6 2004 Jeff Johnson 2.4-2 +- db-4.3.21 returns DB_BUFFER_SMALL rather than ENOMEM (#141994). +- add Provide: python(abi) = 2.4 +- include msgfmt/pygettext *.pyc and *.pyo from brp-python-bytecompile. + +* Fri Dec 3 2004 Mihai Ibanescu 2.4-1 +- Python-2.4.tar.bz2 (final) + +* Fri Nov 19 2004 Mihai Ibanescu 2.4-0.c1.1 +- Python-2.4c1.tar.bz2 (release candidate 1) + +* Thu Nov 11 2004 Jeff Johnson 2.4-0.b2.4 +- rebuild against db-4.3.21. + +* Mon Nov 8 2004 Jeremy Katz - 2.4-0.b2.3 +- fix the lib64 patch so that 64bit arches still look in /usr/lib/python... + +* Mon Nov 8 2004 Jeremy Katz - 2.4-0.b2.2 +- cryptmodule still needs -lcrypt (again) + +* Thu Nov 4 2004 Mihai Ibanescu 2.4-0.b2.1 +- Updated to python 2.4b2 (and labeled it 2.4-0.b2.1 to avoid breaking rpm's + version comparison) + +* Thu Nov 4 2004 Mihai Ibanescu 2.3.4-13 +- Fixed bug #138112 (python overflows stack buffer) - SF bug 105470 + +* Tue Nov 2 2004 Mihai Ibanescu 2.3.4-12 +- Fixed bugs #131439 #136023 #137863 (.pyc/.pyo files had the buildroot added) + +* Tue Oct 26 2004 Mihai Ibanescu 2.3.4-11 +- Fixed bug #136654 (python has sketchy audio clip) + +* Tue Aug 31 2004 Mihai Ibanescu 2.3.4-10 +- Fixed bug #77418 (Demo dir not packaged) +- More tweaking on #19347 (Moved Tools/ under /usr/lib/python2.3/Tools) + +* Fri Aug 13 2004 Mihai Ibanescu 2.3.4-8 +- Fixed bug #129769: Makefile in new python conflicts with older version found + in old python-devel +- Reorganized the spec file to get rid of the aspython2 define; __python_ver + is more powerful. + +* Tue Aug 3 2004 Mihai Ibanescu 2.3.4-7 +- Including html documentation for non-i386 arches +- Fixed #125362 (python-doc html files have japanese character encoding) +- Fixed #128923 (missing dependency between python and python-devel) + +* Fri Jul 30 2004 Mihai Ibanescu 2.3.4-6 +- Fixed #128030 (help() not printing anything) +- Fixed #125472 (distutils.sysconfig.get_python_lib() not returning the right + path on 64-bit systems) +- Fixed #127357 (building python as a shared library) +- Fixed #19347 (including the contents of Tools/scripts/ in python-tools) + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Jun 8 2004 Mihai Ibanescu 2.3.4-3 +- Added an optik.py that provides the same interface from optparse for + backward compatibility; obsoleting python-optik + +* Mon Jun 7 2004 Mihai Ibanescu 2.3.4-2 +- Patched bdist_rpm to allow for builds of multiple binary rpms (bug #123598) + +* Fri Jun 4 2004 Mihai Ibanescu 2.3.4-1 +- Updated to 2.3.4-1 with Robert Scheck's help (bug #124764) +- Added BuildRequires: tix-devel (bug #124918) + +* Fri May 7 2004 Mihai Ibanescu 2.3.3-6 +- Correct fix for #122304 from upstream: + http://sourceforge.net/tracker/?func=detail&atid=105470&aid=931848&group_id=5470 + +* Thu May 6 2004 Mihai Ibanescu 2.3.3-4 +- Fix for bug #122304 : splitting the domain name fails on 64-bit arches +- Fix for bug #120879 : including Makefile into the main package + +- Requires XFree86-devel instead of -libs (see bug #118442) + +* Tue Mar 16 2004 Mihai Ibanescu 2.3.3-3 +- Requires XFree86-devel instead of -libs (see bug #118442) + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Fri Dec 19 2003 Jeff Johnson 2.3.3-1 +- upgrade to 2.3.3. + +* Sat Dec 13 2003 Jeff Johnson 2.3.2-9 +- rebuild against db-4.2.52. + +* Fri Dec 12 2003 Jeremy Katz 2.3.2-8 +- more rebuilding for new tcl/tk + +* Wed Dec 3 2003 Jeff Johnson 2.3.2-7.1 +- rebuild against db-4.2.42. + +* Fri Nov 28 2003 Mihai Ibanescu 2.3.2-7 +- rebuilt against newer tcl/tk + +* Mon Nov 24 2003 Mihai Ibanescu 2.3.2-6 +- added a Provides: python-abi + +* Wed Nov 12 2003 Mihai Ibanescu 2.3.2-5 +- force CC (#109268) + +* Sun Nov 9 2003 Jeremy Katz 2.3.2-4 +- cryptmodule still needs -lcrypt + +* Wed Nov 5 2003 Mihai Ibanescu 2.3.2-2 +- Added patch for missing mkhowto + +* Thu Oct 16 2003 Mihai Ibanescu 2.3.2-1 +- Updated to 2.3.2 + +* Thu Sep 25 2003 Mihai Ibanescu 2.3.1-1 +- 2.3.1 final + +* Tue Sep 23 2003 Mihai Ibanescu 2.3.1-0.8.RC1 +- Building the python 2.3.1 release candidate +- Updated the lib64 patch + +* Wed Jul 30 2003 Mihai Ibanescu 2.3-0.2 +- Building python 2.3 +- Added more BuildRequires +- Updated the startup files for modulator and pynche; idle installs its own + now. + +* Thu Jul 3 2003 Mihai Ibanescu 2.2.3-4 +- Rebuilt against newer db4 packages (bug #98539) + +* Mon Jun 9 2003 Elliot Lee 2.2.3-3 +- rebuilt + +* Sat Jun 7 2003 Mihai Ibanescu 2.2.3-2 +- Rebuilt + +* Fri Jun 6 2003 Mihai Ibanescu 2.2.3-1 +- Upgraded to 2.2.3 + +* Wed Apr 2 2003 Mihai Ibanescu 2.2.2-28 +- Rebuilt + +* Wed Apr 2 2003 Mihai Ibanescu 2.2.2-27 +- Modified the ftpuri patch conforming to http://ietf.org/rfc/rfc1738.txt + +* Mon Feb 24 2003 Elliot Lee +- rebuilt + +* Mon Feb 24 2003 Mihai Ibanescu 2.2.2-25 +- Fixed bug #84886: pydoc dies when run w/o arguments +- Fixed bug #84205: add python shm module back (used to be shipped with 1.5.2) +- Fixed bug #84966: path in byte-compiled code still wrong + +* Thu Feb 20 2003 Jeremy Katz 2.2.2-23 +- ftp uri's should be able to specify being rooted at the root instead of + where you login via ftp (#84692) + +* Mon Feb 10 2003 Mihai Ibanescu 2.2.2-22 +- Using newer Japanese codecs (1.4.9). Thanks to + Peter Bowen for pointing this out. + +* Thu Feb 6 2003 Mihai Ibanescu 2.2.2-21 +- Rebuild + +* Wed Feb 5 2003 Mihai Ibanescu 2.2.2-20 +- Release number bumped really high: turning on UCS4 (ABI compatibility + breakage) + +* Fri Jan 31 2003 Mihai Ibanescu 2.2.2-13 +- Attempt to look both in /usr/lib64 and /usr/lib/python2.2/site-packages/: + some work on python-2.2.2-lib64.patch + +* Thu Jan 30 2003 Mihai Ibanescu 2.2.2-12 +- Rebuild to incorporate the removal of .lib64 and - files. + +* Thu Jan 30 2003 Mihai Ibanescu 2.2.2-11.7.3 +- Fixed bug #82544: Errata removes most tools +- Fixed bug #82435: Python 2.2.2 errata breaks redhat-config-users +- Removed .lib64 and - files that get installed after we fix the multilib + .py files. + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Jan 15 2003 Jens Petersen 2.2.2-10 +- rebuild to update tkinter's tcltk deps +- convert changelog to utf-8 + +* Tue Jan 7 2003 Nalin Dahyabhai 2.2.2-9 +- rebuild + +* Fri Jan 3 2003 Nalin Dahyabhai +- pick up OpenSSL cflags and ldflags from pkgconfig if available + +* Thu Jan 2 2003 Jeremy Katz 2.2.2-8 +- urllib2 didn't support non-anonymous ftp. add support based on how + urllib did it (#80676, #78168) + +* Mon Dec 16 2002 Mihai Ibanescu 2.2.2-7 +- Fix bug #79647 (Rebuild of SRPM fails if python isn't installed) +- Added a bunch of missing BuildRequires found while fixing the + above-mentioned bug + +* Tue Dec 10 2002 Tim Powers 2.2.2-6 +- rebuild to fix broken tcltk deps for tkinter + +* Fri Nov 22 2002 Mihai Ibanescu +2.2.2-3.7.3 +- Recompiled for 7.3 (to fix the -lcrypt bug) +- Fix for the spurious error message at the end of the build (build-requires + gets confused by executable files starting with """"): make the tests + non-executable. + +* Wed Nov 20 2002 Mihai Ibanescu +2.2.2-5 +- Fixed configuration patch to add -lcrypt when compiling cryptmodule.c + +2.2.2-4 +- Spec file change from Matt Wilson to disable linking + with the C++ compiler. + +* Mon Nov 11 2002 Mihai Ibanescu +2.2.2-3.* +- Merged patch from Karsten Hopp from 2.2.1-17hammer to + use %%{_libdir} +- Added XFree86-libs as BuildRequires (because of tkinter) +- Fixed duplicate listing of plat-linux2 +- Fixed exclusion of lib-dynload/japanese +- Added lib64 patch for the japanese codecs +- Use setup magic instead of using tar directly on JapaneseCodecs + +* Tue Nov 5 2002 Mihai Ibanescu +2.2.2-2 +- Fix #76912 (python-tools contains idle, which uses tkinter, but there is no + requirement of tkinter from python-tools). +- Fix #74013 (rpm is missing the /usr/lib/python2.2/test directory) + +* Mon Nov 4 2002 Mihai Ibanescu +- builds as python2 require a different libdb +- changed the buildroot name of python to match python2 builds + +* Fri Nov 1 2002 Mihai Ibanescu +- updated python to 2.2.2 and adjusted the patches accordingly + +* Mon Oct 21 2002 Mihai Ibanescu +- Fix #53930 (Python-2.2.1-buildroot-bytecode.patch) +- Added BuildPrereq dependency on gcc-c++ + +* Fri Aug 30 2002 Trond Eivind Glomsrød 2.2.1-17 +- security fix for _execvpe + +* Tue Aug 13 2002 Trond Eivind Glomsrød 2.2.1-16 +- Fix #71011,#71134, #58157 + +* Wed Aug 7 2002 Trond Eivind Glomsrød 2.2.1-15 +- Resurrect tkinter +- Fix for distutils (#67671) +- Fix #69962 + +* Thu Jul 25 2002 Trond Eivind Glomsrød 2.2.1-14 +- Obsolete tkinter/tkinter2 (#69838) + +* Tue Jul 23 2002 Trond Eivind Glomsrød 2.2.1-13 +- Doc fixes (#53951) - not on alpha at the momemt + +* Mon Jul 8 2002 Trond Eivind Glomsrød 2.2.1-12 +- fix pydoc (#68082) + +* Mon Jul 8 2002 Trond Eivind Glomsrød 2.2.1-11 +- Add db4-devel as a BuildPrereq + +* Fri Jun 21 2002 Tim Powers 2.2.1-10 +- automated rebuild + +* Mon Jun 17 2002 Trond Eivind Glomsrød 2.2.1-9 +- Add Japanese codecs (#66352) + +* Tue Jun 11 2002 Trond Eivind Glomsrød 2.2.1-8 +- No more tkinter... + +* Wed May 29 2002 Trond Eivind Glomsrød 2.2.1-7 +- Rebuild + +* Tue May 21 2002 Trond Eivind Glomsrød 2.2.1-6 +- Add the email subcomponent (#65301) + +* Fri May 10 2002 Trond Eivind Glomsrød 2.2.1-5 +- Rebuild + +* Thu May 02 2002 Than Ngo 2.2.1-4 +- rebuild i new enviroment + +* Tue Apr 23 2002 Trond Eivind Glomsrød +- Use ucs2, not ucs4, to avoid breaking tkinter (#63965) + +* Mon Apr 22 2002 Trond Eivind Glomsrød 2.2.1-2 +- Make it use db4 + +* Fri Apr 12 2002 Trond Eivind Glomsrød 2.2.1-1 +- 2.2.1 - a bugfix-only release + +* Fri Apr 12 2002 Trond Eivind Glomsrød 2.2-16 +- the same, but in builddirs - this will remove them from the + docs package, which doesn't look in the buildroot for files. + +* Fri Apr 12 2002 Trond Eivind Glomsrød 2.2-15 +- Get rid of temporary files and .cvsignores included + in the tarball and make install + +* Fri Apr 5 2002 Trond Eivind Glomsrød 2.2-14 +- Don't own lib-tk in main package, only in tkinter (#62753) + +* Mon Mar 25 2002 Trond Eivind Glomsrød 2.2-13 +- rebuild + +* Mon Mar 25 2002 Trond Eivind Glomsrød 2.2-12 +- rebuild + +* Fri Mar 1 2002 Trond Eivind Glomsrød 2.2-11 +- Add a not to the Distutils obsoletes test (doh!) + +* Fri Mar 1 2002 Trond Eivind Glomsrød 2.2-10 +- Rebuild + +* Mon Feb 25 2002 Trond Eivind Glomsrød 2.2-9 +- Only obsolete Distutils when built as python + +* Thu Feb 21 2002 Trond Eivind Glomsrød 2.2-8 +- Make files in /usr/bin install side by side with python 1.5 when +- Drop explicit requirement of db4 + built as python2 + +* Thu Jan 31 2002 Elliot Lee 2.2-7 +- Use version and pybasever macros to make updating easy +- Use _smp_mflags macro + +* Tue Jan 29 2002 Trond Eivind Glomsrød 2.2-6 +- Add db4-devel to BuildPrereq + +* Fri Jan 25 2002 Nalin Dahyabhai 2.2-5 +- disable ndbm support, which is db2 in disguise (really interesting things + can happen when you mix db2 and db4 in a single application) + +* Thu Jan 24 2002 Trond Eivind Glomsrød 2.2-4 +- Obsolete subpackages if necesarry +- provide versioned python2 +- build with db4 + +* Wed Jan 16 2002 Trond Eivind Glomsrød 2.2-3 +- Alpha toolchain broken. Disable build on alpha. +- New openssl + +* Wed Dec 26 2001 Trond Eivind Glomsrød 2.2-1 +- 2.2 final + +* Fri Dec 14 2001 Trond Eivind Glomsrød 2.2-0.11c1 +- 2.2 RC 1 +- Don't include the _tkinter module in the main package - it's + already in the tkiter packace +- Turn off the mpzmodule, something broke in the buildroot + +* Wed Nov 28 2001 Trond Eivind Glomsrød 2.2-0.10b2 +- Use -fPIC for OPT as well, in lack of a proper libpython.so + +* Mon Nov 26 2001 Matt Wilson 2.2-0.9b2 +- changed DESTDIR to point to / so that distutils will install dynload + modules properly in the installroot + +* Fri Nov 16 2001 Matt Wilson 2.2-0.8b2 +- 2.2b2 + +* Fri Oct 26 2001 Matt Wilson 2.2-0.7b1 +- python2ify + +* Fri Oct 19 2001 Trond Eivind Glomsrød 2.2-0.5b1 +- 2.2b1 + +* Sun Sep 30 2001 Trond Eivind Glomsrød 2.2-0.4a4 +- 2.2a4 +- Enable UCS4 support +- Enable IPv6 +- Provide distutils +- Include msgfmt.py and pygettext.py + +* Fri Sep 14 2001 Trond Eivind Glomsrød 2.2-0.3a3 +- Obsolete Distutils, which is now part of the main package +- Obsolete python2 + +* Thu Sep 13 2001 Trond Eivind Glomsrød 2.2-0.2a3 +- Add docs, tools and tkinter subpackages, to match the 1.5 layout + +* Wed Sep 12 2001 Trond Eivind Glomsrød 2.2-0.1a3 +- 2.2a3 +- don't build tix and blt extensions + +* Mon Aug 13 2001 Trond Eivind Glomsrød +- Add tk and tix to build dependencies + +* Sat Jul 21 2001 Trond Eivind Glomsrød +- 2.1.1 bugfix release - with a GPL compatible license + +* Fri Jul 20 2001 Trond Eivind Glomsrød +- Add new build dependencies (#49753) + +* Tue Jun 26 2001 Nalin Dahyabhai +- build with -fPIC + +* Fri Jun 1 2001 Trond Eivind Glomsrød +- 2.1 +- reorganization of file includes + +* Wed Dec 20 2000 Trond Eivind Glomsrød +- fix the "requires" clause, it lacked a space causing problems +- use %%{_tmppath} +- don't define name, version etc +- add the available patches from the Python home page + +* Fri Dec 15 2000 Matt Wilson +- added devel subpackage + +* Fri Dec 15 2000 Matt Wilson +- modify all files to use "python2.0" as the intrepter +- don't build the Expat bindings +- build against db1 + +* Mon Oct 16 2000 Jeremy Hylton +- updated for 2.0 final + +* Mon Oct 9 2000 Jeremy Hylton +- updated for 2.0c1 +- build audioop, imageop, and rgbimg extension modules +- include xml.parsers subpackage +- add test.xml.out to files list + +* Thu Oct 5 2000 Jeremy Hylton +- added bin/python2.0 to files list (suggested by Martin v. L?) + +* Tue Sep 26 2000 Jeremy Hylton +- updated for release 1 of 2.0b2 +- use .bz2 version of Python source + +* Tue Sep 12 2000 Jeremy Hylton +- Version 2 of 2.0b1 +- Make the package relocatable. Thanks to Suchandra Thapa. +- Exclude Tkinter from main RPM. If it is in a separate RPM, it is + easier to track Tk releases.