#32 Add OpenSSL 1.1.1 support
Merged 2 months ago by cstratak. Opened 6 months ago by vstinner.
rpms/ vstinner/python34 openssl111  into  master

@@ -0,0 +1,816 @@ 

+ From 55ffb704cc17d41ddf8f34aac3de5f218cd43dee Mon Sep 17 00:00:00 2001

+ From: Christian Heimes <christian@python.org>

+ Date: Mon, 5 Sep 2016 23:19:05 +0200

+ Subject: [PATCH] bpo-26470: Port ssl and hashlib module to OpenSSL 1.1.0.

+ 

+ Backport notes

+ 

+ * Don't add PROTOCOL_TLS

+ * Ignore documentation changes

+ 

+ (cherry picked from commit 598894ff48e9c1171cb2ec1c798235826a75c7e0)

+ 

+ diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py

+ index e36a309..401cc2f 100644

+ --- a/Lib/test/test_ssl.py

+ +++ b/Lib/test/test_ssl.py

+ @@ -23,6 +23,8 @@ ssl = support.import_module("ssl")

+  

+  PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)

+  HOST = support.HOST

+ +IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')

+ +

+  

+  def data_file(*name):

+      return os.path.join(os.path.dirname(__file__), *name)

+ @@ -318,9 +320,9 @@ class BasicSocketTests(unittest.TestCase):

+          self.assertGreaterEqual(status, 0)

+          self.assertLessEqual(status, 15)

+          # Version string as returned by {Open,Libre}SSL, the format might change

+ -        if "LibreSSL" in s:

+ -            self.assertTrue(s.startswith("LibreSSL {:d}.{:d}".format(major, minor)),

+ -                            (s, t))

+ +        if IS_LIBRESSL:

+ +            self.assertTrue(s.startswith("LibreSSL {:d}".format(major)),

+ +                            (s, t, hex(n)))

+          else:

+              self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),

+                              (s, t))

+ @@ -698,15 +700,15 @@ class ContextTests(unittest.TestCase):

+      def test_options(self):

+          ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

+          # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value

+ -        self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3,

+ -                         ctx.options)

+ +        default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)

+ +        if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0):

+ +            default |= ssl.OP_NO_COMPRESSION

+ +        self.assertEqual(default, ctx.options)

+          ctx.options |= ssl.OP_NO_TLSv1

+ -        self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1,

+ -                         ctx.options)

+ +        self.assertEqual(default | ssl.OP_NO_TLSv1, 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 = (ctx.options & ~ssl.OP_NO_TLSv1)

+ +            self.assertEqual(default, ctx.options)

+              ctx.options = 0

+              # Ubuntu has OP_NO_SSLv3 forced on by default

+              self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)

+ @@ -1042,6 +1044,7 @@ class ContextTests(unittest.TestCase):

+          self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')

+  

+      @unittest.skipIf(sys.platform == "win32", "not-Windows specific")

+ +    @unittest.skipIf(IS_LIBRESSL, "LibreSSL doesn't support env vars")

+      def test_load_default_certs_env(self):

+          ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

+          with support.EnvironmentVarGuard() as env:

+ diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c

+ index f494e77..6387c3f 100644

+ --- a/Modules/_hashopenssl.c

+ +++ b/Modules/_hashopenssl.c

+ @@ -38,10 +38,22 @@

+  #define _OPENSSL_SUPPORTS_SHA2

+  #endif

+  

+ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)

+ +/* OpenSSL < 1.1.0 */

+ +#define EVP_MD_CTX_new EVP_MD_CTX_create

+ +#define EVP_MD_CTX_free EVP_MD_CTX_destroy

+ +#define HAS_FAST_PKCS5_PBKDF2_HMAC 0

+ +#include <openssl/hmac.h>

+ +#else

+ +/* OpenSSL >= 1.1.0 */

+ +#define HAS_FAST_PKCS5_PBKDF2_HMAC 1

+ +#endif

+ +

+ +

+  typedef struct {

+      PyObject_HEAD

+      PyObject            *name;  /* name of this hash algorithm */

+ -    EVP_MD_CTX           ctx;   /* OpenSSL message digest context */

+ +    EVP_MD_CTX          *ctx;   /* OpenSSL message digest context */

+  #ifdef WITH_THREAD

+      PyThread_type_lock   lock;  /* OpenSSL context lock */

+  #endif

+ @@ -54,10 +66,10 @@ static PyTypeObject EVPtype;

+     We have one of these per algorithm */

+  typedef struct {

+      PyObject *name_obj;

+ -    EVP_MD_CTX ctxs[2];

+ +    EVP_MD_CTX* ctxs[2];

+      /* ctx_ptrs will point to ctxs unless an error occurred, when it will

+         be NULL: */

+ -    EVP_MD_CTX *ctx_ptrs[2];

+ +    int initialized[2];

+      PyObject *error_msgs[2];

+  } EVPCachedInfo;

+  

+ @@ -74,18 +86,57 @@ DEFINE_CONSTS_FOR_NEW(sha512)

+  #endif

+  

+  

+ +/* 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 */

+ +

+  static EVPobject *

+  newEVPobject(PyObject *name)

+  {

+      EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype);

+ +    if (retval == NULL) {

+ +        return NULL;

+ +    }

+  

+      /* save the name for .name to return */

+ -    if (retval != NULL) {

+ -        Py_INCREF(name);

+ -        retval->name = name;

+ +    Py_INCREF(name);

+ +    retval->name = name;

+  #ifdef WITH_THREAD

+ -        retval->lock = NULL;

+ +    retval->lock = NULL;

+  #endif

+ +

+ +    retval->ctx = EVP_MD_CTX_new();

+ +    if (retval->ctx == NULL) {

+ +        Py_DECREF(retval);

+ +        PyErr_NoMemory();

+ +        return NULL;

+      }

+  

+      return retval;

+ @@ -101,7 +152,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)

+              process = MUNCH_SIZE;

+          else

+              process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);

