Attached is my current diff for python3.4 in Jessie. It attempts to fix all security vulnerabilities except:
* CVE-2013-1753 * CVE-2014-9365 As these look invasive, not easy to fix, and where not fixed in Wheezy either. The patch for CVE-2018-14647 seems to break compiling. It references a symbol that was not defined. Considering dropping this patch. ../Modules/_elementtree.c:3244:32: error: 'PyObject' has no member named 'parser' EXPAT(SetHashSalt)(self->parser, Unfortunately, failing tests do not fail the build. I see a number of test failures after applying the patches, but I strongly suspect these failures would also be occuring without applying the patch - as many look unrelated to the changes I made. Some tests also appear require networking, as they retrieve remote files. It might be worth doing a build with and without these patches and comparing the diff, in attempt to see if it causes any new tests failed. -- Brian May <b...@debian.org>
diff -u python3.4-3.4.2/debian/changelog python3.4-3.4.2/debian/changelog --- python3.4-3.4.2/debian/changelog +++ python3.4-3.4.2/debian/changelog @@ -1,3 +1,18 @@ +python3.4 (3.4.2-1+deb8u2) UNRELEASED; urgency=high + + * Non-maintainer upload by the LTS Team. + * CVE-2016-0772: Check for StartTLS failure. + * CVE-2016-5636: Fix integer overflow in the get_data. + * CVE-2016-5699: Fix CRLF injection vulnerability in the + HTTPConnection.putheader function in urllib2 and urllib. + * CVE-2018-14647: Fix Python's elementtree C accelerator failed to + initialise Expat's hash salt during initialization. + * CVE-2018-20406: Fix Modules/_pickle.c integer overflow. + * CVE-2019-5010: Fix NULL pointer dereference using a specially crafted X509 + certificate. + + -- Brian May <b...@debian.org> Thu, 10 Jan 2019 17:43:03 +1100 + python3.4 (3.4.2-1+deb8u1) jessie-security; urgency=medium * Non-maintainer upload by the LTS Security Team. diff -u python3.4-3.4.2/debian/patches/series.in python3.4-3.4.2/debian/patches/series.in --- python3.4-3.4.2/debian/patches/series.in +++ python3.4-3.4.2/debian/patches/series.in @@ -49,0 +50,6 @@ +CVE-2016-0772.patch +CVE-2016-5636.patch +CVE-2016-5699.patch +CVE-2018-14647.patch +CVE-2018-20406.patch +CVE-2019-5010.patch only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2016-0772.patch +++ python3.4-3.4.2/debian/patches/CVE-2016-0772.patch @@ -0,0 +1,22 @@ + +# HG changeset patch +# User Benjamin Peterson <benja...@python.org> +# Date 1465676202 25200 +# Node ID d590114c23940c41f558216f92f9c084d32aa688 +# Parent 90e58a77d386e658b76fd097e8a5efb48e7421e4 +raise an error when STARTTLS fails + +--- a/Lib/smtplib.py ++++ b/Lib/smtplib.py +@@ -696,6 +696,11 @@ + 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=[], only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2016-5636.patch +++ python3.4-3.4.2/debian/patches/CVE-2016-5636.patch @@ -0,0 +1,34 @@ + +# HG changeset patch +# User Benjamin Peterson <benja...@python.org> +# Date 1453357424 28800 +# Node ID 01ddd608b85c85952537d95a43bbabf4fb655057 +# Parent eb19459ce46a197d160540d4c05f97b8eb780e2e +prevent buffer overflow in get_data (closes #26171) + +--- a/Misc/NEWS ++++ b/Misc/NEWS +@@ -71,6 +71,9 @@ + Core and Builtins + ----------------- + ++- Issue #26171: Fix possible integer overflow and heap corruption in ++ zipimporter.get_data(). ++ + Library + ------- + +--- a/Modules/zipimport.c ++++ b/Modules/zipimport.c +@@ -1111,6 +1111,11 @@ + } + file_offset += l; /* Start of file data */ + ++ if (data_size > LONG_MAX - 1) { ++ fclose(fp); ++ PyErr_NoMemory(); ++ return NULL; ++ } + bytes_size = compress == 0 ? data_size : data_size + 1; + if (bytes_size == 0) + bytes_size++; only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2016-5699.patch +++ python3.4-3.4.2/debian/patches/CVE-2016-5699.patch @@ -0,0 +1,148 @@ + +# HG changeset patch +# User Serhiy Storchaka <storch...@gmail.com> +# Date 1426151616 -7200 +# Node ID bf3e1c9b80e995311ba932e42200f076e03034c0 +# Parent 2b4a04c3681b1210529eb8a224cc007a0b92a890 +Issue #22928: Disabled HTTP header injections in http.client. +Original patch by Demian Brecht. + +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -70,6 +70,7 @@ + import email.message + import io + import os ++import re + import socket + import collections + from urllib.parse import urlsplit +@@ -215,6 +216,34 @@ + _MAXLINE = 65536 + _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(rb'[^:\s][^:\r\n]*').fullmatch ++_is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search ++ + + class HTTPMessage(email.message.Message): + # XXX The only usage of this method is in +@@ -1060,12 +1089,20 @@ + + if hasattr(header, 'encode'): + header = header.encode('ascii') ++ ++ if not _is_legal_header_name(header): ++ raise ValueError('Invalid header name %r' % (header,)) ++ + values = list(values) + for i, one_value in enumerate(values): + if hasattr(one_value, 'encode'): + values[i] = one_value.encode('latin-1') + elif isinstance(one_value, int): + values[i] = str(one_value).encode('ascii') ++ ++ if _is_illegal_header_value(values[i]): ++ raise ValueError('Invalid header value %r' % (values[i],)) ++ + value = b'\r\n\t'.join(values) + header = header + b': ' + value + self._output(header) +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -141,6 +141,33 @@ + conn.putheader('Content-length', 42) + self.assertIn(b'Content-length: 42', 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 +@@ -160,6 +187,36 @@ + conn.request('GET', '/foo') + self.assertTrue(sock.data.startswith(expected)) + ++ def test_invalid_headers(self): ++ conn = client.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.subTest((name, value)): ++ with self.assertRaisesRegex(ValueError, 'Invalid header'): ++ conn.putheader(name, value) ++ + + class BasicTest(TestCase): + def test_status_lines(self): only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2018-14647.patch +++ python3.4-3.4.2/debian/patches/CVE-2018-14647.patch @@ -0,0 +1,76 @@ +From f7666e828cc3d5873136473ea36ba2013d624fa1 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-isling...@users.noreply.github.com> +Date: Tue, 18 Sep 2018 06:14:13 -0700 +Subject: [PATCH] bpo-34623: Use XML_SetHashSalt in _elementtree (GH-9146) + +The C accelerated _elementtree module now initializes hash randomization +salt from _Py_HashSecret instead of libexpat's default CPRNG. + +Signed-off-by: Christian Heimes <christ...@python.org> + +https://bugs.python.org/issue34623 +(cherry picked from commit cb5778f00ce48631c7140f33ba242496aaf7102b) + +Co-authored-by: Christian Heimes <christ...@python.org> +--- + Include/pyexpat.h | 4 +++- + .../next/Security/2018-09-10-16-05-39.bpo-34623.Ua9jMv.rst | 2 ++ + Modules/_elementtree.c | 5 +++++ + Modules/pyexpat.c | 5 +++++ + 4 files changed, 15 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2018-09-10-16-05-39.bpo-34623.Ua9jMv.rst + +--- a/Include/pyexpat.h ++++ b/Include/pyexpat.h +@@ -3,7 +3,7 @@ + + /* note: you must import expat.h before importing this module! */ + +-#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" ++#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.1" + #define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" + + struct PyExpat_CAPI +@@ -48,6 +48,8 @@ + enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); + int (*DefaultUnknownEncodingHandler)( + void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); ++ /* might be none for expat < 2.1.0 */ ++ int (*SetHashSalt)(XML_Parser parser, unsigned long hash_salt); + /* always add new stuff to the end! */ + }; + +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2018-09-10-16-05-39.bpo-34623.Ua9jMv.rst +@@ -0,0 +1,2 @@ ++The C accelerated _elementtree module now initializes hash randomization ++salt from _Py_HashSecret instead of libexpat's default CSPRNG. +--- a/Modules/_elementtree.c ++++ b/Modules/_elementtree.c +@@ -3239,6 +3239,11 @@ + PyErr_NoMemory(); + return -1; + } ++ /* expat < 2.1.0 has no XML_SetHashSalt() */ ++ if (EXPAT(SetHashSalt) != NULL) { ++ EXPAT(SetHashSalt)(self->parser, ++ (unsigned long)_Py_HashSecret.expat.hashsalt); ++ } + + if (target) { + Py_INCREF(target); +--- a/Modules/pyexpat.c ++++ b/Modules/pyexpat.c +@@ -1959,6 +1959,11 @@ + capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler; + capi.SetEncoding = XML_SetEncoding; + capi.DefaultUnknownEncodingHandler = PyUnknownEncodingHandler; ++#if XML_COMBINED_VERSION >= 20100 ++ capi.SetHashSalt = XML_SetHashSalt; ++#else ++ capi.SetHashSalt = NULL; ++#endif + + /* export using capsule */ + capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL); only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2018-20406.patch +++ python3.4-3.4.2/debian/patches/CVE-2018-20406.patch @@ -0,0 +1,186 @@ +From 71a9c65e74a70b6ed39adc4ba81d311ac1aa2acc Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-isling...@users.noreply.github.com> +Date: Thu, 20 Sep 2018 19:00:37 -0700 +Subject: [PATCH] closes bpo-34656: Avoid relying on signed overflow in _pickle + memos. (GH-9261) + +(cherry picked from commit a4ae828ee416a66d8c7bf5ee71d653c2cc6a26dd) + +Co-authored-by: Benjamin Peterson <benja...@python.org> +--- + Modules/_pickle.c | 62 +++++++++++++++++++++++------------------------ + 1 file changed, 31 insertions(+), 31 deletions(-) + +--- a/Modules/_pickle.c ++++ b/Modules/_pickle.c +@@ -518,9 +518,9 @@ + } PyMemoEntry; + + typedef struct { +- Py_ssize_t mt_mask; +- Py_ssize_t mt_used; +- Py_ssize_t mt_allocated; ++ size_t mt_mask; ++ size_t mt_used; ++ size_t mt_allocated; + PyMemoEntry *mt_table; + } PyMemoTable; + +@@ -564,8 +564,8 @@ + /* The unpickler memo is just an array of PyObject *s. Using a dict + is unnecessary, since the keys are contiguous ints. */ + PyObject **memo; +- Py_ssize_t memo_size; /* Capacity of the memo array */ +- Py_ssize_t memo_len; /* Number of objects in the memo */ ++ size_t memo_size; /* Capacity of the memo array */ ++ size_t memo_len; /* Number of objects in the memo */ + + PyObject *pers_func; /* persistent_load() method, can be NULL. */ + +@@ -649,7 +649,7 @@ + static PyMemoTable * + PyMemoTable_Copy(PyMemoTable *self) + { +- Py_ssize_t i; ++ size_t i; + PyMemoTable *new = PyMemoTable_New(); + if (new == NULL) + return NULL; +@@ -712,7 +712,7 @@ + { + size_t i; + size_t perturb; +- size_t mask = (size_t)self->mt_mask; ++ size_t mask = self->mt_mask; + PyMemoEntry *table = self->mt_table; + PyMemoEntry *entry; + Py_hash_t hash = (Py_hash_t)key >> 3; +@@ -734,22 +734,24 @@ + + /* Returns -1 on failure, 0 on success. */ + static int +-_PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size) ++_PyMemoTable_ResizeTable(PyMemoTable *self, size_t min_size) + { + PyMemoEntry *oldtable = NULL; + PyMemoEntry *oldentry, *newentry; +- Py_ssize_t new_size = MT_MINSIZE; +- Py_ssize_t to_process; ++ size_t new_size = MT_MINSIZE; ++ size_t to_process; + + assert(min_size > 0); + +- /* Find the smallest valid table size >= min_size. */ +- while (new_size < min_size && new_size > 0) +- new_size <<= 1; +- if (new_size <= 0) { ++ if (min_size > PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return -1; + } ++ ++ /* Find the smallest valid table size >= min_size. */ ++ while (new_size < min_size) { ++ new_size <<= 1; ++ } + /* new_size needs to be a power of two. */ + assert((new_size & (new_size - 1)) == 0); + +@@ -799,6 +801,7 @@ + PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value) + { + PyMemoEntry *entry; ++ size_t desired_size; + + assert(key != NULL); + +@@ -822,10 +825,12 @@ + * Very large memo tables (over 50K items) use doubling instead. + * This may help applications with severe memory constraints. + */ +- if (!(self->mt_used * 3 >= (self->mt_mask + 1) * 2)) ++ if (SIZE_MAX / 3 >= self->mt_used && self->mt_used * 3 < self->mt_allocated * 2) { + return 0; +- return _PyMemoTable_ResizeTable(self, +- (self->mt_used > 50000 ? 2 : 4) * self->mt_used); ++ } ++ // self->mt_used is always < PY_SSIZE_T_MAX, so this can't overflow. ++ desired_size = (self->mt_used > 50000 ? 2 : 4) * self->mt_used; ++ return _PyMemoTable_ResizeTable(self, desired_size); + } + + #undef MT_MINSIZE +@@ -1258,9 +1263,9 @@ + /* Returns -1 (with an exception set) on failure, 0 on success. The memo array + will be modified in place. */ + static int +-_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size) ++_Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size) + { +- Py_ssize_t i; ++ size_t i; + PyObject **memo; + + assert(new_size > self->memo_size); +@@ -1279,9 +1284,9 @@ + + /* Returns NULL if idx is out of bounds. */ + static PyObject * +-_Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx) ++_Unpickler_MemoGet(UnpicklerObject *self, size_t idx) + { +- if (idx < 0 || idx >= self->memo_size) ++ if (idx >= self->memo_size) + return NULL; + + return self->memo[idx]; +@@ -1290,7 +1295,7 @@ + /* Returns -1 (with an exception set) on failure, 0 on success. + This takes its own reference to `value`. */ + static int +-_Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value) ++_Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value) + { + PyObject *old_item; + +@@ -4097,7 +4102,7 @@ + _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) + /*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/ + { +- Py_ssize_t i; ++ size_t i; + PyMemoTable *memo; + PyObject *new_memo = PyDict_New(); + if (new_memo == NULL) +@@ -6472,7 +6477,7 @@ + _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) + /*[clinic end generated code: output=e12af7e9bc1e4c77 input=97769247ce032c1d]*/ + { +- Py_ssize_t i; ++ size_t i; + PyObject *new_memo = PyDict_New(); + if (new_memo == NULL) + return NULL; +@@ -6623,8 +6628,8 @@ + Unpickler_set_memo(UnpicklerObject *self, PyObject *obj) + { + PyObject **new_memo; +- Py_ssize_t new_memo_size = 0; +- Py_ssize_t i; ++ size_t new_memo_size = 0; ++ size_t i; + + if (obj == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -6689,8 +6694,7 @@ + + error: + if (new_memo_size) { +- i = new_memo_size; +- while (--i >= 0) { ++ for (i = new_memo_size - 1; i != SIZE_MAX; i--) { + Py_XDECREF(new_memo[i]); + } + PyMem_FREE(new_memo); only in patch2: unchanged: --- python3.4-3.4.2.orig/debian/patches/CVE-2019-5010.patch +++ python3.4-3.4.2/debian/patches/CVE-2019-5010.patch @@ -0,0 +1,108 @@ +From 216a4d83c3b72f4fdcd81b588dc3f42cc461739a Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-isling...@users.noreply.github.com> +Date: Tue, 15 Jan 2019 17:16:36 -0800 +Subject: [PATCH] bpo-35746: Fix segfault in ssl's cert parser (GH-11569) + (GH-11573) + +Fix a NULL pointer deref in ssl module. The cert parser did not handle CRL +distribution points with empty DP or URI correctly. A malicious or buggy +certificate can result into segfault. + +Signed-off-by: Christian Heimes <christ...@python.org> + +https://bugs.python.org/issue35746 +(cherry picked from commit a37f52436f9aa4b9292878b72f3ff1480e2606c3) + +Co-authored-by: Christian Heimes <christ...@python.org> +--- + Lib/test/talos-2019-0758.pem | 22 +++++++++++++++++++ + Lib/test/test_ssl.py | 22 +++++++++++++++++++ + .../2019-01-15-18-16-05.bpo-35746.nMSd0j.rst | 3 +++ + Modules/_ssl.c | 4 ++++ + 4 files changed, 51 insertions(+) + create mode 100644 Lib/test/talos-2019-0758.pem + create mode 100644 Misc/NEWS.d/next/Security/2019-01-15-18-16-05.bpo-35746.nMSd0j.rst + +--- /dev/null ++++ b/Lib/test/talos-2019-0758.pem +@@ -0,0 +1,22 @@ ++-----BEGIN CERTIFICATE----- ++MIIDqDCCApKgAwIBAgIBAjALBgkqhkiG9w0BAQswHzELMAkGA1UEBhMCVUsxEDAO ++BgNVBAMTB2NvZHktY2EwHhcNMTgwNjE4MTgwMDU4WhcNMjgwNjE0MTgwMDU4WjA7 ++MQswCQYDVQQGEwJVSzEsMCoGA1UEAxMjY29kZW5vbWljb24tdm0tMi50ZXN0Lmxh ++bC5jaXNjby5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC63fGB ++J80A9Av1GB0bptslKRIUtJm8EeEu34HkDWbL6AJY0P8WfDtlXjlPaLqFa6sqH6ES ++V48prSm1ZUbDSVL8R6BYVYpOlK8/48xk4pGTgRzv69gf5SGtQLwHy8UPBKgjSZoD ++5a5k5wJXGswhKFFNqyyxqCvWmMnJWxXTt2XDCiWc4g4YAWi4O4+6SeeHVAV9rV7C ++1wxqjzKovVe2uZOHjKEzJbbIU6JBPb6TRfMdRdYOw98n1VXDcKVgdX2DuuqjCzHP ++WhU4Tw050M9NaK3eXp4Mh69VuiKoBGOLSOcS8reqHIU46Reg0hqeL8LIL6OhFHIF ++j7HR6V1X6F+BfRS/AgMBAAGjgdYwgdMwCQYDVR0TBAIwADAdBgNVHQ4EFgQUOktp ++HQjxDXXUg8prleY9jeLKeQ4wTwYDVR0jBEgwRoAUx6zgPygZ0ZErF9sPC4+5e2Io ++UU+hI6QhMB8xCzAJBgNVBAYTAlVLMRAwDgYDVQQDEwdjb2R5LWNhggkA1QEAuwb7 ++2s0wCQYDVR0SBAIwADAuBgNVHREEJzAlgiNjb2Rlbm9taWNvbi12bS0yLnRlc3Qu ++bGFsLmNpc2NvLmNvbTAOBgNVHQ8BAf8EBAMCBaAwCwYDVR0fBAQwAjAAMAsGCSqG ++SIb3DQEBCwOCAQEAvqantx2yBlM11RoFiCfi+AfSblXPdrIrHvccepV4pYc/yO6p ++t1f2dxHQb8rWH3i6cWag/EgIZx+HJQvo0rgPY1BFJsX1WnYf1/znZpkUBGbVmlJr ++t/dW1gSkNS6sPsM0Q+7HPgEv8CPDNK5eo7vU2seE0iWOkxSyVUuiCEY9ZVGaLVit ++p0C78nZ35Pdv4I+1cosmHl28+es1WI22rrnmdBpH8J1eY6WvUw2xuZHLeNVN0TzV ++Q3qq53AaCWuLOD1AjESWuUCxMZTK9DPS4JKXTK8RLyDeqOvJGjsSWp3kL0y3GaQ+ ++10T1rfkKJub2+m9A9duin1fn6tHc2wSvB7m3DA== ++-----END CERTIFICATE----- +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -64,6 +64,7 @@ + BADKEY = data_file("badkey.pem") + NOKIACERT = data_file("nokia.pem") + NULLBYTECERT = data_file("nullbytecert.pem") ++TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem") + + DHFILE = data_file("dh512.pem") + BYTES_DHFILE = os.fsencode(DHFILE) +@@ -230,6 +231,27 @@ + self.assertEqual(p['crlDistributionPoints'], + ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) + ++ def test_parse_cert_CVE_2019_5010(self): ++ p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP) ++ if support.verbose: ++ sys.stdout.write("\n" + pprint.pformat(p) + "\n") ++ self.assertEqual( ++ p, ++ { ++ 'issuer': ( ++ (('countryName', 'UK'),), (('commonName', 'cody-ca'),)), ++ 'notAfter': 'Jun 14 18:00:58 2028 GMT', ++ 'notBefore': 'Jun 18 18:00:58 2018 GMT', ++ 'serialNumber': '02', ++ 'subject': ((('countryName', 'UK'),), ++ (('commonName', ++ 'codenomicon-vm-2.test.lal.cisco.com'),)), ++ 'subjectAltName': ( ++ ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),), ++ 'version': 3 ++ } ++ ) ++ + def test_parse_cert_CVE_2013_4238(self): + p = ssl._ssl._test_decode_cert(NULLBYTECERT) + if support.verbose: +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2019-01-15-18-16-05.bpo-35746.nMSd0j.rst +@@ -0,0 +1,3 @@ ++[CVE-2019-5010] Fix a NULL pointer deref in ssl module. The cert parser did ++not handle CRL distribution points with empty DP or URI correctly. A ++malicious or buggy certificate can result into segfault. +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -1052,6 +1052,10 @@ + STACK_OF(GENERAL_NAME) *gns; + + dp = sk_DIST_POINT_value(dps, i); ++ if (dp->distpoint == NULL) { ++ /* Ignore empty DP value, CVE-2019-5010 */ ++ continue; ++ } + gns = dp->distpoint->name.fullname; + + for (j=0; j < sk_GENERAL_NAME_num(gns); j++) {