+ -        EVP_DigestUpdate(&self->ctx, (const void*)cp, process);

+ +        EVP_DigestUpdate(self->ctx, (const void*)cp, process);

+          len -= process;

+          cp += process;

+      }

+ @@ -158,16 +209,19 @@ EVP_dealloc(EVPobject *self)

+      if (self->lock != NULL)

+          PyThread_free_lock(self->lock);

+  #endif

+ -    EVP_MD_CTX_cleanup(&self->ctx);

+ +    EVP_MD_CTX_free(self->ctx);

+      Py_XDECREF(self->name);

+      PyObject_Del(self);

+  }

+  

+ -static void locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self)

+ +static int

+ +locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self)

+  {

+ +    int result;

+      ENTER_HASHLIB(self);

+ -    EVP_MD_CTX_copy(new_ctx_p, &self->ctx);

+ +    result = EVP_MD_CTX_copy(new_ctx_p, self->ctx);

+      LEAVE_HASHLIB(self);

+ +    return result;

+  }

+  

+  /* External methods for a hash object */

+ @@ -183,7 +237,9 @@ EVP_copy(EVPobject *self, PyObject *unused)

+      if ( (newobj = newEVPobject(self->name))==NULL)

+          return NULL;

+  

+ -    locked_EVP_MD_CTX_copy(&newobj->ctx, self);

+ +    if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {

+ +        return _setException(PyExc_ValueError);

+ +    }

+      return (PyObject *)newobj;

+  }

+  

+ @@ -194,16 +250,24 @@ static PyObject *

+  EVP_digest(EVPobject *self, PyObject *unused)

+  {

+      unsigned char digest[EVP_MAX_MD_SIZE];

+ -    EVP_MD_CTX temp_ctx;

+ +    EVP_MD_CTX *temp_ctx;

+      PyObject *retval;

+      unsigned int digest_size;

+  

+ -    locked_EVP_MD_CTX_copy(&temp_ctx, self);

+ -    digest_size = EVP_MD_CTX_size(&temp_ctx);

+ -    EVP_DigestFinal(&temp_ctx, digest, NULL);

+ +    temp_ctx = EVP_MD_CTX_new();

+ +    if (temp_ctx == NULL) {

+ +        PyErr_NoMemory();

+ +        return NULL;

+ +    }

+ +

+ +    if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {

+ +        return _setException(PyExc_ValueError);

+ +    }

+ +    digest_size = EVP_MD_CTX_size(temp_ctx);

+ +    EVP_DigestFinal(temp_ctx, digest, NULL);

+  

+      retval = PyBytes_FromStringAndSize((const char *)digest, digest_size);

+ -    EVP_MD_CTX_cleanup(&temp_ctx);

+ +    EVP_MD_CTX_free(temp_ctx);

+      return retval;

+  }

+  

+ @@ -214,17 +278,25 @@ static PyObject *

+  EVP_hexdigest(EVPobject *self, PyObject *unused)

+  {

+      unsigned char digest[EVP_MAX_MD_SIZE];

+ -    EVP_MD_CTX temp_ctx;

+ +    EVP_MD_CTX *temp_ctx;

+      PyObject *retval;

+      char *hex_digest;

+      unsigned int i, j, digest_size;

+  

+ +    temp_ctx = EVP_MD_CTX_new();

+ +    if (temp_ctx == NULL) {

+ +        PyErr_NoMemory();

+ +        return NULL;

+ +    }

+ +

+      /* Get the raw (binary) digest value */

+ -    locked_EVP_MD_CTX_copy(&temp_ctx, self);

+ -    digest_size = EVP_MD_CTX_size(&temp_ctx);

+ -    EVP_DigestFinal(&temp_ctx, digest, NULL);

+ +    if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {

+ +        return _setException(PyExc_ValueError);

+ +    }

+ +    digest_size = EVP_MD_CTX_size(temp_ctx);

+ +    EVP_DigestFinal(temp_ctx, digest, NULL);

+  

+ -    EVP_MD_CTX_cleanup(&temp_ctx);

+ +    EVP_MD_CTX_free(temp_ctx);

+  

+      /* Allocate a new buffer */

+      hex_digest = PyMem_Malloc(digest_size * 2 + 1);

+ @@ -293,7 +365,7 @@ static PyObject *

+  EVP_get_block_size(EVPobject *self, void *closure)

+  {

+      long block_size;

+ -    block_size = EVP_MD_CTX_block_size(&self->ctx);

+ +    block_size = EVP_MD_CTX_block_size(self->ctx);

+      return PyLong_FromLong(block_size);

+  }

+  

+ @@ -301,7 +373,7 @@ static PyObject *

+  EVP_get_digest_size(EVPobject *self, void *closure)

+  {

+      long size;

+ -    size = EVP_MD_CTX_size(&self->ctx);

+ +    size = EVP_MD_CTX_size(self->ctx);

+      return PyLong_FromLong(size);

+  }

+  

+ @@ -363,8 +435,8 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)

+              PyBuffer_Release(&view);

+          return -1;

+      }

+ -    mc_ctx_init(&self->ctx, usedforsecurity);

+ -    if (!EVP_DigestInit_ex(&self->ctx, digest, NULL)) {

+ +    mc_ctx_init(self->ctx, usedforsecurity);

+ +    if (!EVP_DigestInit_ex(self->ctx, digest, NULL)) {

+          set_evp_exception();

+          PyBuffer_Release(&view);

+          return -1;

+ @@ -466,10 +538,10 @@ EVPnew(PyObject *name_obj,

+          return NULL;

+  

+      if (initial_ctx) {

+ -        EVP_MD_CTX_copy(&self->ctx, initial_ctx);

+ +        EVP_MD_CTX_copy(self->ctx, initial_ctx);

+      } else {

+ -        mc_ctx_init(&self->ctx, usedforsecurity);

+ -        if (!EVP_DigestInit_ex(&self->ctx, digest, NULL)) {

+ +        mc_ctx_init(self->ctx, usedforsecurity);

+ +        if (!EVP_DigestInit_ex(self->ctx, digest, NULL)) {

+              set_evp_exception();

+              Py_DECREF(self);

+              return NULL;

+ @@ -548,6 +620,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)

+  

+  #define PY_PBKDF2_HMAC 1

+  

+ +#if !HAS_FAST_PKCS5_PBKDF2_HMAC

+  /* Improved implementation of PKCS5_PBKDF2_HMAC()

+   *

+   * PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of

+ @@ -629,37 +702,8 @@ PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen,

+      HMAC_CTX_cleanup(&hctx_tpl);

+      return 1;

+  }

+ +#endif

+  

+ -/* 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\

+ @@ -741,10 +785,17 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)

+      key = PyBytes_AS_STRING(key_obj);

+  

+      Py_BEGIN_ALLOW_THREADS

+ +#if HAS_FAST_PKCS5_PBKDF2_HMAC

+ +    retval = PKCS5_PBKDF2_HMAC((char*)password.buf, (int)password.len,

+ +                               (unsigned char *)salt.buf, (int)salt.len,

+ +                               iterations, digest, dklen,

+ +                               (unsigned char *)key);

+ +#else

+      retval = PKCS5_PBKDF2_HMAC_fast((char*)password.buf, (int)password.len,

+                                      (unsigned char *)salt.buf, (int)salt.len,

+                                      iterations, digest, dklen,

+                                      (unsigned char *)key);

+ +#endif

+      Py_END_ALLOW_THREADS

+  

+      if (!retval) {

+ @@ -860,11 +911,11 @@ implement_specific_EVP_new(PyObject *self, PyObject *args, PyObject *kwdict,

+       * If an error occurred during creation of the global content, the ctx_ptr

+       * will be NULL, and the error_msg will hopefully be non-NULL:

+       */

+ -    if (cached_info->ctx_ptrs[idx]) {

+ +    if (cached_info->initialized[idx]) {

+          /* We successfully initialized this context; copy it: */

+          ret_obj = EVPnew(cached_info->name_obj,

+                           NULL,

+ -                         cached_info->ctx_ptrs[idx],

+ +                         cached_info->ctxs[idx],

+                           (unsigned char*)view.buf, view.len,

+                           usedforsecurity);

+      } else {

+ @@ -897,14 +948,11 @@ implement_specific_EVP_new(PyObject *self, PyObject *args, PyObject *kwdict,

+  

+    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

+ -  entry, and err_msgs will be set (unless we're very low on memory)

+ +

+ +  Any that have errors during initialization will end up with initialized[i]

+ +  set to 0 and err_msgs being set.

+  */

+ -#define INIT_CONSTRUCTOR_CONSTANTS(NAME)  do {    \

+ -    init_constructor_constant(&cached_info_ ## NAME, #NAME); \

+ -} while (0);

+ -static void

+ +static int

+  init_constructor_constant(EVPCachedInfo *cached_info, const char *name)

+  {

+      assert(cached_info);

+ @@ -912,18 +960,25 @@ init_constructor_constant(EVPCachedInfo *cached_info, const char *name)

+      if (EVP_get_digestbyname(name)) {

+          int i;

+          for (i=0; i<2; i++) {

+ -            mc_ctx_init(&cached_info->ctxs[i], i);

+ -            if (EVP_DigestInit_ex(&cached_info->ctxs[i],

+ -                                  EVP_get_digestbyname(name), NULL)) {

+ +            cached_info->ctxs[i] = EVP_MD_CTX_new();

+ +            if (cached_info->ctxs[i] == NULL) {

+ +                PyErr_NoMemory();

+ +                return -1;

+ +            }

+ +

+ +            mc_ctx_init(cached_info->ctxs[i], i);

+ +            if (EVP_DigestInit(cached_info->ctxs[i],

+ +                        EVP_get_digestbyname(name))) {

+                  /* Success: */

+ -                cached_info->ctx_ptrs[i] = &cached_info->ctxs[i];

+ +                cached_info->initialized[i] = 1;

+              } else {

+                  /* Failure: */

+ -              cached_info->ctx_ptrs[i] = NULL;

+ -              cached_info->error_msgs[i] = error_msg_for_last_error();

+ +                cached_info->error_msgs[i] = error_msg_for_last_error();

+ +                cached_info->initialized[i] = 0;

+              }

+          }

+      }

+ +    return 0;

+  }

+  

+  

+ @@ -1002,6 +1057,13 @@ PyInit__hashlib(void)

+      Py_INCREF((PyObject *)&EVPtype);

+      PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);

+  

+ +#define INIT_CONSTRUCTOR_CONSTANTS(NAME)  \

+ +    do { \

+ +        if (init_constructor_constant(&cached_info_ ## NAME, #NAME) < 0) { \

+ +            return NULL; \

+ +        } \

+ +    } while (0);

+ +

+      /* these constants are used by the convenience constructors */

+      INIT_CONSTRUCTOR_CONSTANTS(md5);

+      INIT_CONSTRUCTOR_CONSTANTS(sha1);

+ diff --git a/Modules/_ssl.c b/Modules/_ssl.c

+ index 0ff9d55..c94cdc3 100644

+ --- a/Modules/_ssl.c

+ +++ b/Modules/_ssl.c

+ @@ -55,6 +55,14 @@ static PySocketModule_APIObject PySocketModule;

+  #include <sys/poll.h>

+  #endif

+  

+ +/* Don't warn about deprecated functions */

+ +#ifdef __GNUC__

+ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

+ +#endif

+ +#ifdef __clang__

+ +#pragma clang diagnostic ignored "-Wdeprecated-declarations"

+ +#endif

+ +

+  /* Include OpenSSL header files */

+  #include "openssl/rsa.h"

+  #include "openssl/crypto.h"

+ @@ -90,6 +98,10 @@ struct py_ssl_library_code {

+  /* Include generated data (error codes) */

+  #include "_ssl_data.h"

+  

+ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)

+ +#  define OPENSSL_VERSION_1_1 1

+ +#endif

+ +

+  /* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1

+      http://www.openssl.org/news/changelog.html

+   */

+ @@ -108,6 +120,72 @@ struct py_ssl_library_code {

+  # define HAVE_SNI 0

+  #endif

+  

+ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation

+ +# define HAVE_ALPN

+ +#endif

+ +

+ +#ifndef INVALID_SOCKET /* MS defines this */

+ +#define INVALID_SOCKET (-1)

+ +#endif

+ +

+ +#ifdef OPENSSL_VERSION_1_1

+ +/* OpenSSL 1.1.0+ */

+ +#ifndef OPENSSL_NO_SSL2

+ +#define OPENSSL_NO_SSL2

+ +#endif

+ +#else /* OpenSSL < 1.1.0 */

+ +#if defined(WITH_THREAD)

+ +#define HAVE_OPENSSL_CRYPTO_LOCK

+ +#endif

+ +

+ +static int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne)

+ +{

+ +    return ne->set;

+ +}

+ +

+ +#ifndef OPENSSL_NO_COMP

+ +static int COMP_get_type(const COMP_METHOD *meth)

+ +{

+ +    return meth->type;

+ +}

+ +

+ +static const char *COMP_get_name(const COMP_METHOD *meth)

+ +{

+ +    return meth->name;

+ +}

+ +#endif

+ +

+ +static pem_password_cb *SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)

+ +{

+ +    return ctx->default_passwd_callback;

+ +}

+ +

+ +static void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)

+ +{

+ +    return ctx->default_passwd_callback_userdata;

+ +}

+ +

+ +static int X509_OBJECT_get_type(X509_OBJECT *x)

+ +{

+ +    return x->type;

+ +}

+ +

+ +static X509 *X509_OBJECT_get0_X509(X509_OBJECT *x)

+ +{

+ +    return x->data.x509;

+ +}

+ +

+ +static STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *store) {

+ +    return store->objs;

+ +}

+ +

+ +static X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *store)

+ +{

+ +    return store->param;

+ +}

+ +#endif /* OpenSSL < 1.1.0 or LibreSSL */

+ +

+ +

+  enum py_ssl_error {

+      /* these mirror ssl.h */

+      PY_SSL_ERROR_NONE,

+ @@ -691,7 +769,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname)

+  

+          /* check to see if we've gotten to a new RDN */

+          if (rdn_level >= 0) {

+ -            if (rdn_level != entry->set) {

+ +            if (rdn_level != X509_NAME_ENTRY_set(entry)) {

+                  /* yes, new RDN */

+                  /* add old RDN to DN */

+                  rdnt = PyList_AsTuple(rdn);

+ @@ -708,7 +786,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname)

+                      goto fail0;

+              }

+          }

+ -        rdn_level = entry->set;

+ +        rdn_level = X509_NAME_ENTRY_set(entry);

+  

+          /* now add this attribute to the current RDN */

+          name = X509_NAME_ENTRY_get_object(entry);

+ @@ -811,18 +889,18 @@ _get_peer_alt_names (X509 *certificate) {

+              goto fail;

+          }

+  

+ -        p = ext->value->data;

+ +        p = X509_EXTENSION_get_data(ext)->data;

+          if (method->it)

+              names = (GENERAL_NAMES*)

+                (ASN1_item_d2i(NULL,

+                               &p,

+ -                             ext->value->length,

+ +                             X509_EXTENSION_get_data(ext)->length,

+                               ASN1_ITEM_ptr(method->it)));

+          else

+              names = (GENERAL_NAMES*)

+                (method->d2i(NULL,

+                             &p,

+ -                           ext->value->length));

+ +                           X509_EXTENSION_get_data(ext)->length));

+  

+          for(j = 0; j < sk_GENERAL_NAME_num(names); j++) {

+              /* get a rendering of each name in the set of names */

+ @@ -1033,13 +1111,11 @@ _get_crl_dp(X509 *certificate) {

+      int i, j;

+      PyObject *lst, *res = NULL;

+  

+ -#if OPENSSL_VERSION_NUMBER < 0x10001000L

+ -    dps = X509_get_ext_d2i(certificate, NID_crl_distribution_points, NULL, NULL);

+ -#else

+ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L

+      /* Calls x509v3_cache_extensions and sets up crldp */

+      X509_check_ca(certificate);

+ -    dps = certificate->crldp;

+  #endif

+ +    dps = X509_get_ext_d2i(certificate, NID_crl_distribution_points, NULL, NULL);

+  

+      if (dps == NULL)

+          return Py_None;

+ @@ -1431,9 +1507,9 @@ static PyObject *PySSL_compression(PySSLSocket *self) {

+      if (self->ssl == NULL)

+          Py_RETURN_NONE;

+      comp_method = SSL_get_current_compression(self->ssl);

+ -    if (comp_method == NULL || comp_method->type == NID_undef)

+ +    if (comp_method == NULL || COMP_get_type(comp_method) == NID_undef)

+          Py_RETURN_NONE;

+ -    short_name = OBJ_nid2sn(comp_method->type);

+ +    short_name = COMP_get_name(comp_method);

+      if (short_name == NULL)

+          Py_RETURN_NONE;

+      return PyUnicode_DecodeFSDefault(short_name);

+ @@ -2051,8 +2127,9 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)

+  #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)

+ +       policy, so we should be safe. OpenSSL 1.1 has it enabled by default.

+ +     */

+ +#if defined(SSL_CTX_set_ecdh_auto) && !defined(OPENSSL_VERSION_1_1)

+      SSL_CTX_set_ecdh_auto(self->ctx, 1);

+  #else

+      {

+ @@ -2263,10 +2340,12 @@ static PyObject *

+  get_verify_flags(PySSLContext *self, void *c)

+  {

+      X509_STORE *store;

+ +    X509_VERIFY_PARAM *param;

+      unsigned long flags;

+  

+      store = SSL_CTX_get_cert_store(self->ctx);

+ -    flags = X509_VERIFY_PARAM_get_flags(store->param);

+ +    param = X509_STORE_get0_param(store);

+ +    flags = X509_VERIFY_PARAM_get_flags(param);

+      return PyLong_FromUnsignedLong(flags);

+  }

+  

+ @@ -2274,22 +2353,24 @@ static int

+  set_verify_flags(PySSLContext *self, PyObject *arg, void *c)

+  {

+      X509_STORE *store;

+ +    X509_VERIFY_PARAM *param;

+      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);

+ +    param = X509_STORE_get0_param(store);

+ +    flags = X509_VERIFY_PARAM_get_flags(param);

+      clear = flags & ~new_flags;

+      set = ~flags & new_flags;

+      if (clear) {

+ -        if (!X509_VERIFY_PARAM_clear_flags(store->param, clear)) {

+ +        if (!X509_VERIFY_PARAM_clear_flags(param, clear)) {

+              _setSSLError(NULL, 0, __FILE__, __LINE__);

+              return -1;

+          }

+      }

+      if (set) {

+ -        if (!X509_VERIFY_PARAM_set_flags(store->param, set)) {

+ +        if (!X509_VERIFY_PARAM_set_flags(param, set)) {

+              _setSSLError(NULL, 0, __FILE__, __LINE__);

+              return -1;

+          }

+ @@ -2459,8 +2540,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)

+      char *kwlist[] = {"certfile", "keyfile", "password", NULL};

+      PyObject *certfile, *keyfile = NULL, *password = NULL;

+      PyObject *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;

+ +    pem_password_cb *orig_passwd_cb = SSL_CTX_get_default_passwd_cb(self->ctx);

+ +    void *orig_passwd_userdata = SSL_CTX_get_default_passwd_cb_userdata(self->ctx);

+      _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 };

+      int r;

+  

+ @@ -2591,8 +2672,9 @@ _add_ca_certs(PySSLContext *self, void *data, Py_ssize_t len,

+              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);

+ +                                     SSL_CTX_get_default_passwd_cb(self->ctx),

+ +                                     SSL_CTX_get_default_passwd_cb_userdata(self->ctx)

+ +                                    );

+          }

+          if (cert == NULL) {

+              break;

+ @@ -3040,25 +3122,24 @@ static PyObject *

+  cert_store_stats(PySSLContext *self)

+  {

+      X509_STORE *store;

+ +    STACK_OF(X509_OBJECT) *objs;

+      X509_OBJECT *obj;

+ -    int x509 = 0, crl = 0, pkey = 0, ca = 0, i;

+ +    int x509 = 0, crl = 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) {

+ +    objs = X509_STORE_get0_objects(store);

+ +    for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {

+ +        obj = sk_X509_OBJECT_value(objs, i);

+ +        switch (X509_OBJECT_get_type(obj)) {

+              case X509_LU_X509:

+                  x509++;

+ -                if (X509_check_ca(obj->data.x509)) {

+ +                if (X509_check_ca(X509_OBJECT_get0_X509(obj))) {

+                      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

+ @@ -3083,6 +3164,7 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds)

+  {

+      char *kwlist[] = {"binary_form", NULL};

+      X509_STORE *store;

+ +    STACK_OF(X509_OBJECT) *objs;

+      PyObject *ci = NULL, *rlist = NULL;

+      int i;

+      int binary_mode = 0;

+ @@ -3097,17 +3179,18 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds)

+      }

+  

+      store = SSL_CTX_get_cert_store(self->ctx);

+ -    for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) {

+ +    objs = X509_STORE_get0_objects(store);

+ +    for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {

+          X509_OBJECT *obj;

+          X509 *cert;

+  

+ -        obj = sk_X509_OBJECT_value(store->objs, i);

+ -        if (obj->type != X509_LU_X509) {

+ +        obj = sk_X509_OBJECT_value(objs, i);

+ +        if (X509_OBJECT_get_type(obj) != X509_LU_X509) {

+              /* not a x509 cert */

+              continue;

+          }

+          /* CA for any purpose */

+ -        cert = obj->data.x509;

+ +        cert = X509_OBJECT_get0_X509(obj);

+          if (!X509_check_ca(cert)) {

+              continue;

+          }

+ @@ -3780,10 +3863,12 @@ static PyMethodDef PySSL_methods[] = {

+  };

+  

+  

+ -#ifdef WITH_THREAD

+ +#ifdef HAVE_OPENSSL_CRYPTO_LOCK

+  

+  /* an implementation of OpenSSL threading operations in terms

+ -   of the Python C thread library */

+ + * of the Python C thread library

+ + * Only used up to 1.0.2. OpenSSL 1.1.0+ has its own locking code.

+ + */

+  

+  static PyThread_type_lock *_ssl_locks = NULL;

+  

+ @@ -3864,7 +3949,7 @@ static int _setup_ssl_threads(void) {

+      return 1;

+  }

+  

+ -#endif  /* def HAVE_THREAD */

+ +#endif  /* HAVE_OPENSSL_CRYPTO_LOCK for WITH_THREAD && OpenSSL < 1.1.0 */

+  

+  PyDoc_STRVAR(module_doc,

+  "Implementation module for SSL socket operations.  See the socket module\n\

+ @@ -3931,11 +4016,16 @@ PyInit__ssl(void)

+      SSL_load_error_strings();

+      SSL_library_init();

+  #ifdef WITH_THREAD

+ +#ifdef HAVE_OPENSSL_CRYPTO_LOCK

+      /* note that this will start threading if not already started */

+      if (!_setup_ssl_threads()) {

+          return NULL;

+      }

+ +#elif OPENSSL_VERSION_1_1 && defined(OPENSSL_THREADS)

+ +    /* OpenSSL 1.1.0 builtin thread support is enabled */

+ +    _ssl_locks_count++;

+  #endif

+ +#endif  /* WITH_THREAD */

+      OpenSSL_add_all_algorithms();

+  

+      /* Add symbols to module dict */

@@ -0,0 +1,67 @@ 

+ bpo-36576: Skip test_ssl and test_asyncio tests failing with OpenSSL 1.1.1

+ 

+ Some test_ssl and test_asyncio are written for OpenSSL 1.0 and TLS

+ 1.0, but fail with OpenSSL 1.1.1 and TLS 1.3.

+ 

+ Fixing these needs require to backport new ssl flags like

+ ssl.OP_NO_TLSv1_3 or ssl.OP_NO_COMPRESSION which cannot be done in a

+ minor 3.5.x release. Moreover, it is not really worth it: the code

+ works fine, issues are in the tests.

+ 

+ Backport of: https://github.com/python/cpython/pull/12694

+ 

+ Resolves: rhbz#1685609

+ 

+ diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py

+ index 6373618..3db3707 100644

+ --- a/Lib/test/test_asyncio/test_events.py

+ +++ b/Lib/test/test_asyncio/test_events.py

+ @@ -33,6 +33,12 @@ except ImportError:

+      from asyncio import test_support as support

+  

+  

+ +if ssl is not None:

+ +    IS_OPENSSL_1_1_1 = ssl.OPENSSL_VERSION_INFO >= (1, 1, 1)

+ +else:

+ +    IS_OPENSSL_1_1_1 = False

+ +

+ +

+  def data_file(filename):

+      if hasattr(support, 'TEST_HOME_DIR'):

+          fullname = os.path.join(support.TEST_HOME_DIR, filename)

+ @@ -1049,6 +1055,7 @@ class EventLoopTestsMixin:

+              self.test_create_unix_server_ssl_verify_failed()

+  

+      @unittest.skipIf(ssl is None, 'No ssl module')

+ +    @unittest.skipIf(IS_OPENSSL_1_1_1, "bpo-36576: fail on OpenSSL 1.1.1")

+      def test_create_server_ssl_match_failed(self):

+          proto = MyProto(loop=self.loop)

+          server, host, port = self._make_ssl_server(

+ diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py

+ index 401cc2f..8edf055 100644

+ --- a/Lib/test/test_ssl.py

+ +++ b/Lib/test/test_ssl.py

+ @@ -24,6 +24,7 @@ ssl = support.import_module("ssl")

+  PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)

+  HOST = support.HOST

+  IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')

+ +IS_OPENSSL_1_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 1)

+  

+  

+  def data_file(*name):

+ @@ -697,6 +698,7 @@ class ContextTests(unittest.TestCase):

+              ctx.set_ciphers("^$:,;?*'dorothyx")

+  

+      @skip_if_broken_ubuntu_ssl

+ +    @unittest.skipIf(IS_OPENSSL_1_1_1, "bpo-36576: fail on OpenSSL 1.1.1")

+      def test_options(self):

+          ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

+          # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value

+ @@ -2655,6 +2657,7 @@ else:

+              self.assertIn("no shared cipher", str(server.conn_errors[0]))

+  

+          @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")

+ +        @unittest.skipIf(IS_OPENSSL_1_1_1, "bpo-36576: fail on OpenSSL 1.1.1")

+          def test_default_ecdh_curve(self):

+              # Issue #21015: elliptic curve-based Diffie Hellman key exchange

+              # should be enabled by default on SSL contexts.

file modified
+18 -1

@@ -113,7 +113,7 @@ 

  #global prerel ...

  %global upstream_version %{general_version}%{?prerel}

  Version: %{general_version}%{?prerel:~%{prerel}}

- Release: 2%{?dist}

+ Release: 3%{?dist}

  License: Python

  

  # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package

@@ -510,6 +510,18 @@ 

  # https://bugzilla.redhat.com/show_bug.cgi?id=1652843

  Patch315: 00315-test_email-mktime.patch

  

+ # 00321 #

+ # OpenSSL 1.1.1 support for Python 3.4

+ # https://bugzilla.redhat.com/show_bug.cgi?id=1685612

+ # Rejected upstream https://github.com/python/cpython/pull/12211

+ # and Python 3.4 reached end-of-life.

+ Patch321: 00321-python34-openssl-1.1.1.patch

+ 

+ # 00322 #

+ # Skip test_ssl and test_asyncio tests failing with OpenSSL 1.1.1

+ # https://bugzilla.redhat.com/show_bug.cgi?id=1685609

+ Patch322: 00322-test_ssl-skip-openssl111.patch

+ 

  # (New patches go here ^^^)

  #

  # When adding new patches to "python" and "python3" in Fedora 17 onwards,

@@ -674,6 +686,8 @@ 

  %patch273 -p1

  %patch290 -p1

  %patch315 -p1

+ %patch321 -p1

+ %patch322 -p1

  

  # Currently (2010-01-15), http://docs.python.org/library is for 2.6, and there

  # are many differences between 2.6 and the Python 3 library.

@@ -1211,6 +1225,9 @@ 

  # ======================================================

  

  %changelog

+ * Wed Jul 31 2019 Victor Stinner <vstinner@redhat.com> - 3.4.10-3

+ - Add OpenSSL 1.1.1 support (rhbz#1685612)

+ 

  * Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.4.10-2

  - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild

  

Backport change from Python 3.5 to add OpenSSL 1.1.1 support.

Resolves: rhbz#1685612

+ echo 'Patch #321 (00321-python34-openssl-1.1.1.patch):'
+ /usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0
patching file Lib/test/test_ssl.py
patching file Misc/NEWS.d/next/Library/2019-03-07-15-39-52.bpo-26470.QGu_wo.rst
patching file Modules/_hashopenssl.c
Hunk #1 FAILED at 20.
Hunk #2 succeeded at 33 (offset 2 lines).
Hunk #3 FAILED at 58.
Hunk #4 succeeded at 81 (offset 10 lines).
Hunk #5 succeeded at 146 (offset 10 lines).
Hunk #6 succeeded at 203 (offset 52 lines).
Hunk #7 succeeded at 231 (offset 52 lines).
Hunk #8 succeeded at 244 (offset 52 lines).
Hunk #9 succeeded at 272 (offset 52 lines).
Hunk #10 succeeded at 359 (offset 52 lines).
Hunk #11 succeeded at 367 (offset 52 lines).
Hunk #12 FAILED at 376.
Hunk #13 FAILED at 473.
Hunk #14 succeeded at 614 (offset 73 lines).
Hunk #15 succeeded at 696 (offset 73 lines).
Hunk #16 succeeded at 779 (offset 73 lines).
Hunk #17 FAILED at 835.
5 out of 17 hunks FAILED -- saving rejects to file Modules/_hashopenssl.c.rej
patching file Modules/_ssl.c
BUILDSTDERR: error: Bad exit status from /var/tmp/rpm-tmp.kva1GT (%prep)

Tip: run fedpkg --release master prep locally to check if all patches apply.

Also, without actually changing the BR to openssl-devel, the CI here only checks is this patch doesn't break openssl10 support.

Usually, I always use "fedpkg prep" to regenerate the patch. I don't recall how I succeeded to mess up so much here... My patch didn't apply at all because of 00146-hashlib-fips.patch.

I updated the OpenSSL 1.1.1 patch to update also code introduced/modified by 00146-hashlib-fips.patch.

rebased onto 0db1b20fe4719dde6abc2d46a87016f6cfb16897

5 months ago

rebased onto f1a139c071198e5ca886333b3a9ba51e447d4635

5 months ago

@cstratak: Please review carefully the patch since it now also updates 00146-hashlib-fips.patch.

Still doesn't build.

Ok, fixed.

I had a lot of issues to compile Python locally, I wasn't sure if it was a mistake on my side or not. I checked the CI: there are the same errors.

My patch had a bug, I removed the following code while removing a conflict:

/* Minimum OpenSSL version needed to support sha224 and higher. */
#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x00908000)
#define _OPENSSL_SUPPORTS_SHA2
#endif

With the updated patch, 2 test_ssl tests are still failing, but I'm not sure how we should fix them. Just skip these tests?

======================================================================
FAIL: test_options (test.test_ssl.ContextTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/vstinner/prog/fedora_maint/python34/Python-3.4.10/Lib/test/test_ssl.py", line 707, in test_options
    self.assertEqual(default, ctx.options)
AssertionError: 2181169236 != 2182217812

======================================================================
FAIL: test_default_ecdh_curve (test.test_ssl.ThreadedTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/vstinner/prog/fedora_maint/python34/Python-3.4.10/Lib/test/test_ssl.py", line 2673, in test_default_ecdh_curve
    self.assertIn("ECDH", s.cipher()[0])
AssertionError: 'ECDH' not found in 'TLS_AES_256_GCM_SHA384'

The same tests are failing on Python 3.5, I don't think that it's worth it to fix them.

rebased onto 9d1ec1a4d1019c731cf03ac1dc568068e872faf0

5 months ago

I would agree we don't have to fix those tests.

I'm assigning the review to myself, but I'll manage to get to it later on this week.

Metadata Update from @cstratak:
- Request assigned

5 months ago

All tests passed on Koji, but since compat-openssl10 is still a dependency: the _ssl module is linked to OpenSSL 1.0 and so tests are run with OpenSSL 1.0. This PR prepares the package for the removal of the compat-openssl10 package, but it doesn't remove the dependency yet.

To remove compat-openssl10 dependency, test_options() and test_default_ecdh_curve() of test_ssl should be skipped. That can be done later.

Right now, Fedora CI is still failing, but it's a virtualization bug in the CI which failed before building the package. I will schedule a new CI job.

@churchyard asked me to do a scratch build with OpenSSL 1.1.1:

diff --git a/python34.spec b/python34.spec
index 1ffed64..dfe7049 100644
--- a/python34.spec
+++ b/python34.spec
@@ -152,7 +152,7 @@ BuildRequires: net-tools
 BuildRequires: pkgconfig
 BuildRequires: readline-devel
 BuildRequires: sqlite-devel
-BuildRequires: compat-openssl10-devel
+BuildRequires: openssl-devel

 %if 0%{?with_systemtap}
 BuildRequires: systemtap-sdt-devel

Scratch build (currently running): https://koji.fedoraproject.org/koji/taskinfo?taskID=33884459

rebased onto 39b0b21fa8fb75dd422c826bf1ce1a4e9946f8a9

5 months ago

Sorry, I reverted whitespace changes in the spec file.

OpenSSL 1.1.1 scratch build https://koji.fedoraproject.org/koji/taskinfo?taskID=33884459 failed as expected with:

======================================================================
FAIL: test_options (test.test_ssl.ContextTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/Python-3.4.10/Lib/test/test_ssl.py", line 707, in test_options
    self.assertEqual(default, ctx.options)
AssertionError: 2181169236 != 2182217812
======================================================================
FAIL: test_default_ecdh_curve (test.test_ssl.ThreadedTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/Python-3.4.10/Lib/test/test_ssl.py", line 2673, in test_default_ecdh_curve
    self.assertIn("ECDH", s.cipher()[0])
AssertionError: 'ECDH' not found in 'TLS_AES_256_GCM_SHA384'
----------------------------------------------------------------------

The useful information is not that 2 tests of test_ssl failed, but that the compilation succeeded and that other test_hashlib and test_ssl tests succeeded ;-)

Metadata Update from @cstratak:
- Request reset

5 months ago

If noone gets to it sooner than next week, I'll be able to review it by then.

This is not (yet) time critical.

Once https://src.fedoraproject.org/rpms/python35/pull-request/23 will be merged, I will also include this fix into this PR.

@vstinner please update this, python35 PR was merged.

rebased onto 8498acc2f79c980beeaeda39becdf881b1d17a1f

3 months ago

rebased onto f667775d90dbda86be3d4e8efa05fbd79c71125c

3 months ago

@vstinner please update this, python35 PR was merged.

Done.

I rebased my PR on top of the master branch, I added patch 322 to skip some tests on OpenSSL 1.1.1 (same change than Python 3.5, but adapted to Python 3.4). I also remove IS_OPENSSL_1_1 from test_ssl in patch 321 since it is unused in Python 3.4 (in Python 3.5, this constant is only used in a test which doesn't exist in Python 3.4).

Here is a scratchbuild using openssl-devel (OpenSSL 1.1.1) instead of compat-openssl10-devel: https://koji.fedoraproject.org/koji/taskinfo?taskID=35865429

vstinner@apu$ git diff
diff --git a/python34.spec b/python34.spec
index 72e9a0b..940abe6 100644
--- a/python34.spec
+++ b/python34.spec
@@ -152,7 +152,7 @@ BuildRequires: net-tools
 BuildRequires: pkgconfig
 BuildRequires: readline-devel
 BuildRequires: sqlite-devel
-BuildRequires: compat-openssl10-devel
+BuildRequires: openssl-devel

 %if 0%{?with_systemtap}
 BuildRequires: systemtap-sdt-devel

cstratak: Would you mind to review this update PR?

rebased onto 4669ae5b9e98bf8ea234007c4af5d457e75a9c59

2 months ago

@vstinner this now also needs a rebase due a to mass rebuild bumping the release and adding a changelog entry.

rebased onto 64324fa

2 months ago

@vstinner this now also needs a rebase due a to mass rebuild bumping the release and adding a changelog entry.

I rebased my PR. But it already has a changelog entry, no?

 %changelog
+* Wed Mar 20 2019 Victor Stinner <vstinner@redhat.com> - 3.4.10-3
+- Add OpenSSL 1.1.1 support (rhbz#1685612)
+

Yes, it has and that's why there was a conflict.

Oh ok, I misunderstood your comment. Anyway, the conflict is now solved.

1 new commit added

  • Fix changelog: use newer date
2 months ago

After going through the patch it LGTM. However the fips patch is problematic as it forces as to maintain compatibility with FIPS and openssl 1.1.1

Go ahead and merge as soon as the build finishes and I'll sent a subsequent PR for removing the FIPS patch.

Please make a scratch build with depending on openssl and not compat-ssl first. Maybe we could just drop right now the dependency on compat-ssl as it seems to be retired on rawhide now.

Right now, compat-openssl-devel package is gone from Fedora Rawhide, so I understand that this PR cannot be merged with "BuildRequires: compat-openssl10-devel":
https://bugzilla.redhat.com/show_bug.cgi?id=1673419

Miro: Would you be ok to switch to OpenSSL 1.1.1 for Python 3.4 in Rawhide? We provide Python 3.4 mostly for testing purpose only, and with my change, hashlib and ssl modules should just work (confirmed by local tests and previous scratch builds).

I suggest to apply the following change as part of this PR:

-BuildRequires: compat-openssl10-devel
+BuildRequires: openssl-devel

Miro, Charalampos: Would you be ok with that?

I'd like to have this change reviewed and ready, but not switching yet, until we know what is the resolution of https://bugzilla.redhat.com/show_bug.cgi?id=1673419

On IRC, Miro told me that this change can be merged even if the RPM doesn't build. The RPM doesn't build currently without this change neither: merging the change doesn't make the situation worse.

Miro added that if we want to switch python34 to OpenSSL 1.1 (replace "BuildRequires: compat-openssl10-devel" with "BuildRequires: openssl-devel"), he wants to also do it in python35, which makes sense.

Miro prefers to first prepare the package for OpenSSL 1.1 (this change), but switch to OpenSSL 1.1 in separated change.

About OpenSSL 1.0.x: I thought that OpenSSL 1.0 was no longer supported upstream (don't get any security fix anymore), but I was wrong. Only OpenSSL 1.0.0 and 1.0.1 versions are no longer maintained: 1.0.2 is a TLS version which is supported until the end of the year (openssl.org: "Our previous LTS version (1.0.2 series) will continue to be supported until 31st December 2019").

compat-openssl10 uses OpenSSL 1.0.2o released at 27 Mar 2018. The latest 1.0.2 released version is 1.0.2s (28 May 2019). It seems like 1.0.2o has multiple known security vulnerabilities.

Right now, compat-openssl10 has known security vulnerabilities, but it can be updated to retrieve fixes.

Pull-Request has been merged by cstratak

2 months ago

Pull-Request has been merged by cstratak

Yeah! Thanks.